Avatar ·

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

Привет! Я новичок в Kotlin и Gradle Kotlin DSL. У меня есть мультимодульный проект, и я хочу, чтобы все Java-код компилировался под Java 11, а Kotlin-код — под ту же версию (target JVM 1.8 устарел, я хочу 11). Я использую плагин Kotlin 1.8.x и плагин Java. Проблема: в моём build.gradle.kts я задаю sourceCompatibility и targetCompatibility для Java, но compileKotlin всё равно использует старую цель JVM. Как это исправить? Вот мой текущий файл: ```kotlin plugins { kotlin("jvm") version "1.8.20" java } java { sourceCompatibility = JavaVersion.VERSION_11 targetCompatibility = JavaVersion.VERSION_11 } tasks.withType { kotlinOptions { jvmTarget = "11" // или "1.8"? Ошибка! } } ``` При сборке я получаю предупреждение: "w: Using JVM 11 target is not supported for Kotlin JVM compiler 1.8.20" или просто несовместимость. Я пробовал ставить `jvmTarget = "11"`, но тогда Gradle ругается. В официальной документации написано про `kotlin.jvm.target.validation.mode=warning`, но я не уверен, это ли нужно. Вопрос: как правильно синхронизировать target JVM для Java и Kotlin в Kotlin DSL? Нужно ли указывать версию везде вручную? Или есть единая настройка? Спасибо за помощь! <<>>

Правильное решение: используйте свойство kotlin.jvm.target и настройки Java

Ваша проблема распространена среди разработчиков, переходящих с Groovy DSL на Kotlin DSL. Основная причина путаницы — устаревшие примеры из документации. Начиная с Kotlin 1.5.0, для JVM-проектов рекомендуется использовать единый источник истины: свойство kotlin.jvm.target в gradle.properties или прямое указание через kotlin.jvm.target.validation.mode.

Вот самый надёжный способ настроить совместимость JVM для Java 11 и Kotlin 1.8.x в build.gradle.kts:

// build.gradle.kts
plugins {
    kotlin("jvm") version "1.8.20"
    java
}

// 1. Явно задаём target для Java
java {
    sourceCompatibility = JavaVersion.VERSION_11
    targetCompatibility = JavaVersion.VERSION_11
}

// 2. Настраиваем Kotlin compiler на ту же версию
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>().configureEach {
    kotlinOptions {
        jvmTarget = "11" // Важно: строка "11", а не JavaVersion
    }
}

// 3. (Опционально) Включаем строгую проверку совпадения версий
kotlin {
    jvmToolchain(11) // Устанавливает тулчейн Java 11 для Kotlin-задач
}

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

  • jvmTarget = "11" — это строка, а не объект JavaVersion. Kotlin принимает именно строковое представление (например, "1.8", "11", "17").
  • jvmToolchain(11) — автоматически синхронизирует Kotlin-компилятор с JDK 11. Это самый чистый способ в Kotlin 1.8+.
  • Если вы используете kotlin.jvm.target.validation.mode=error в gradle.properties, Gradle будет выдавать ошибку при несовпадении версий Java и Kotlin.

Дополнительно про gradle.properties:

Добавьте в файл gradle.properties (в корне проекта) следующее:

kotlin.jvm.target.validation.mode=error
kotlin.code.style=official

Это заставит Gradle строго проверять, что jvmTarget Kotlin совпадает с targetCompatibility Java. Если они различаются — сборка упадёт с ошибкой.

Полный пример для мультимодульного проекта:

// В корневом build.gradle.kts
subprojects {
    apply(plugin = "java")
    apply(plugin = "kotlin")

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

    tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>().configureEach {
        kotlinOptions {
            jvmTarget = "11"
        }
    }
}

Важное примечание про версию Kotlin: Начиная с Kotlin 1.8.0, поддержка JVM-таргетов изменилась. Если вы видите предупреждение "Using JVM 11 target is not supported", проверьте:

  • Установлен ли у вас JDK 11 (команда java -version).
  • Не используете ли вы устаревший плагин Kotlin (версии ниже 1.5.0).
  • Не конфликтуют ли jvmTarget с настройками compileJava.

В 99% случаев решение с jvmToolchain(11) и явным указанием jvmTarget = "11" решает проблему. Если же проект требует Java 8 для совместимости с библиотеками, используйте jvmTarget = "1.8" и sourceCompatibility = JavaVersion.VERSION_1_8.

<<>>

Альтернативный подход: через kotlin.jvm.target в gradle.properties

Если вы не хотите дублировать версию в каждом модуле, можно использовать единую настройку через gradle.properties. Этот метод особенно удобен для CI/CD, где версия JVM централизованно задаётся переменной окружения.

// gradle.properties (корень проекта)
kotlin.jvm.target=11

Затем в build.gradle.kts достаточно указать только Java-совместимость:

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

Kotlin-задачи автоматически подхватят значение из gradle.properties. Однако этот способ не сработает, если вы явно переопределяете jvmTarget в kotlinOptions — в таком случае приоритет будет у явного указания.

Минусы подхода:

  • Меньше контроля — если вам нужно разное значение для разных модулей, придётся использовать первый вариант.
  • Не все версии Kotlin поддерживают kotlin.jvm.target (работает с 1.5+).

Рекомендую комбинировать: задать kotlin.jvm.target в gradle.properties как умолчание, а в отдельных модулях переопределять через kotlinOptions, если необходимо.