Por que seu projeto em Kotlin e Java de repente "quebra"?
\n\nVocê já se deparou com uma situação em que escreve código em Kotlin, usa Java 11 para o código principal, e o Gradle de repente exibe um erro de compatibilidade? Familiar? Este é um dos problemas mais comuns ao configurar projetos multimódulo. Especialmente quando você usa build.gradle.kts (Kotlin DSL) e tenta integrar compileJava com compileKotlin. Neste artigo, vamos analisar como definir corretamente a compatibilidade de alvo JVM para Java 11 e Kotlin 1.8, para que seu projeto seja compilado sem erros. E sim, faremos isso em português, com humor e sem teoria entediante.
Se você veio do Stack Overflow, sabe que a pergunta original acumulou milhares de visualizações. Nós a adaptaremos para um formato educacional, para que você não apenas copie a resposta, mas entenda por que o erro ocorre e como evitá-lo no futuro.
\n\nProblema: quando Java e Kotlin falam línguas diferentes
\n\nImagine que Java 11 é um professor rigoroso, que exige que tudo esteja de acordo com o padrão. E Kotlin 1.8 é seu colega criativo, que quer usar novos recursos, mas esquece de avisar o professor. O resultado é um conflito.
\n\nNo Gradle, cada tarefa de compilação (compileJava, compileKotlin) tem seu próprio alvo JVM — a versão do bytecode para a qual o código é compilado. Se eles não coincidirem, você receberá um erro como:
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, pior ainda, uma queda silenciosa de desempenho devido à incompatibilidade do bytecode.
\n\nPor que isso acontece especificamente no build.gradle.kts?
\n\nKotlin DSL (arquivos .gradle.kts) é uma ferramenta poderosa, mas exige a especificação explícita dos parâmetros. Ao contrário do Groovy DSL, onde algumas configurações são "capturadas" automaticamente, no Kotlin DSL você precisa ser preciso. Isso é especialmente verdadeiro para o alvo JVM.
Erro típico: você define java.targetCompatibility = JavaVersion.VERSION_11, mas esquece de especificar o mesmo para o Kotlin. Ou vice-versa — configura compileKotlin, mas compileJava permanece no Java 8.
Solução correta: alvo JVM unificado para Java e Kotlin
\n\nPara evitar erros, você precisa definir explicitamente o alvo JVM para ambas as tarefas. Veja como fazer isso no build.gradle.kts:
Passo 1. Configuração do Java (compileJava)
\n\nAdicione no bloco java {} ou em 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\nObserve: sourceCompatibility e targetCompatibility devem ser iguais. Se você escreve código em Java 11, o bytecode também deve ser Java 11.
Passo 2. Configuração do Kotlin (compileKotlin)
\n\nAgora, o mais importante — definir o alvo JVM para o Kotlin. Isso é feito através do bloco kotlin {} ou através de tasks.withType<KotlinCompile>():
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile\n\ntasks.withType<KotlinCompile>() {\n kotlinOptions {\n jvmTarget = "11" // Atenção: isso é uma string, não JavaVersion!\n apiVersion = "1.8"\n languageVersion = "1.8"\n }\n}\n\n\nPor que jvmTarget é uma string? Porque o Kotlin espera exatamente uma representação textual da versão (por exemplo, "1.8", "11", "17"). Se você tentar passar JavaVersion.VERSION_11, o compilador exibirá um erro.
Exemplo completo do build.gr