Лямбда-выражение не работает в, казалось бы, идентичном kotlin - PullRequest
1 голос
/ 12 июня 2019

При попытке создать простой помощник по базе данных у меня есть RowMapper<T> от Spring, который я хочу заполнить, но Котлин настаивает на использовании KFunction2, хотя интерфейс RowMapper совпадает. Это работает на необработанном интерфейсе из Java-кода Spring.

Мне кажется, методы имеют идентичные значения в важных частях. Однако Котлин не согласен со мной.

Мой интерфейс (kotlin) выглядит следующим образом:

interface MyJdbcOperations : NamedParameterJdbcOperations {
    fun <T> querySingle(
        sql: String,
        parameters: MapSqlParameterSource,
        rowMapper: RowMapper<T>): Optional<T>
}

Интерфейс запроса внутри NamedParameterJdbcOperations выглядит следующим образом (Java):

public interface NamedParameterJdbcOperations {
    // ... rest of interface omitted for readability

    <T> List<T> query(String sql, SqlParameterSource paramSource, RowMapper<T> rowMapper)
            throws DataAccessException;
}

Но когда я использую свою реализацию MyJdbcOperations следующим образом:

template.query<Foo>(sql, parameters, this::mapToFoo)
template.querySingle<Foo>(sql, parameters, this::mapToFoo)

Первая версия работает, без проблем, и я также могу удалить <Foo> и позволить выводу типов делать свою работу.

Вторая версия, однако, выдаёт мне ошибки вроде:

Error:(25, 54) Kotlin: Type mismatch: inferred type is KFunction2<@ParameterName ResultSet, @ParameterName Int, Foo> but RowMapper<Foo> was expected

Однако я действительно ожидал, что это сработает, если подпись KFunction2 может удовлетворить RowMapper<Foo> в интерфейсе Java, то я, скорее всего, ожидаю, что это будет возможно и в Kotlin. Это явно не тот случай.

Так что же я делаю не так, и как лучше всего это исправить?

Ответы [ 2 ]

3 голосов
/ 12 июня 2019

Я вижу ключевое различие между рабочим случаем и вызовом с ошибкой компиляции в том, что второй относится к методу, определенному в интерфейсе Kotlin, в то время как первый использует метод, определенный в интерфейсе Java.

Я знаю, что преобразование SAM происходит из lambas / методов только в интерфейсы Java, как описано здесь: https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions.Я не могу понять, почему это может повлиять на ваш сценарий, но если вы переопределите MyJJdbcOperations как интерфейс Java, проблема исчезнет ...

Это не реальное решение, но это обходной путь.

Похоже, что лямбды (я тоже пытался с лабдами вроде {x -> this.mapToFoo(x)} с тем же результатом, с которым вы уже сталкивались) и методы, передаваемые интерфейсным методам Kotlin, преобразуются в KFunctionN, а не в ожидаемый интерфейс, также когдаожидаемый интерфейс определяется как интерфейс Java ...

Это не полный ответ, но я надеюсь, что это поможет вам приблизиться к решению.

1 голос
/ 12 июня 2019

Я нашел по крайней мере один обходной путь, но я все еще озадачен, почему это происходит и почему это не работает, как ожидалось.Следующее решит насущную проблему:

    template.querySingle<Foo>(sql, parameters, RowMapper { rs, rowNum -> this.mapToFoo(rs, rowNum) })

Благодаря @ pietro-martinelli опубликовал ответ, который помог мне выбрать правильный путь:)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...