РЕДАКТИРОВАТЬ: обновлен более простым примером.
Согласно документации, дженерики и JDBI работают вместе, и я видел эту работу раньше (хотя и со старой версией JDBI), но по какой-то причине теперь я получаю сообщение об ошибке:
org.jdbi.v3.sqlobject.UnableToCreateSqlObjectException: интерфейс Bar имеет неоднозначные методы [общедоступный абстрактный java.lang.Object Foo.baz (java.util.UUID), общедоступный абстрактный java.util.UUID Bar.baz (java.util.UUID )], разрешите явное переопределение
http://jdbi.org/#_annotations_and_inheritance
Я попробовал @Override для хорошей меры, но это ничего не изменило.
interface Foo<T> {
<strong i="12">@SqlQuery</strong>
fun baz(a: UUID): T
}
interface Bar : Foo<UUID> {
@SqlQuery("SELECT ClientID " +
"FROM ClientInstance " +
"WHERE ClientInstanceID = ?")
override fun baz(a: UUID): UUID
}
JDBI.inTransactionUnchecked { handle ->
val tester = handle.attach(Bar::class.java)
val hest = tester.baz(UUID.fromString("7a949c0e-28db-424a-a449-b118e5175a3b"))
LOGGER.info { "hest $hest" }
}
Привет Тор,
Мы проверили, что очень похожая конструкция работает в ванильной Java: https://github.com/jdbi/jdbi/blob/master/sqlobject/src/test/java/org/jdbi/v3/sqlobject/TestSqlObject.java#L293 - L307
Возможно, мы упустили случай с Котлином. Мы должны добавить сюда тест, соответствующий вашему использованию, и исправить любую обнаруженную ошибку.
А, если присмотреться: обратите внимание, что типы возвращаемых значений разные: Object
vs UUID
. Я ожидаю, что это означает, что компилятор Kotlin испускает метод синтетического моста, который мы затем обрабатываем неправильно.
Для людей, выполняющих поиск в Google, эта ошибка выдает другое сообщение об ошибке, когда родительский интерфейс не аннотирован (мне потребовалось время, чтобы найти это!)
Exception in thread "main" java.lang.IllegalStateException: Method StringRepo.get must be default or be annotated with a SQL method annotation.
at org.jdbi.v3.sqlobject.SqlObjectFactory.lambda$buildMethodHandler$15(SqlObjectFactory.java:148)
...
interface Repo<T> {
fun get(): T
}
interface StringRepo : Repo<String> {
@SqlQuery("SELECT 'Hello world!'")
override fun get(): String
}
//...snip
jdbi.onDemand(StringRepo::class.java).get()
@LittleMikeDev , это немного другая проблема. Я улучшил сообщение об ошибках, чтобы не вводить в заблуждение относительно класса, в котором отсутствует аннотация: https://github.com/jdbi/jdbi/pull/1590/files#diff -75b1c04d402bd8924262c7fececfcdb1L166
@TorRanfelt , я немного неясно , что делать, чтобы это исправить. Похоже, что компилятор Kotlin не генерирует мост-метод для специализации ковариантного метода. Я зарегистрировал проблему в системе отслеживания ошибок Kotlin: https://youtrack.jetbrains.com/issue/KT-33634
В качестве обходного пути Jdbi мог эмулировать необходимый метод моста. Необходимый код, вероятно, окажется небольшим, но его очень сложно написать. Я надеюсь, что Котлин, по крайней мере, скоро оценит проблему.
@stevenschlansker Спасибо, что
У Котлина, должно быть, был этот мост раньше, потому что я видел, как он работает. - Это объясняет, почему я не смог заставить его снова работать, вернувшись к более старым версиям JDBI.
Похоже, это был компромисс для обеспечения совместимости с Java 6: 6 не поддерживал методы моста в интерфейсах, поэтому Kotlin их не генерирует. В наши дни это звучит очень глупо, но, вероятно, имело смысл 10 лет назад;) Надеюсь, они скоро откажутся от поддержки 6 или, по крайней мере, условно включат совместимость с миром после 6.
Самый полезный комментарий
Привет Тор,
Мы проверили, что очень похожая конструкция работает в ванильной Java: https://github.com/jdbi/jdbi/blob/master/sqlobject/src/test/java/org/jdbi/v3/sqlobject/TestSqlObject.java#L293 - L307
Возможно, мы упустили случай с Котлином. Мы должны добавить сюда тест, соответствующий вашему использованию, и исправить любую обнаруженную ошибку.