Jdbi: Erreur de méthodes ambiguës (méthode du pont manquant) pour la surcharge covariante Kotlin

Créé le 9 août 2019  ·  8Commentaires  ·  Source: jdbi/jdbi

EDIT : mis à jour avec un exemple plus simple.

Selon la documentation, les génériques et JDBI fonctionnent ensemble, et j'ai déjà vu ce travail auparavant (bien qu'avec une ancienne version de JDBI), mais pour une raison quelconque, j'obtiens maintenant une erreur :

org.jdbi.v3.sqlobject.UnableToCreateSqlObjectException: interface Bar a des méthodes ambiguës [public abstract java.lang.Object Foo.baz(java.util.UUID), public abstract java.util.UUID Bar.baz(java.util.UUID )], veuillez résoudre avec un remplacement explicite

http://jdbi.org/#_annotations_and_inheritance

J'ai essayé @Override pour faire bonne mesure mais cela n'a rien changé.

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" }
}
bug

Commentaire le plus utile

Salut Tor,
Nous avons testé qu'une construction très similaire fonctionne en Java vanille : https://github.com/jdbi/jdbi/blob/master/sqlobject/src/test/java/org/jdbi/v3/sqlobject/TestSqlObject.java#L293 - L307
Peut-être avons-nous raté une affaire pour Kotlin. Nous devrions ajouter ici un test correspondant à votre utilisation et corriger tout bogue découvert.

Tous les 8 commentaires

Salut Tor,
Nous avons testé qu'une construction très similaire fonctionne en Java vanille : https://github.com/jdbi/jdbi/blob/master/sqlobject/src/test/java/org/jdbi/v3/sqlobject/TestSqlObject.java#L293 - L307
Peut-être avons-nous raté une affaire pour Kotlin. Nous devrions ajouter ici un test correspondant à votre utilisation et corriger tout bogue découvert.

Ah, en y regardant de plus près : notez que les types de retour sont différents, Object vs UUID . Je suppose que cela signifie que le compilateur Kotlin émet une méthode de pont synthétique que nous ne gérons alors pas correctement.

Pour les personnes qui recherchent Google, ce bogue génère un message d'erreur différent lorsque l'interface parent n'est pas annotée (il m'a fallu un certain temps pour le trouver !)

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 , c'est un problème légèrement différent. J'ai amélioré le message d'erreur pour ne pas être trompeur sur la classe à laquelle il manque l'annotation : https://github.com/jdbi/jdbi/pull/1590/files#diff -75b1c04d402bd8924262c7fececfcdb1L166

@TorRanfelt , j'ai creusé un peu plus là-dedans et il n'est pas évident de savoir quoi faire pour y remédier. Il semble que le compilateur Kotlin n'émet pas de méthode de pont pour la spécialisation de méthode covariante. J'ai déposé un problème sur le bug tracker de Kotlin : https://youtrack.jetbrains.com/issue/KT-33634

Comme solution de contournement, Jdbi pourrait émuler la méthode de pont nécessaire. Le code nécessaire finit probablement par être petit mais très difficile à écrire. J'espère que Kotlin évaluera au moins le problème bientôt.

@stevenschlansker Merci pour votre recherche.
Kotlin a dû avoir ce pont avant parce que je l'ai vu fonctionner. - Cela explique pourquoi je n'ai pas pu le faire fonctionner à nouveau en revenant aux anciennes versions de JDBI.

Il semble que ce soit un compromis pour maintenir la compatibilité Java 6 : 6 ne supportait pas les méthodes de pont dans les interfaces, donc Kotlin ne les émet pas. Cela semble idiot de nos jours, mais cela avait probablement du sens il y a 10 ans ;) Espérons qu'ils abandonneront bientôt le support 6, ou au moins activeront conditionnellement la compatibilité avec le monde post-6.

Cette page vous a été utile?
0 / 5 - 0 notes