Почему ваш проект на Kotlin и Java внезапно «разваливается»?
Вы когда-нибудь сталкивались с ситуацией, когда пишете код на Kotlin, используете Java 11 для основного кода, а Gradle вдруг выдает ошибку совместимости? Знакомо? Это одна из самых частых проблем при настройке многомодульных проектов. Особенно, когда вы используете build.gradle.kts (Kotlin DSL) и пытаетесь подружить compileJava с compileKotlin. В этой статье мы разберем, как правильно задать jvm target compatibility для Java 11 и Kotlin 1.8, чтобы ваш проект собирался без ошибок. И да, мы сделаем это на русском, с юмором и без скучной теории.
Если вы пришли с Stack Overflow, то знаете, что оригинальный вопрос собрал тысячи просмотров. Мы адаптируем его под образовательный формат, чтобы вы не просто скопировали ответ, а поняли, почему возникает ошибка и как её избежать в будущем.
Проблема: когда Java и Kotlin говорят на разных языках
Представьте, что Java 11 — это строгий профессор, который требует, чтобы всё было по стандарту. А Kotlin 1.8 — это его креативный коллега, который хочет использовать новые фишки, но забывает сообщить профессору. В итоге — конфликт.
В Gradle каждая задача компиляции (compileJava, compileKotlin) имеет свой JVM target — версию байт-кода, в которую компилируется код. Если они не совпадают, вы получите ошибку вроде:
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.
Или, что ещё хуже, — молчаливое падение производительности из-за несовместимости байт-кода.
Почему это происходит именно в build.gradle.kts?
Kotlin DSL (файлы .gradle.kts) — это мощный инструмент, но он требует явного указания параметров. В отличие от Groovy DSL, где некоторые настройки «подхватываются» автоматически, в Kotlin DSL нужно быть точным. Особенно это касается jvm target.
Типовая ошибка: вы задаёте java.targetCompatibility = JavaVersion.VERSION_11, но забываете указать то же самое для Kotlin. Или наоборот — настраиваете compileKotlin, а compileJava остаётся на Java 8.
Правильное решение: единый JVM target для Java и Kotlin
Чтобы избежать ошибок, нужно явно задать jvm target для обеих задач. Вот как это сделать в build.gradle.kts:
Шаг 1. Настройка Java (compileJava)
Добавьте в блок java {} или в tasks.withType<JavaCompile>():
java {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
tasks.withType<JavaCompile>() {
options.encoding = "UTF-8"
options.compilerArgs.add("-parameters")
}
Обратите внимание: sourceCompatibility и targetCompatibility должны быть одинаковыми. Если вы пишете код на Java 11, то и байт-код должен быть Java 11.
Шаг 2. Настройка Kotlin (compileKotlin)
Теперь самое важное — задать jvm target для Kotlin. Это делается через блок kotlin {} или через tasks.withType<KotlinCompile>():
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
tasks.withType<KotlinCompile>() {
kotlinOptions {
jvmTarget = "11" // Внимание: это строка, а не JavaVersion!
apiVersion = "1.8"
languageVersion = "1.8"
}
}
Почему jvmTarget — это строка? Потому что Kotlin ожидает именно строковое представление версии (например, "1.8", "11", "17"). Если вы попытаетесь передать JavaVersion.VERSION_11, компилятор выдаст ошибку.
Полный пример build.gradle.kts:
plugins {
java
kotlin("jvm") version "1.8.0"
}
java {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
tasks.withType<JavaCompile>() {
options.encoding = "UTF-8"
}
tasks.withType<KotlinCompile>() {
kotlinOptions {
jvmTarget = "11"
apiVersion = "1.8"
languageVersion = "1.8"
}
}
Топ-5 ошибок при настройке JVM target и как их избежать
Давайте разберём самые популярные грабли, на которые наступают разработчики:
Ошибка 1: Забыли указать jvmTarget для Kotlin
Ваш код на Java компилируется в Java 11, а Kotlin — в Java 8. Результат: ошибки во время выполнения или при использовании Java 11-специфичных фич.
Решение: Всегда явно задавайте jvmTarget в kotlinOptions.
Ошибка 2: Путаница между JavaVersion и строкой
В Java вы используете JavaVersion.VERSION_11, а в Kotlin — "11". Если перепутать, Gradle выдаст ошибку компиляции.
Решение: Запомните: для Java — JavaVersion, для Kotlin — строка.
Ошибка 3: Несоответствие версий Kotlin и Java
Например, вы используете Kotlin 1.8, но указываете jvmTarget = "1.8" (Java 8). Это может работать, но вы теряете возможность использовать фичи Java 11.
Решение: Убедитесь, что jvmTarget совпадает с версией Java, которую вы используете в проекте.
Ошибка 4: Глобальная настройка в allprojects или subprojects
Если вы задаёте jvmTarget глобально, но в одном из модулей используете другую версию, конфликт неизбежен.
Решение: Настраивайте jvmTarget индивидуально для каждого модуля, если версии различаются.
Ошибка 5: Игнорирование apiVersion и languageVersion
Эти параметры не обязательны, но их отсутствие может привести к неожиданным ошибкам при использовании новых API Kotlin.
Решение: Укажите их, чтобы зафиксировать версию Kotlin, с которой работает проект.