Wie kann ich Kotlin Standard-Methoden mit Spring-Data-repository-Schnittstellen?

Betrachten Sie die folgenden repository-interface-Deklaration:

interface KotlinUserRepository : Repository<User, String> {

  fun findById(username: String): User

  fun search(username: String) = findById(username)
}

Ich bin der Deklaration eine default-interface-Methoden search(…) Voreinstellung aufrufen findById(…).

Starten meiner Anwendung schlägt fehl mit:

org.springframework.data.mapping.PropertyReferenceException: No property Search found for type User!

Wie kann ich Kotlin Standard-Methoden mit Spring-Data-repository-Schnittstellen und verhindern PropertyReferenceException?

InformationsquelleAutor mp911de | 2018-03-09



3 Replies
  1. 6

    TL;DR

    Kotlin 1.1/1.2 kompiliert werden, default-Methoden zu abstrakten interface-Methoden in den ersten Platz. Es ist nicht möglich, Kotlin Standard-Methoden in der Spring-Data-repository-Schnittstellen.

    Erklärung

    Kotlin ermöglicht default-interface-Methoden mit einer Java-Laufzeitumgebung der version 1.6. JVM-level-default-interface-Methoden eingeführt wurden, die mit Java 1.8. Dies bewirkt, dass Kotlin zu verwenden, einen anderen Ansatz zu kompilieren default-interface-Methoden als Java funktioniert.

    Den code aus KotlinUserRepository kompiliert:

    interface KotlinUserRepository extends Repository {
    
      User findById(String username);
    
      User search(String username);
    
      @Metadata(…)
      public static final class DefaultImpls {
    
        public static User search(KotlinUserRepository $this, String username) {
          Intrinsics.checkParameterIsNotNull(username, "username");
          return $this.findById(username);
        }
      }
    }

    Die Methode search(…) kompiliert, um eine abstrakte interface-Methode. Die Umsetzung bit-Kompilierungen zu einer Klasse DefaultImpls widerspiegelt die Standard-Signatur der Methode. Eine Klasse implementieren wollen KotlinUserRepository zu implementieren search(…). Mit der Schnittstelle in einer reinen Kotlin Umgebung lassen den Kotlin-compiler erstellen, der die Umsetzung bits.

    Spring Data repositories mit proxies unter. Jede Methode, die auf ein repository muss entweder:

    1. Umsetzung durch die Shop-spezifischen repository.
    2. Umgesetzt durch eine benutzerdefinierte Implementierung.
    3. Java 8 default-Methode.
    4. Werden, versehen mit einem query annotation.
    5. Passen die Methode naming-Schema zu ermöglichen-Abfrage Ableitung.

    In diesem Fall search(…) ist nicht implementiert, indem Sie den benutzerdefinierten code nach, wie würden Sie implementieren Sie eine Java-Schnittstelle. Spring Data versucht, daraus eine Abfrage und der Ansicht search(…) als Eigentum des User domain-Klasse. Suche schlägt fehl, und wirft PropertyReferenceException.

    Dies ist eine bekannte Einschränkung.

    Referenzen

  2. 2

    Als Ben darauf hingewiesen, Sie können jetzt (Kotlin 1.2.40+) verwenden @JvmDefault.

    interface BatchRepository : PagingAndSortingRepository<Batch, Long> {
        fun getAllByOrderByPriorityAscNameAsc(): List<Batch>
    
        @JvmDefault
        fun getForAdmin() = getAllByOrderByPriorityAscNameAsc()
    }

    Brauchen Sie, um die option, die Sie bauen.gradle mit so etwas wie dieses:

    tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
        kotlinOptions {
            freeCompilerArgs = ['-Xenable-jvm-default']
        }
    }

    Habe es gerade getestet auf Kotlin 1.2.41 und es funktioniert.

  3. 1

    Den kürzlich veröffentlichten Kotlin 1.2.40 jetzt unterstützt ein experimentelles feature aktivieren Zusammenstellung von Kotlin default-Methoden in Java 8 default-Methoden über die @JvmDefault annotation und Einstellung der Funktion flag: Xenable-jvm-default

    https://blog.jetbrains.com/kotlin/2018/04/kotlin-1-2-40-is-out/#more-5922

    Ich habe nicht versucht es noch, aber dein Beispiel theoretisch sollte arbeiten, etwa so:

    interface KotlinUserRepository : Repository<User, String> {
    
      fun findById(username: String): User
    
      @JvmDefault
      fun search(username: String) = findById(username)
    }

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.