Warum Ihr Kotlin- und Java-Projekt plötzlich „auseinanderfällt“?
\n\nHaben Sie schon einmal die Situation erlebt, dass Sie Code in Kotlin schreiben, Java 11 für den Hauptcode verwenden und Gradle plötzlich einen Kompatibilitätsfehler ausgibt? Kommt Ihnen das bekannt vor? Dies ist eines der häufigsten Probleme bei der Konfiguration von Multi-Modul-Projekten. Besonders, wenn Sie build.gradle.kts (Kotlin DSL) verwenden und versuchen, compileJava mit compileKotlin zu verbinden. In diesem Artikel werden wir erläutern, wie Sie die JVM target compatibility für Java 11 und Kotlin 1.8 korrekt einstellen, damit Ihr Projekt fehlerfrei gebaut wird. Und ja, wir machen das auf Deutsch, mit Humor und ohne langweilige Theorie.
Wenn Sie von Stack Overflow kommen, wissen Sie, dass die ursprüngliche Frage tausende Aufrufe hatte. Wir passen sie an ein Bildungsformat an, damit Sie nicht nur die Antwort kopieren, sondern verstehen, warum der Fehler auftritt und wie Sie ihn in Zukunft vermeiden können.
\n\nDas Problem: Wenn Java und Kotlin verschiedene Sprachen sprechen
\n\nStellen Sie sich vor, Java 11 ist ein strenger Professor, der verlangt, dass alles nach Standard läuft. Und Kotlin 1.8 ist sein kreativer Kollege, der neue Funktionen nutzen möchte, aber vergisst, den Professor zu informieren. Das Ergebnis – ein Konflikt.
\n\nIn Gradle hat jede Kompilierungsaufgabe (compileJava, compileKotlin) ihr eigenes JVM target – die Bytecode-Version, in die der Code kompiliert wird. Wenn diese nicht übereinstimmen, erhalten Sie einen Fehler wie:
Error: Module was compiled with an incompatible version of Kotlin. The binary version of its metadata is 1.8.0, expected version is 1.6.0.\n\n\nOder, noch schlimmer, eine stille Leistungseinbuße aufgrund von Bytecode-Inkompatibilität.
\n\nWarum passiert das gerade in build.gradle.kts?
\n\nKotlin DSL (Dateien .gradle.kts) ist ein mächtiges Werkzeug, erfordert aber die explizite Angabe von Parametern. Im Gegensatz zu Groovy DSL, wo einige Einstellungen automatisch „übernommen“ werden, muss man in Kotlin DSL präzise sein. Dies betrifft insbesondere das JVM target.
Ein typischer Fehler: Sie setzen java.targetCompatibility = JavaVersion.VERSION_11, vergessen aber, dasselbe für Kotlin anzugeben. Oder umgekehrt – Sie konfigurieren compileKotlin, während compileJava auf Java 8 bleibt.
Die richtige Lösung: Einheitliches JVM target für Java und Kotlin
\n\nUm Fehler zu vermeiden, müssen Sie das JVM target für beide Aufgaben explizit festlegen. So geht's in build.gradle.kts:
Schritt 1: Java konfigurieren (compileJava)
\n\nFügen Sie im Block java {} oder in tasks.withType<JavaCompile>() hinzu:
java {\n sourceCompatibility = JavaVersion.VERSION_11\n targetCompatibility = JavaVersion.VERSION_11\n}\n\ntasks.withType<JavaCompile>() {\n options.encoding = "UTF-8"\n options.compilerArgs.add("-parameters")\n}\n\n\nBeachten Sie: sourceCompatibility und targetCompatibility müssen identisch sein. Wenn Sie Code in Java 11 schreiben, sollte auch der Bytecode Java 11 sein.
Schritt 2: Kotlin konfigurieren (compileKotlin)
\n\nJetzt der wichtigste Teil – das JVM target für Kotlin festlegen. Dies erfolgt über den Block kotlin {} oder über tasks.withType<KotlinCompile>():
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile\n\ntasks.withType<KotlinCompile>() {\n kotlinOptions {\n jvmTarget = "11" // Achtung: Dies ist ein String, kein JavaVersion!\n apiVersion = "1.8"\n languageVersion = "1.8"\n }\n}\n\n\nWarum ist jvmTarget ein String? Weil Kotlin eine String-Darstellung der Version erwartet (z.B. "1.8", "11", "17"). Wenn Sie versuchen, JavaVersion.VERSION_11 zu übergeben, gibt der Compiler einen Fehler aus.
Vollständiges Beispiel build.gr