jigsaw: cannot find Kotlin symbols

Viewed 284

I have a Java/Kotlin project with multiple sub-projects (modules). This is module-info.java for the base module:

module ir.openuniverse {
    requires java.desktop;
    requires kotlin.stdlib;
    requires transitive org.apache.logging.log4j;
    requires org.apache.logging.log4j.core;

    exports ir.openuniverse;  // Base module has exported here.
}

And for a consumer module, I have:

module ir.openuniverse.watchservice {
    requires kotlin.stdlib;
    requires gson;
    requires ir.openuniverse; // Base module has imported here

    exports ir.openuniverse.watchservice;
}

Now I insert a test file in consumer module:

package ir.openuniverse.watchservice;

import ir.openuniverse.UtilKt;
import ir.openuniverse.JUtil;
import ir.openuniverse.Entry; 

public class Test {}

and then try to compile it:

> Task :watch-service:compileJava FAILED
[...]\watch-service\src\main\ir\openuniverse\watchservice\Test.java:3: error: cannot find symbol
import ir.openuniverse.UtilKt;
                      ^
  symbol:   class UtilKt
  location: package ir.openuniverse
[...]\watch-service\src\main\ir\openuniverse\watchservice\Test.java:5: error: cannot find symbol
import ir.openuniverse.Entry;
                      ^
  symbol:   class Entry
  location: package ir.openuniverse
2 errors

FAILURE: Build failed with an exception.

All three classes (UtilKt, JUtil, Entry) are in the base module. But JUtil is in Java (JUtil.java) and two others in Kotlin (Util.kt and Entry.kt).

As you can see there is no problem with importing JUtil, but the classes that their sources in Kotlin, can't be resolved. (Without importing two Kotlin classes I can compile the module, successfully).

Also, there is no problem if I don't use Java 9 module system totally.


I use Gradle and tested with these two plugins:

gradle.plugin.org.gradle.java:experimental-jigsaw:0.1.1

xor:

gradle.plugin.rgoldberg:experimental-jigsaw:0.4.1-SNAPSHOT

UPDATE 1:

Due to @nullpointer's comment, I tried to check classpaths. This is a part of executing the task with --debug option that shows -classpath is empty and --module-path has correct values (Especially see these two: D:\Devel\IdeaProjects\Tinifier\base\build\classes\java\main;D:\Devel\IdeaProjects\Tinifier\base\build\classes\kotlin\main;):

05:40:29.575 [DEBUG] [org.gradle.api.internal.tasks.compile.NormalizingJavaCompiler] Compiler arguments: -source 11 -target 11 -d D:\Devel\IdeaProjects\Tinifier\watch-service\build\classes\java\main -g -sourcepath  -proc:none -XDuseUnsharedTable=true -classpath  --module-path D:\Devel\.gradle\caches\modules-2\files-2.1\org.jetbrains.kotlin\kotlin-stdlib-jdk8\1.3.10\71d0fa967493eb76648b575edf1762cb2d0c7f10\kotlin-stdlib-jdk8-1.3.10.jar;D:\Devel\.gradle\caches\modules-2\files-2.1\com.google.code.gson\gson\2.8.5\f645ed69d595b24d4cf8b3fbb64cc505bede8829\gson-2.8.5.jar;D:\Devel\IdeaProjects\Tinifier\base\build\classes\java\main;D:\Devel\IdeaProjects\Tinifier\base\build\classes\kotlin\main;D:\Devel\.gradle\caches\modules-2\files-2.1\org.jetbrains.kotlin\kotlin-stdlib-jdk7\1.3.10\4d147bf43060dc43d61b096e24da1e67dfe0c032\kotlin-stdlib-jdk7-1.3.10.jar;D:\Devel\.gradle\caches\modules-2\files-2.1\org.jetbrains.kotlin\kotlin-stdlib\1.3.10\b178c1501609c6e4ee8be635513cb023a466457d\kotlin-stdlib-1.3.10.jar;D:\Devel\.gradle\caches\modules-2\files-2.1\org.apache.logging.log4j\log4j-api\2.11.1\268f0fe4df3eefe052b57c87ec48517d64fb2a10\log4j-api-2.11.1.jar;D:\Devel\.gradle\caches\modules-2\files-2.1\org.jetbrains.kotlin\kotlin-stdlib-common\1.3.10\1b19d99229dcedad7caf50534dce38fe82845269\kotlin-stdlib-common-1.3.10.jar;D:\Devel\.gradle\caches\modules-2\files-2.1\org.jetbrains\annotations\13.0\919f0dfe192fb4e063e7dacadee7f8bb9a2672a9\annotations-13.0.jar;D:\Devel\IdeaProjects\Tinifier\watch-service\build\classes\kotlin\main D:\Devel\IdeaProjects\Tinifier\watch-service\src\main\ir\openuniverse\watchservice\T.java D:\Devel\IdeaProjects\Tinifier\watch-service\src\main\module-info.java
05:40:29.576 [INFO] [org.gradle.api.internal.tasks.compile.JdkJavaCompiler] Compiling with JDK Java compiler API.
05:40:30.138 [ERROR] [system.err] D:\Devel\IdeaProjects\Tinifier\watch-service\src\main\ir\openuniverse\watchservice\T.java:3: error: cannot find symbol
05:40:30.139 [ERROR] [system.err] import ir.openuniverse.UtilKt;
05:40:30.139 [ERROR] [system.err]                       ^
05:40:30.139 [ERROR] [system.err]   symbol:   class UtilKt
05:40:30.139 [ERROR] [system.err]   location: package ir.openuniverse
05:40:30.142 [ERROR] [system.err] D:\Devel\IdeaProjects\Tinifier\watch-service\src\main\ir\openuniverse\watchservice\T.java:5: error: cannot find symbol
05:40:30.142 [ERROR] [system.err] import ir.openuniverse.Entry;
05:40:30.143 [ERROR] [system.err]                       ^
05:40:30.143 [ERROR] [system.err]   symbol:   class Entry
05:40:30.143 [ERROR] [system.err]   location: package ir.openuniverse
05:40:30.164 [ERROR] [system.err] 2 errors

Unfortunately, even though I know Compiler arguments from above logs, I don't know how to manually compile the source. Simply running javac <compiler-arguments> doesn't work.


UPDATE 2:

Making a copy of Kotlin .class files to the path of Java .class files solved the issue. See my answer for a simple Gradle's configuration to do this. But I know this is not a fundamental solution.


UPDATE 3:

I found a more fundamental issue! If I remove all Java sources from a module (even if it's not depended on another; like my base module) and just stay Kotlin sources, then the compilation of that module throws at where that package (that includes only Kotlin sources) exported (in module-info.java) and says the package is empty!!:

> Task :base:compileJava FAILED
D:\Devel\IdeaProjects\Tinifier\base\src\main\module-info.java:9: error: package is empty or does not exist: ir.openuniverse
    exports ir.openuniverse;
              ^
1 error

FAILURE: Build failed with an exception.
1 Answers

Making a copy of Kotlin .class files to the path of Java .class files solved the issue. But I know this is not a fundamental solution (As a sample see UPDATE 3 of the question). You can change the destination path of the Kotlin compilation. In Gradle:

sourceSets {
    main {
        // Optional: Removing `java` directory from output path that usually is `build/classes/java/main/`:  
        java.outputDir = file(java.outputDir.toString().replaceAll("\\${File.separatorChar}java", ""))

        // Mandatory:
        kotlin.outputDir = java.outputDir 
    }
}

compileKotlin {
    kotlinOptions.jvmTarget = "1.8"

    // Unfortunately setting `main.kotlin.outputDir` isn't enough. See: https://stackoverflow.com/questions/49638136/kotlin-gradle-plugin-how-to-use-custom-output-directory#comment95108749_49638136 and https://youtrack.jetbrains.com/issue/KT-23807
    destinationDir = sourceSets.main.kotlin.outputDir
}

compileTestKotlin {
    // ...
}
Related