Pourquoi votre projet Kotlin et Java s'effondre-t-il soudainement ?
\n\nAvez-vous déjà été confronté à une situation où vous écrivez du code en Kotlin, utilisez Java 11 pour le code principal, et Gradle affiche soudainement une erreur de compatibilité ? Cela vous dit quelque chose ? C'est l'un des problèmes les plus courants lors de la configuration de projets multi-modules. Surtout lorsque vous utilisez build.gradle.kts (Kotlin DSL) et que vous essayez de faire cohabiter compileJava avec compileKotlin. Dans cet article, nous allons voir comment définir correctement la compatibilité de la cible JVM pour Java 11 et Kotlin 1.8, afin que votre projet se compile sans erreur. Et oui, nous le ferons en français, avec humour et sans théorie ennuyeuse.
Si vous venez de Stack Overflow, vous savez que la question originale a recueilli des milliers de vues. Nous l'adaptons ici dans un format éducatif pour que vous ne vous contentiez pas de copier la réponse, mais que vous compreniez pourquoi l'erreur se produit et comment l'éviter à l'avenir.
\n\nLe problème : quand Java et Kotlin parlent des langues différentes
\n\nImaginez que Java 11 est un professeur strict qui exige que tout soit conforme à la norme. Et Kotlin 1.8 est son collègue créatif qui veut utiliser les nouvelles fonctionnalités, mais oublie d'en informer le professeur. Résultat : un conflit.
\n\nDans Gradle, chaque tâche de compilation (compileJava, compileKotlin) a sa propre cible JVM — la version du bytecode dans laquelle le code est compilé. Si elles ne correspondent pas, vous obtiendrez une erreur comme celle-ci :
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\nOu, pire encore, une baisse silencieuse des performances due à une incompatibilité du bytecode.
\n\nPourquoi cela se produit-il spécifiquement dans build.gradle.kts ?
\n\nLe Kotlin DSL (fichiers .gradle.kts) est un outil puissant, mais il nécessite une spécification explicite des paramètres. Contrairement au Groovy DSL où certains réglages sont « repris » automatiquement, dans le Kotlin DSL, vous devez être précis. Cela concerne particulièrement la cible JVM.
L'erreur typique : vous définissez java.targetCompatibility = JavaVersion.VERSION_11, mais vous oubliez de faire de même pour Kotlin. Ou inversement — vous configurez compileKotlin, tandis que compileJava reste sur Java 8.
La solution correcte : une cible JVM unique pour Java et Kotlin
\n\nPour éviter les erreurs, vous devez définir explicitement la cible JVM pour les deux tâches. Voici comment faire dans build.gradle.kts :
Étape 1. Configuration de Java (compileJava)
\n\nAjoutez dans le bloc java {} ou dans tasks.withType<JavaCompile>() :
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\nNotez que sourceCompatibility et targetCompatibility doivent être identiques. Si vous écrivez du code en Java 11, le bytecode doit également être Java 11.
Étape 2. Configuration de Kotlin (compileKotlin)
\n\nMaintenant, le plus important — définir la cible JVM pour Kotlin. Cela se fait via le bloc kotlin {} ou via tasks.withType<KotlinCompile>() :
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile\n\ntasks.withType<KotlinCompile>() {\n kotlinOptions {\n jvmTarget = "11" // Attention : c'est une chaîne, pas un JavaVersion !\n apiVersion = "1.8"\n languageVersion = "1.8"\n }\n}\n\n\nPourquoi jvmTarget est-il une chaîne ? Parce que Kotlin attend une représentation textuelle de la version (par exemple, "1.8", "11", "17"). Si vous essayez de passer JavaVersion.VERSION_11, le compilateur générera une erreur.
Exemple complet de build.gr