I'm fairly new to Gradle (and Java 9, to be honest), and I'm trying to use Gradle to build a simple library project that is a mix of Java 9 and Kotlin. More in detail, there is an interface in Java and an implementation in Kotlin; I'd do everything in Kotlin, but the modules-info.java
is java anyway, so I decided to do things this way.
I'm building on IntelliJ Idea, with the 1.2.0 kotlin plugin and gradle 4.3.1 defined externally.
Filesystem schema is:
+ src
+ main
+ java
+ some.package
- Roundabout.java [an interface]
- module-info.java
+ kotlin
+ some.package.impl
- RoundaboutImpl.kt [implementing the interface]
module-info.java
is:
module some.package {
requires kotlin.stdlib;
exports some.package;
}
and build.gradle
is:
buildscript {
ext.kotlin_version = '1.2.0'
repositories {
mavenCentral()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
group 'some.package'
version '1.0-PRE_ALPHA'
apply plugin: 'java-library'
apply plugin: 'kotlin'
tasks.withType(JavaCompile) {
options.encoding = 'UTF-8'
}
sourceCompatibility = 9
compileJava {
dependsOn(':compileKotlin')
doFirst {
options.compilerArgs = [
'--module-path', classpath.asPath,
]
classpath = files()
}
}
repositories {
mavenCentral()
}
dependencies {
compile group: 'org.jetbrains.kotlin', name: 'kotlin-stdlib', version: "$kotlin_version"
testCompile group: 'junit', name: 'junit', version: '4.12'
}
compileKotlin {
kotlinOptions.jvmTarget = "1.8"
}
compileTestKotlin {
kotlinOptions.jvmTarget = "1.8"
}
Notice that I had to specify a module path on the java compile task, or the compilation fails with:
error: module not found: kotlin.stdlib requires kotlin.stdlib;
Anyway, now this build fails with this error, and I can't figure out how to solve it:
error: package some.package.impl does not exist
import some.package.impl.RoundaboutImpl;
error: cannot find symbol
return new RoundaboutImpl<>(queueSize, parallelism, worker, threadPool);
I think that the Kotlin part of the compilation is going ok, then the java part fails because it doesn't "see" the kotlin side, so to speak.
I think I should tell it somehow to to load the already compiled kotlin classes in the classpath; but (first) how do I do this in gradle? and (second) is it even possible? I think you can't mix module path and class path in Java 9.
How can I solve this? I think it is a pretty common situation, as every java9-style module will be a mixed-language module (because of module-info.java
), so I think I'm missing something really basic here.
Thanks in advance!
Solved! It was sufficient to set the kotlin compilation dir to the same dir as Java:
compileKotlin.destinationDir = compileJava.destinationDir
It works now, both with the sources in the same tree or in different trees; but with a quirk: the jar
task produces a jar with all the entries duplicated. I'll work on fix this, next.
Thanks to everyone!
I am using the following gradle script where I put the module-info.java under src/module. It gets automatically included in the jar (without duplicates):
if (JavaVersion.current() >= JavaVersion.VERSION_1_9) {
subprojects {
def srcModule = "src/module"
def moduleInfo = file("${project.projectDir}/$srcModule/module-info.java")
if (moduleInfo.exists()) {
sourceSets {
module {
java {
srcDirs = [srcModule]
compileClasspath = main.compileClasspath
sourceCompatibility = '9'
targetCompatibility = '9'
}
}
main {
kotlin { srcDirs += [srcModule] }
}
}
compileModuleJava.configure {
dependsOn compileKotlin
destinationDir = compileKotlin.destinationDir
doFirst {
options.compilerArgs = ['--module-path', classpath.asPath,]
classpath = files()
}
}
jar.dependsOn compileModuleJava
}
}
}
I won't update it any longer, have a look at https://github.com/robstoll/atrium/blob/master/build.gradle to see the current version in use.
The accepted answer did not work for me (atleast not the way it was presented), but this is what worked:
plugins {
id "org.jetbrains.kotlin.jvm" version "1.3.50"
}
compileKotlin {
doFirst {
destinationDir = compileJava.destinationDir
}
}
jar {
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
}
Doing it the way the accepted answer suggests led to me getting this error:
Directory '/path/to/project/build/classes/kotlin/main' specified for property 'compileKotlinOutputClasses' does not exist.
Gradle version: 5.6
I ran into the same problem and the existing answers fixed only part of the issue for me, so I searched over all internet and ended up with a working solution. I don't know exactly why this works, but I decided to share my build.gradle.kts
file here to help other people to find they way. This file is a combination of many pieces that I found on the internet.
I'm using Java 16, Kotlin 1.5.31 and Gradle 7.1.
The file tree is:
+ project
- build.gradle.kts
+ src
+ main
+ java
- module-info.java
+ my
+ package
- SomeClasses.java
+ kotlin
+ my
+ package
- MoreClasses.kt
module-info.java
module name.of.your.javamodule {
requires kotlin.stdlib;
requires kotlinx.coroutines.core.jvm;
requires org.jetbrains.annotations;
exports my.pacakge;
}
build.gradle.kts
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
application
kotlin("jvm") version "1.5.31"
id("org.jetbrains.kotlin.plugin.serialization") version "1.5.31"
}
val kotlinVersion = "1.5.31"
group = "your.group.id"
version = "0.0.1-SNAPSHOT"
application {
mainClass.set("full.name.of.your.MainClass")
mainModule.set("name.of.your.javamodule") // Same defined in module-info.java
executableDir = "run"
}
repositories {
mavenCentral()
}
dependencies {
implementation(kotlin("stdlib-jdk8", kotlinVersion))
implementation("com.michael-bull.kotlin-inline-logger:kotlin-inline-logger:1.0.3")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2-native-mt")
implementation("org.jetbrains:annotations:22.0.0")
testImplementation(kotlin("test", kotlinVersion))
}
java {
sourceCompatibility = JavaVersion.VERSION_16
targetCompatibility = JavaVersion.VERSION_16
}
tasks {
run.configure {
dependsOn(jar)
doFirst {
jvmArgs = listOf(
"--module-path", classpath.asPath
)
classpath = files()
}
}
compileJava {
dependsOn(compileKotlin)
doFirst {
options.compilerArgs = listOf(
"--module-path", classpath.asPath
)
}
}
compileKotlin {
destinationDirectory.set(compileJava.get().destinationDirectory)
}
jar {
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
}
}
tasks.withType<KotlinCompile>().configureEach {
kotlinOptions {
jvmTarget = "16"
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With