Avatar ·

Как настроить совместимость JVM для compileJava (Java 11) и compileKotlin (Kotlin 1.8) в build.gradle.kts?

Всем привет! Я новичок в Kotlin и Gradle, и у меня возникла проблема с настройкой совместимости версий JVM для Java и Kotlin в проекте. Использую Gradle с Kotlin DSL (build.gradle.kts). В проекте есть смешанный код: основной на Kotlin 1.8, и несколько классов на Java 11. Когда я запускаю сборку, Gradle выдает ошибки, что задачи compileJava и compileKotlin используют разные целевые версии JVM. Например: - compileJava настроен на Java 11 (target = 11) - compileKotlin настроен на Java 8 (по умолчанию) Я хочу, чтобы оба компилятора использовали одну и ту же версию JVM, например Java 11. Но как это правильно сделать в build.gradle.kts? Пробовал разные варианты, но ничего не работает. Вот мой текущий файл build.gradle.kts: ```kotlin plugins { java kotlin("jvm") version "1.8.0" } java { sourceCompatibility = JavaVersion.VERSION_11 targetCompatibility = JavaVersion.VERSION_11 } tasks.withType { options.release.set(11) } ``` Но после этого compileKotlin всё равно использует Java 8. Что я делаю не так? Нужно ли отдельно настраивать Kotlin? Может быть, есть какой-то глобальный параметр? Буду благодарен за подробный ответ с примерами. <<>>

Проблема: разные JVM target для Java и Kotlin

Вы столкнулись с типичной ситуацией в смешанных проектах Java+Kotlin. Задача compileJava и compileKotlin по умолчанию используют разные версии JVM, если не задать явные настройки. Решение — синхронизировать их через единый параметр.

Решение: используйте kotlin.jvmTarget и java.targetCompatibility

Самый правильный способ — задать JVM target для Kotlin через блок kotlin { jvmToolchain { ... } } или напрямую через tasks.withType { kotlinOptions.jvmTarget = "11" }. Одновременно настройте Java через java { targetCompatibility = ... }. Вот полный пример:

plugins {
    java
    kotlin("jvm") version "1.8.0"
}

// Глобальная настройка Java
java {
    sourceCompatibility = JavaVersion.VERSION_11
    targetCompatibility = JavaVersion.VERSION_11
}

// Настройка Kotlin JVM target
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile> {
    kotlinOptions.jvmTarget = "11"
}

// Альтернативный вариант через kotlin блок (если используете kotlin-dsl)
kotlin {
    jvmToolchain(11) // Устанавливает и Java, и Kotlin на одну версию
}

Почему это работает?

  • java.targetCompatibility — задаёт версию байт-кода для Java-компилятора.
  • kotlinOptions.jvmTarget — задаёт версию байт-кода для Kotlin-компилятора.
  • Если используете jvmToolchain(11), Gradle автоматически подтянет JDK 11 и применит его ко всем задачам.

Важные нюансы

  • Убедитесь, что у вас установлен JDK 11 или выше (проверьте java -version).
  • Если проект мультимодульный, настройки нужно продублировать в каждом подпроекте или вынести в allprojects { ... }.
  • Для Gradle 7+ рекомендуется использовать jvmToolchain — это упрощает управление версиями.
  • Если вы используете options.release.set(11) для JavaCompile, это эквивалентно targetCompatibility, но более новый способ. Однако для Kotlin это не работает — нужно явно задавать jvmTarget.

Полный проверенный пример build.gradle.kts

plugins {
    java
    kotlin("jvm") version "1.8.0"
}

java {
    sourceCompatibility = JavaVersion.VERSION_11
    targetCompatibility = JavaVersion.VERSION_11
}

kotlin {
    jvmToolchain(11)
}

tasks.withType<JavaCompile> {
    options.release.set(11)
}

tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile> {
    kotlinOptions.jvmTarget = "11"
}

После этого обе задачи будут компилировать в байт-код для JVM 11. Проверить можно, запустив gradle build — ошибки совместимости исчезнут.

<<>>

Альтернативный подход: использовать kotlin-dsl и единый блок kotlin { }

Если вы используете Kotlin DSL и хотите минимизировать код, можно применить более лаконичный вариант через kotlin { jvmToolchain { ... } }. Этот блок автоматически настраивает и Java, и Kotlin на одну версию JVM, если у вас установлен соответствующий JDK.

plugins {
    java
    kotlin("jvm") version "1.8.0"
}

kotlin {
    jvmToolchain {
        (this as JavaToolchainSpec).languageVersion.set(JavaLanguageVersion.of(11))
    }
}

Этот способ особенно удобен в мультимодульных проектах, так как Gradel сам подтянет нужный JDK для компиляции. Однако он требует, чтобы JDK 11 был доступен через toolchain (например, установлен локально или через Adoptium).

Когда использовать: если вы не хотите дублировать настройки для Java и Kotlin отдельно, и ваш проект использует Gradle 7+ с поддержкой toolchain. Минус — может не сработать, если у вас старый Gradle.