Do Kotlin 1.2.10 and Java 9 have opposite rules regarding automatic modules?

百般思念 提交于 2019-11-30 04:03:42

问题


I have a Gradle project using the Kotlin Gradle plugin. I want to build a Java 9 module, so my directory structure looks like this:

src/main/java/
    - module-info.java
src/main/kotlin/
    - Foo.kt
    - Bar.kt
build.gradle
...

My build.gradle declares the following dependencies:

dependencies {
    compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.2.10"
    compile "org.jetbrains.kotlin:kotlin-reflect:1.2.10"
    compile "org.junit.jupiter:junit-jupiter-api:5.0.2"
}

and I use all of these dependencies in my Kotlin source (Foo.kt, Bar.kt, ...).

Everything works hunky-dory if I write my module-info.java like so:

module my.module {
    requires kotlin.stdlib;
    exports my.module.pkg;
}

and if I supply all my compile-time dependencies to javac during the compileJava task using this technique.

However if I turn on -Xlint:all for the Java compiler during the compileJava task (to compile module-info.java), I get the following warnings:

/path/to/my.module/src/main/java/module-info.java:26: warning: requires directive for an automatic module
    requires kotlin.stdlib;
                   ^

So here we have the Java compiler, javac complaining that kotlin.stdlib is an automatic module so I shouldn't have a requires clause for it.

But if I delete the requires clause to make javac happy, it makes kotlinc even angrier than javac was (I get an error not a warning):

e: /path/to/my.module/src/main/java/module-info.java: The Kotlin standard library is not found in the module graph. Please ensure you have the 'requires kotlin.stdlib' clause in your module definition

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':my.module:compileKotlin'.

Now I can fix that, too, by editing my compileKotlin task thus:

compileKotlin {
    doFirst {
        kotlinOptions.freeCompilerArgs = ['-Xallow-kotlin-package']
    }
}

But this only leads to MORE errors during the compileKotlin task, all looking like this one:

e: /path/to/my.module/src/main/kotlin/Foo.kt: (27, 30): Symbol is declared in module 'org.junit.jupiter.api' which current module does not depend on

And then if I try to force compileKotlin to take a module path rather than a classpath by adding "-Xmodule-path=${classpath.asPath}" to freeCompilerArgs and setting classpath to be empty, the Kotlin compiler can't find anything at all, and I end up with zillions of unresolved reference errors!

Why is the Kotlin compiler telling me I have to have requires kotlin.stdlib; when the Java compiler says the opposite? How can I get Kotlin and Java to work together to produce a Java 9 module?


回答1:


If you're authoring Java 9 module in Kotlin, you have to declare requires kotlin.stdlib in your module-info.java in order to satisfy runtime dependencies of the compiled Kotlin code in addition to the explicit dependencies on the standard library API.

javac warns you about requiring an automatic module when lint is enabled, because automatic modules have some potential drawbacks compared to normal modules. Until the standard library is compiled as a normal module, you have to deal with this warning.

-Xallow-kotlin-package compiler flag allows you to omit require kotlin.stdlib, because it is intended to be used only when the standard library itself is compiled. Obviously, if you specify this flag and omit that requirement, you won't be able to use any API from the standard library, so this is not really an option for you.




回答2:


I find it easiest to simply suppress the warnings for use of an automatic module. (In my case I have to use some automatic modules whether I want to or not, so these warnings are just distracting noise.) I have the following in my build.gradle.kts:

val compilerArgs = listOf(
    "-Xlint:all",                           // Enable all warnings except...
    "-Xlint:-requires-automatic",           // Suppress "requires directive for an automatic module" warnings from module-info.java
    "-Xlint:-requires-transitive-automatic" // Suppress "requires transitive directive for an automatic module" warnings from module-info.java
)

// This task will compile all Java code in the target module except for test code.
tasks.compileJava {
    doFirst {
        options.compilerArgs.addAll(compilerArgs)
    }
}

// This task will compile all Java test code in the target module.
tasks.compileTestJava {
    doFirst {
        options.compilerArgs.addAll(compilerArgs)
    }
}


来源:https://stackoverflow.com/questions/47958627/do-kotlin-1-2-10-and-java-9-have-opposite-rules-regarding-automatic-modules

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!