We have a JavaFX based application which is not modularized (there are reasons, a legacy library is involved) but we build an custom runtime using jdeps
and jlink
.
We’ve recently rewritten the app and added a couple of new dependencies, as well as removing others. Now the script that is building the application suddenly stopped working during the jdeps
call.
Note: This is happening on Linux – I’ve yet to test other OS’ses, but I don’t expect another result.
When the script calls
~/path/to/jdk/bin/jdeps -q --multi-release 11 --ignore-missing-deps --print-module-deps --class-path ~/path/to/app/target/package/libs/* target/classes/ch/cnlab/uxtest/MainKt.class
the result is always
Exception in thread "main" java.lang.Error: java.util.concurrent.ExecutionException: com.sun.tools.jdeps.MultiReleaseException at jdk.jdeps/com.sun.tools.jdeps.DependencyFinder.waitForTasksCompleted(DependencyFinder.java:271) at jdk.jdeps/com.sun.tools.jdeps.DependencyFinder.parse(DependencyFinder.java:133) at jdk.jdeps/com.sun.tools.jdeps.DepsAnalyzer.transitiveArchiveDeps(DepsAnalyzer.java:217) at jdk.jdeps/com.sun.tools.jdeps.DepsAnalyzer.run(DepsAnalyzer.java:138) at jdk.jdeps/com.sun.tools.jdeps.ModuleExportsAnalyzer.run(ModuleExportsAnalyzer.java:74) at jdk.jdeps/com.sun.tools.jdeps.JdepsTask$ListModuleDeps.run(JdepsTask.java:1047) at jdk.jdeps/com.sun.tools.jdeps.JdepsTask.run(JdepsTask.java:574) at jdk.jdeps/com.sun.tools.jdeps.JdepsTask.run(JdepsTask.java:533) at jdk.jdeps/com.sun.tools.jdeps.Main.main(Main.java:49) Caused by: java.util.concurrent.ExecutionException: com.sun.tools.jdeps.MultiReleaseException at java.base/java.util.concurrent.FutureTask.report(FutureTask.java:122) at java.base/java.util.concurrent.FutureTask.get(FutureTask.java:191) at jdk.jdeps/com.sun.tools.jdeps.DependencyFinder.waitForTasksCompleted(DependencyFinder.java:267) ... 8 more Caused by: com.sun.tools.jdeps.MultiReleaseException at jdk.jdeps/com.sun.tools.jdeps.VersionHelper.add(VersionHelper.java:62) at jdk.jdeps/com.sun.tools.jdeps.ClassFileReader$JarFileReader.readClassFile(ClassFileReader.java:360) at jdk.jdeps/com.sun.tools.jdeps.ClassFileReader$JarFileIterator.hasNext(ClassFileReader.java:402) at jdk.jdeps/com.sun.tools.jdeps.DependencyFinder.lambda$parse$5(DependencyFinder.java:179) at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539) at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635) at java.base/java.lang.Thread.run(Thread.java:833)
I couldn’t find much in regards to this specific exception and everything I’ve found so far was not applicable to our situation.
To not wait as long as the build takes to reach this point, I’ve let the program print out the command before it gets executed and use it on a terminal. Then it get’s a bit weirder:
Exception in thread "main" java.lang.module.FindException: Module org.slf4j not found, required by com.dlsc.gmapsfx at java.base/java.lang.module.Resolver.findFail(Resolver.java:893) at java.base/java.lang.module.Resolver.resolve(Resolver.java:192) at java.base/java.lang.module.Resolver.resolve(Resolver.java:141) at java.base/java.lang.module.Configuration.resolve(Configuration.java:421) at java.base/java.lang.module.Configuration.resolve(Configuration.java:255) at jdk.jdeps/com.sun.tools.jdeps.JdepsConfiguration$Builder.build(JdepsConfiguration.java:564) at jdk.jdeps/com.sun.tools.jdeps.JdepsTask.buildConfig(JdepsTask.java:603) at jdk.jdeps/com.sun.tools.jdeps.JdepsTask.run(JdepsTask.java:557) at jdk.jdeps/com.sun.tools.jdeps.JdepsTask.run(JdepsTask.java:533) at jdk.jdeps/com.sun.tools.jdeps.Main.main(Main.java:49)
Why of all sudden to I get a different exception? Which one is correct now? I have no clue.
Fact is, the jar containing org.slf4j
only has the automatic module name.
I really have have no idea, what I should do with little information… If someone else can point to something, I’d be glad.
Thanks, Daniel
PS: The following code prints the command and executes it:
echo "detecting required modules" CMD="$JDK/bin/jdeps -q --multi-release ${JAVA_VERSION} --ignore-missing-deps --print-module-deps --class-path ${OUT_LIBS}/* ${MAIN_CLASS_FILE}"; echo "$CMD" detected_modules=$("$JDK"/bin/jdeps -q --multi-release ${JAVA_VERSION} --ignore-missing-deps --print-module-deps --class-path "${OUT_LIBS}/*" "${MAIN_CLASS_FILE}") || exit echo "detected modules: ${detected_modules}"
They really seem to create different result… 🤷
PPS: If I remove the --multi-release
part, I get a different error, that jackson
is multi-release, but I need to specify what I want…
Error: jackson-core-2.13.0.jar is a multi-release jar file but --multi-release option is not set
Edit #1
In the pom file, we have the following deps
<dependency> <groupId>org.openjfx</groupId> <artifactId>javafx-base</artifactId> <version>${use.javafx.version}</version> </dependency> <dependency> <groupId>org.openjfx</groupId> <artifactId>javafx-controls</artifactId> <version>${use.javafx.version}</version> </dependency> <dependency> <groupId>org.openjfx</groupId> <artifactId>javafx-fxml</artifactId> <version>${use.javafx.version}</version> </dependency> <dependency> <groupId>org.openjfx</groupId> <artifactId>javafx-graphics</artifactId> <version>${use.javafx.version}</version> </dependency> <dependency> <groupId>org.openjfx</groupId> <artifactId>javafx-web</artifactId> <version>${use.javafx.version}</version> </dependency> <dependency> <groupId>org.jetbrains.kotlin</groupId> <artifactId>kotlin-stdlib-jdk8</artifactId> <version>${kotlin.version}</version> </dependency> <dependency> <groupId>org.jetbrains.kotlin</groupId> <artifactId>kotlin-reflect</artifactId> <version>${kotlin.version}</version> </dependency> <dependency> <groupId>org.jetbrains.kotlin</groupId> <artifactId>kotlin-test-junit</artifactId> <version>${kotlin.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.jetbrains.kotlinx</groupId> <artifactId>kotlinx-coroutines-core</artifactId> <version>${kotlinx.coroutines.version}</version> </dependency> <dependency> <groupId>org.jetbrains.kotlinx</groupId> <artifactId>kotlinx-coroutines-jdk8</artifactId> <version>${kotlinx.coroutines.version}</version> </dependency> <dependency> <groupId>io.insert-koin</groupId> <artifactId>koin-core-jvm</artifactId> <version>${koin.version}</version> </dependency> <dependency> <groupId>io.insert-koin</groupId> <artifactId>koin-test-jvm</artifactId> <version>${koin.version}</version> </dependency> <dependency> <groupId>org.simpleframework</groupId> <artifactId>simple-xml</artifactId> <version>${simplexml.version}</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version>${log4j.version}</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>${log4j.version}</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-web</artifactId> <version>${log4j.version}</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> <version>${jackson.version}</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>${jackson.version}</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>${jackson.version}</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.module</groupId> <artifactId>jackson-module-kotlin</artifactId> <version>${jackson.version}</version> </dependency> <dependency> <groupId>com.squareup.okhttp3</groupId> <artifactId>okhttp</artifactId> <version>${okhttp.version}</version> </dependency> <dependency> <groupId>net.sf.proguard</groupId> <artifactId>proguard-base</artifactId> <version>${proguard.version}</version> <scope>runtime</scope> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-api</artifactId> <version>${junit.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-engine</artifactId> <version>${junit.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.kordamp.ikonli</groupId> <artifactId>ikonli-materialdesign2-pack</artifactId> <version>${ikonli.mdi2.version}</version> </dependency> <dependency> <groupId>org.kordamp.ikonli</groupId> <artifactId>ikonli-javafx</artifactId> <version>${ikonli.version}</version> </dependency> <dependency> <groupId>org.controlsfx</groupId> <artifactId>controlsfx</artifactId> <version>${controlsfx.version}</version> </dependency> <dependency> <groupId>com.dlsc</groupId> <artifactId>GMapsFX</artifactId> <version>${gmapfx.version}</version> </dependency> <dependency> <groupId>org.xerial</groupId> <artifactId>sqlite-jdbc</artifactId> <version>${sqlite.jdbc.version}</version> </dependency> <!-- some custom deps from our company --> <dependency> <groupId>org.conscrypt</groupId> <artifactId>conscrypt-openjdk</artifactId> <version>${conscrypt.version}</version> <classifier>${os.detected.classifier}</classifier> </dependency>
Resulting in the following JAR files (minus our own):
annotations-13.0.jar apiguardian-api-1.1.2.jar conscrypt-openjdk-2.5.2-linux-x86_64.jar controlsfx-11.1.0.jar GMapsFX-11.0.2.jar hamcrest-core-1.3.jar ikonli-core-12.2.0.jar ikonli-javafx-12.2.0.jar ikonli-materialdesign2-pack-12.2.0.jar jackson-annotations-2.13.0.jar jackson-core-2.13.0.jar jackson-databind-2.13.0.jar jackson-module-kotlin-2.13.0.jar jakarta.activation-1.2.2.jar jakarta.activation-api-1.2.2.jar jakarta.xml.bind-api-2.3.3.jar jaxb-impl-2.3.3.jar junit-4.12.jar junit-jupiter-api-5.8.1.jar junit-jupiter-engine-5.8.1.jar junit-platform-commons-1.8.1.jar junit-platform-engine-1.8.1.jar koin-core-jvm-3.1.3.jar koin-test-jvm-3.1.3.jar kotlin-reflect-1.5.31.jar kotlin-stdlib-1.5.31.jar kotlin-stdlib-common-1.5.30.jar kotlin-stdlib-jdk7-1.5.31.jar kotlin-stdlib-jdk8-1.5.31.jar kotlin-test-1.5.31.jar kotlin-test-annotations-common-1.5.30.jar kotlin-test-common-1.5.30.jar kotlin-test-junit-1.5.31.jar kotlinx-coroutines-core-1.5.2.jar kotlinx-coroutines-core-jvm-1.5.2.jar kotlinx-coroutines-jdk8-1.5.2.jar log4j-api-2.14.1.jar log4j-core-2.14.1.jar log4j-web-2.14.1.jar logback-classic-1.2.3.jar logback-core-1.2.3.jar okhttp-4.9.2.jar okio-2.8.0.jar opentest4j-1.2.0.jar proguard-base-6.2.2.jar simple-xml-2.7.1.jar slf4j-api-1.7.29.jar sqlite-jdbc-3.36.0.3.jar stax-1.2.0.jar stax-api-1.0.1.jar xpp3-1.1.3.3.jar
The Java version in use is Bell Soft’s Full Liberica JDK 17, we used all recent versions since 14 or 15 where it worked well prior to the rebuild of the UI.
edit #2:
The result of
mvn compile org.apache.maven.plugins:maven-dependency-plugin:3.1.1:resolve -DexcludeTransitive
is
[INFO] The following files have been resolved: [INFO] com.fasterxml.jackson.core:jackson-databind:jar:2.13.0:compile -- module com.fasterxml.jackson.databind [INFO] com.squareup.okhttp3:okhttp:jar:4.9.2:compile -- module okhttp3 [auto] [INFO] com.fasterxml.jackson.core:jackson-annotations:jar:2.13.0:compile -- module com.fasterxml.jackson.annotation [INFO] org.openjfx:javafx-fxml:jar:17.0.1:compile -- module javafx.fxmlEmpty [auto] [INFO] org.openjfx:javafx-web:jar:17.0.1:compile -- module javafx.webEmpty [auto] [INFO] org.jetbrains.kotlin:kotlin-stdlib-jdk8:jar:1.5.31:compile -- module kotlin.stdlib.jdk8 [INFO] io.insert-koin:koin-core-jvm:jar:3.1.3:compile -- module koin.core.jvm (auto) [INFO] org.jetbrains.kotlin:kotlin-test-junit:jar:1.5.31:test -- module kotlin.test.junit [INFO] org.simpleframework:simple-xml:jar:2.7.1:compile -- module simple.xml [auto] [INFO] org.apache.logging.log4j:log4j-core:jar:2.14.1:compile -- module org.apache.logging.log4j.core [auto] [INFO] io.insert-koin:koin-test-jvm:jar:3.1.3:compile -- module koin.test.jvm (auto) [INFO] org.junit.jupiter:junit-jupiter-engine:jar:5.8.1:test -- module org.junit.jupiter.engine [INFO] org.xerial:sqlite-jdbc:jar:3.36.0.3:compile -- module org.xerial.sqlitejdbc [auto] [INFO] net.sf.proguard:proguard-base:jar:6.2.2:runtime -- module proguard.base (auto) [INFO] org.openjfx:javafx-graphics:jar:17.0.1:compile -- module javafx.graphicsEmpty [auto] [INFO] org.jetbrains.kotlinx:kotlinx-coroutines-core:jar:1.5.2:compile -- module kotlinx.coroutines.core (auto) [INFO] org.apache.logging.log4j:log4j-web:jar:2.14.1:compile -- module org.apache.logging.log4j.web [auto] [INFO] ch.<ourgroup>:<our-artifact>:1.8.8:compile -- module <our-lib> (auto) [INFO] org.openjfx:javafx-controls:jar:17.0.1:compile -- module javafx.controlsEmpty [auto] [INFO] org.controlsfx:controlsfx:jar:11.1.0:compile -- module org.controlsfx.controls [INFO] com.fasterxml.jackson.core:jackson-core:jar:2.13.0:compile -- module com.fasterxml.jackson.core [INFO] com.fasterxml.jackson.module:jackson-module-kotlin:jar:2.13.0:compile -- module com.fasterxml.jackson.kotlin [INFO] org.apache.logging.log4j:log4j-api:jar:2.14.1:compile -- module org.apache.logging.log4j [INFO] org.openjfx:javafx-base:jar:17.0.1:compile -- module javafx.baseEmpty [auto] [INFO] org.junit.jupiter:junit-jupiter-api:jar:5.8.1:test -- module org.junit.jupiter.api [INFO] org.kordamp.ikonli:ikonli-javafx:jar:12.2.0:compile -- module org.kordamp.ikonli.javafx [INFO] com.dlsc:GMapsFX:jar:11.0.2:compile -- module com.dlsc.gmapsfx [INFO] org.jetbrains.kotlin:kotlin-reflect:jar:1.5.31:compile -- module kotlin.reflect [INFO] org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:jar:1.5.2:compile -- module kotlinx.coroutines.jdk8 (auto) [INFO] org.kordamp.ikonli:ikonli-materialdesign2-pack:jar:12.2.0:compile -- module org.kordamp.ikonli.materialdesign2 [INFO] org.conscrypt:conscrypt-openjdk:jar:linux-x86_64:2.5.2:compile -- module org.conscrypt [auto]
Advertisement
Answer
Update: These issues have been fixed, and a patched version of jdeps
is available as part of the early access build for JDK 18 at: http://jdk.java.net/18/ (starting from build 26)
Turning my comments into an answer. There seem to be 3 bugs going on here:
- The
MultiReleaseException
seems to be becausejdeps
can not handle classes in different jars that have the same name, such asmodule-info.class
, but are stored in a differentMETA-INF/versions/xxx
directory. (JDK-8277165) - The fact that this exception is sometimes suddenly not occuring seems to be the result of a race condition in the code that checks for the above; classes of the same name having multiple versions. (JDK-8277166)
- The
MultiReleaseException
is missing it’s exception message since it’s thrown as part of an asynchronous task, which wraps it in anExecutionException
, which then leads tojdeps
not reporting the exception correctly. (JDK-8277123)
As for a workaround, I don’t think there’s a good one at this point, except maybe for editing all the jars on the class path so that they put the module-info.class
in the same META-INF/versions/xxx
directory (but, this might have other consequences as well, so you probably don’t want to run with the edited jars, and only use them for jdeps
).