I investigated a little bit further. Somehow I assumed that all legacy non-module libraries are accessible by everything else. In particular other java modules. However this is not the case. All non-module libraries are put (by Gradle) in the classpath and form the so called unnamed module. This is true for the Scala library, as its jars do not contain a module-info.class. So the first step towards fixing this is to allow my libraries module access to the unnamed module. This is done via
--add-reads eu.geekplace.beanstalk.core=ALL-UNNAMED
when invoking the JVM.
However, there is still one issue, which is suspect to be a Gradle bug. Starting the application with
$ ./gradlew beanstalk-app:run
shows that Gradle invokes the JVM without the Scala jars put in the class path, instead they are added to the module path. However, Gradle’s documentation states
. Gradle will automatically put a Jar of your dependencies on the module path, instead of the classpath, if these three things are true:
- …
- …
- The Jar our module depends on is itself a module, which Gradles decides based on the presence of a
module-info.class
— the compiled version of the module descriptor — in the Jar. (Or, alternatively, the presence of an Automatic-Module-Name
attribute the Jar manifest)
since the last point is not true for Scala’s runtime libraries, they should not be provided via --module-path
but via --class-path
. However, this is the command, extracted from Gradle’s debug output, that gradle uses to execute the application:
flo@ubook beanstalk $ /opt/openjdk-bin-19.0.1_p10/bin/java \
--enable-preview \
--add-reads eu.geekplace.beanstalk.core=ALL-UNNAMED \
-Dfile.encoding=UTF-8 -Duser.country=US -Duser.language=en -Duser.variant \
--module-path /home/flo/repos/beanstalk/beanstalk-app/build/libs/beanstalk-app.jar:/home/flo/repos/beanstalk/beanstalk-core/build/libs/beanstalk-core.jar:/home/flo/.gradle/caches/modules-2/files-2.1/org.scala-lang/scala3-library_3/3.2.1/ddc77e1f365f0a5202dda84eefede515feb93784/scala3-library_3-3.2.1.jar:/home/flo/.gradle/caches/modules-2/files-2.1/org.scala-lang/scala-library/2.13.10/67c1afabaea9ba51321159e70a78515647e1b73d/scala-library-2.13.10.jar \
--module eu.geekplace.beanstalk.app/eu.geekplace.beanstalk.app.App
WARNING: Using incubator modules: jdk.incubator.concurrent
Hello first
Hello second
Exception in thread "main" java.lang.NoClassDefFoundError: scala/Predef$
at eu.geekplace.beanstalk.core/eu.geekplace.beanstalk.core.scala.BeanstalkScala.sayHello(BeanstalkScala.scala:4)
at eu.geekplace.beanstalk.app/eu.geekplace.beanstalk.app.App.main(App.java:8)
Caused by: java.lang.ClassNotFoundException: scala.Predef$
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
... 2 more
If I move Scala’s runtime libraries from --module-path
to --class-path
, then the application works as expected:
flo@ubook beanstalk $ /opt/openjdk-bin-19.0.1_p10/bin/java \
--enable-preview \
--add-reads eu.geekplace.beanstalk.core=ALL-UNNAMED \
-Dfile.encoding=UTF-8 -Duser.country=US -Duser.language=en -Duser.variant \
--module-path /home/flo/repos/beanstalk/beanstalk-app/build/libs/beanstalk-app.jar:/home/flo/repos/beanstalk/beanstalk-core/build/libs/beanstalk-core.jar \
--class-path /home/flo/.gradle/caches/modules-2/files-2.1/org.scala-lang/scala3-library_3/3.2.1/ddc77e1f365f0a5202dda84eefede515feb93784/scala3-library_3-3.2.1.jar:/home/flo/.gradle/caches/modules-2/files-2.1/org.scala-lang/scala-library/2.13.10/67c1afabaea9ba51321159e70a78515647e1b73d/scala-library-2.13.10.jar
--module eu.geekplace.beanstalk.app/eu.geekplace.beanstalk.app.App
WARNING: Using incubator modules: jdk.incubator.concurrent
Hello first
Hello second
Hello World from Scala
The source code of the minimal non-working project can be found at
Is there something wrong with my project setup, or is this a bug in Gradle?