简体   繁体   中英

Building a Gradle Kotlin project with Java 9/10 and Gradle's Kotlin DSL

This is kind of a follow up to Building a Kotlin + Java 9 project with Gradle . In the linked post Gradle with Groovy is used. In my case Kotlin DSL is used.

Basically I have a gradle project with the following structure (only relevant content here):

src/
|   main/
|   |   kotlin/
|   |   |   com/example/testproject/
|   |   |   |   Main.kt
|   |   |   module-info.java
build.gradle.kts
settings.gradle

Usually I would run gradle run on it, but that results in the following error:

module-info.java:3: error: module not found: kotlin.stdlib
  requires kotlin.stdlib;

Now this is what my build file currently looks like

import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

buildscript {
  var kotlin_version: String by extra
  kotlin_version = "1.2.41"

  repositories {
    mavenCentral()
  }
  dependencies {
    classpath(kotlin("gradle-plugin", kotlin_version))
  }
}

repositories {
  mavenCentral()
}

plugins {
  kotlin("jvm") version "1.2.41"
  application
}

val kotlin_version: String by extra

dependencies {
  implementation(kotlin("stdlib", kotlin_version))
  implementation(kotlin("stdlib-jdk8", kotlin_version))
  implementation(kotlin("runtime", kotlin_version))
  implementation(kotlin("reflect", kotlin_version))
}

val group = "com.example"
application {
  mainClassName = "$group.testproject.Main"
}

java {
  sourceCompatibility = JavaVersion.VERSION_1_10
  targetCompatibility = sourceCompatibility
  sourceSets {
    "main" {
      java.srcDirs("src/main/kotlin")
    }
  }
}

tasks.withType<KotlinCompile> {
  kotlinOptions.jvmTarget = "1.8"
}

And this is my module-info.java:

module com.example.testproject {
  // Kotlin compatibility
  requires kotlin.stdlib;
  exports com.example.testproject;
}

Question: How to get the solution provided in the linked post (or any other solution) running, so that a Kotlin project with Gradle's Kotlin DSL can be compiled using a Java 9/10 environment?

This is kind of a self-answer (I do not full understand that matter, so the explanations might not be correct). The conclusions I draw here are purely empiric and based on a conversion from Kotlin DSL to Gradle's Groovy and back.

The first problem I encountered was that I had two conflicting providers for the Kotlin functions in:

  implementation(kotlin("stdlib", kotlin_version))
  implementation(kotlin("runtime", kotlin_version))

I solved that by deciding to go with stdlib . All other dependencies did not conflict with each other.

The more severe problem was something different: The compileJava task did not find the correct classes (from the project) and modules (from the distribution). Therefore I needed to adapt the paths as in the following example:

val compileKotlin: KotlinCompile by tasks
val compileJava: JavaCompile by tasks
compileJava.destinationDir = compileKotlin.destinationDir

This basically compiles the Java classes within Kotlins compiled output and makes Java find the classes from the project.

The last problem could finally be solved by the following non-idiomatic piece of Kotlin Script:

tasks {
  "compileJava" {
    dependsOn(":compileKotlin")
    if (JavaVersion.current() >= JavaVersion.VERSION_1_9) {
      inputs.property("moduleName", ext["moduleName"])
      doFirst {
        compileJava.options.compilerArgs = listOf(
            // include Gradle dependencies as modules
            "--module-path", java.sourceSets["main"].compileClasspath.asPath,
        )
        java.sourceSets["main"].compileClasspath = files()
      }
    }
  }
}

This basically lets the compileJava task use an empty classpath and sets module path as compiler option to the currently set compileClasspath of the main source set (the Kotlin source set which is also added as Java source set).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM