Gradle 7.6, JDK 19 and Scala 3: "java.lang.ClassNotFoundException: scala.Predef$" even though scala-library-2.13.10.jar is in classpath

I’ve setup a small minimal example Gradle 7.6 project which uses JDK 19 and Scala. Compilation of Java and Scala is done without any errors, however as soon as I run the “application” the JVM is unable to find Scala’s Predef:

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:7)
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

even though, I believe Predef’s class is in classpath, since scala-library-2.13.10.jar, which apparently contains Predef, is in the classpath. Checked via invoking gradle with --debug, which shows the following arguments being passed to the JVM when executing the application

/opt/openjdk-bin-19.0.1_p10/bin/java \
  --enable-preview \
  -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

The minimal non-working example can be found at

Why isn’t the JVM finding the class?

Looks like some JPMS incantation is needed to make the scala.library module available to the code in question?

(Is this your first experience with JPMS, or you already understand JPMS and still can’t make this work…?)

You are right, I assumed that Java modules have implicit full access to traditional non-module libraries. This is not the case, so I added --add-reads eu.geekplace.beanstalk.core=ALL-UNNAMED to grant my module access to the unnamed module. However, it appears that Gradle constructs a wrong command line when executing the JVM in order to run the app: Scala’s runtime libraries are put in the module path and not in the class path, even though, they are not modular. See

for more background.

You wrote:

(Or, alternatively, the presence of an Automatic-Module-Name attribute the Jar manifest)

the last point is not true for Scala’s runtime libraries

But scala3-library and scala-library both do have Automatic-Module-Name in their manifests.

Thanks for pointing this out (also in the gradle bug. However if I add requires org.scala.lang.scala3.library; to my module-info.java, then I get the following warnings:

error: the unnamed module reads package scala from both scala.library and org.scala.lang.scala3.library
error: the unnamed module reads package scala.util from both scala.library and org.scala.lang.scala3.library
error: the unnamed module reads package scala.util.control from both scala.library and org.scala.lang.scala3.library
error: the unnamed module reads package scala.runtime from both scala.library and org.scala.lang.scala3.library
error: the unnamed module reads package scala.reflect from both scala.library and org.scala.lang.scala3.library
error: the unnamed module reads package scala.annotation from both scala.library and org.scala.lang.scala3.library
error: module scala.library reads package scala from both org.scala.lang.scala3.library and scala.library
error: module scala.library reads package scala.util from both org.scala.lang.scala3.library and scala.library
error: module scala.library reads package scala.util.control from both org.scala.lang.scala3.library and scala.library
error: module scala.library reads package scala.runtime from both org.scala.lang.scala3.library and scala.library
error: module scala.library reads package scala.reflect from both org.scala.lang.scala3.library and scala.library
error: module scala.library reads package scala.annotation from both org.scala.lang.scala3.library and scala.library
error: module org.scala.lang.scala3.library reads package scala from both scala.library and org.scala.lang.scala3.library
error: module org.scala.lang.scala3.library reads package scala.util from both scala.library and org.scala.lang.scala3.library
error: module org.scala.lang.scala3.library reads package scala.util.control from both scala.library and org.scala.lang.scala3.library
error: module org.scala.lang.scala3.library reads package scala.runtime from both scala.library and org.scala.lang.scala3.library
error: module org.scala.lang.scala3.library reads package scala.reflect from both scala.library and org.scala.lang.scala3.library
error: module org.scala.lang.scala3.library reads package scala.annotation from both scala.library and org.scala.lang.scala3.library
/home/flo/repos/beanstalk/beanstalk-core/src/main/java/module-info.java:1: error: module eu.geekplace.beanstalk.core reads package scala from both org.scala.lang.scala3.library and scala.library
module eu.geekplace.beanstalk.core {
^
19 errors

I assume that is because the scala package is provided by multiple modules: scala3-library and scala-library (upon which scala3-library depends). I guess I have to wait till

is fixed? Or are there other ways to get my build going? :slight_smile:

We’ve reached the limits of my knowledge of JPMS — perhaps someone else can offer assistance.

The relevant Scala 2 PR is Add Automatic-Module-Name attribute to library, reflect, compiler by retronym · Pull Request #6395 · scala/scala · GitHub and the relevant Scala 3 PR is Add Automatic-Module-Names to MANIFEST.MF files of projects with suffix_3 by makingthematrix · Pull Request #12903 · lampepfl/dotty · GitHub

Unless I’ve misunderstood something, Support JEP-261 Module System · Issue #529 · scala/scala-dev · GitHub is orthogonal, as I don’t think the problem you’re experiencing stems from lack of JPMS support in the Scala compiler.

I’ve fixed it via --patch-module \o/

Using

--patch-module org.scala.lang.scala3.library scala-library-2.13.10.jar

will “patch” the contents of scala-library in the org.scala.lang.scala3.library module, which scala3-library declares, and thus resolve the split package situation.

But thanks for pointing me into the right direction! :slight_smile:

Nice! Thanks for coming back and recording the answer here, for future searchers.

1 Like