Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

script with java.sql.Date reference hits a NoClassDefFoundError when running from compiled jar #13760

Closed
philwalk opened this issue Oct 17, 2021 · 9 comments · Fixed by #15103

Comments

@philwalk
Copy link
Contributor

philwalk commented Oct 17, 2021

Compiler version

Scala code runner version 3.1.1-RC2 -- Copyright 2002-2021, LAMP/EPFL

The problem occurs when running a script with these runtime java versions:

  • openjdk version "16.0.1" 2021-04-20
  • java version "11.0.12" 2021-07-20 LTS

The problem does NOT occur with java 8

  • openjdk version "1.8.0_312"

The symptoms are similar to those reported in #11646, although the problem here is restricted to running the compiled jar.

Minimized code

If a script references java.sql.Date, a NoClassDefFoundError occurs, but only when running from a compiled script jar.

Here's the test script (notice the -save option in the hash bang line):

#!/opt/scala3/bin/scala -save
def main(args: Array[String]): Unit = {
    val d: java.sql.Date = new java.sql.Date(100L) // Compile and execution is successfully.
    println(d)
}

Output

The compile-and-run pass is successful:

/opt/scala3/bin/scala -save sqlDateError.sc
C:/opt/scala3

But because -save is specified, subsequent script runs execute from the compiled jar file, producing the error java.lang.NoClassDefFoundError: java/sql/Date

$ /opt/scala3/bin/scala -save ./sqlDateBug.sc
Exception in thread "main" java.lang.NoClassDefFoundError: java/sql/Date
        at java.base/java.lang.Class.getDeclaredMethods0(Native Method)
        at java.base/java.lang.Class.privateGetDeclaredMethods(Class.java:3166)
        at java.base/java.lang.Class.getMethodsRecursive(Class.java:3307)
        at java.base/java.lang.Class.getMethod0(Class.java:3293)
        at java.base/java.lang.Class.getMethod(Class.java:2106)
        at dotty.tools.runner.RichClassLoader$.run$extension(ScalaClassLoader.scala:91)
        at dotty.tools.runner.CommonRunner.run(ObjectRunner.scala:23)
        at dotty.tools.runner.CommonRunner.run$(ObjectRunner.scala:13)
        at dotty.tools.runner.ObjectRunner$.run(ObjectRunner.scala:48)
        at dotty.tools.runner.CommonRunner.runAndCatch(ObjectRunner.scala:30)
        at dotty.tools.runner.CommonRunner.runAndCatch$(ObjectRunner.scala:13)
        at dotty.tools.runner.ObjectRunner$.runAndCatch(ObjectRunner.scala:48)
        at dotty.tools.MainGenericRunner$.run$1(MainGenericRunner.scala:218)
        at dotty.tools.MainGenericRunner$.main(MainGenericRunner.scala:238)
        at dotty.tools.MainGenericRunner.main(MainGenericRunner.scala)
Caused by: java.lang.ClassNotFoundException: java.sql.Date
        at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:471)
        at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:588)
        at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
        ... 15 more
``` 

However, there seems to be nothing wrong with the compiled jar itself, which can be run directly by java:

java -jar sqlDateBug.jar

Expectation

A script running from the compiled jar file should behave the same as when doing a compile-and-run.

@philwalk

This comment has been minimized.

@michelou
Copy link
Contributor

@philwalk The section Removed Tools Support for Compact Profiles you mention in your issue description also states the following :

"[...] You can use the jdeps tool to do a static analysis of the Java packages that are being used in your source code."

When targetting JDK 9+ a library developer (e.g. authoring sqlDateError.jar) should be aware of the usage of compact profiles and should take care appropriately.

As a first reaction I would say it's not a good idea to modify dotty.tools.MainGenericRunner and dotty.tools.scripting.Main.

PS. Based on my experience (I'm coding in Java since JDK 1.O) people must accept that developping under JDK 9+ is a more demanding task.

@philwalk
Copy link
Contributor Author

philwalk commented Dec 24, 2021

As a first reaction I would say it's not a good idea to modify dotty.tools.MainGenericRunner and dotty.tools.scripting.Main

Changes that are necessary haven't yet been registered in a bug report, but there is an issue that needs to be addressed:

  • the wrong classpath is used when executing from a jar file

When testing the minimized code above (with scala3-3.1.1-RC2):

  • the compile and run phase is successful,
  • the run from the compiled jar throws java.lang.NoClassDefFoundError: java/sql/Date

However, when running the compiled jar directly via java -jar sqlDateError.jar, it quietly catches and discards the exception. it runs successfully, although the original version of the script would not print anything, since sys.props("scala.home") would not be initialized in that case.

@michelou
Copy link
Contributor

@philwalk Thanks for the clarification. I can't wait to see the proposed changes and their effect on runtime behavior 😉

@philwalk
Copy link
Contributor Author

philwalk commented Dec 25, 2021

Updating the classpath when dotty.tools.MainGenericRunner runs from the Jar file does not resolve this issue, so I will continue to investigate.

Also note the simplified test script above. It can be expected to behave the same way whether the jar is executed internally by dotty.tools.MainGenericRunner or directly via java -jar

The original script would need -Dscala.home=/opt/scala3 or similar on the java -jar command line in order to print anything.

To my surprise, the problem also occurs with java 8, so it seems to have nothing to do with the java module system of jdk9+.
I wasn't able to duplicate the error with java 8, so my best guess is that this does seem to be related to jdk9+ modules.

@philwalk philwalk changed the title with jdk9+, script with java.sql.Date reference hits a NoClassDefFoundError when running from compiled jar script with java.sql.Date reference hits a NoClassDefFoundError when running from compiled jar Dec 25, 2021
@philwalk
Copy link
Contributor Author

#14241 provides 2 fixes plus a workaround for this bug.

  • exceptions are always reported when executing from a compiled jar file
  • will not execute from a previously compiled jar file unless the -save option is specified
  • a -nosave option provides a way to selectively prevent scripts affected by this bug from executing via the jar

@BarkingBad BarkingBad linked a pull request Jan 11, 2022 that will close this issue
BarkingBad added a commit that referenced this issue Jan 12, 2022
@BarkingBad
Copy link
Contributor

@philwalk should we close it or is you want to continue work on this issue?

@philwalk
Copy link
Contributor Author

philwalk commented Jan 16, 2022

should we close it or is you want to continue work on this issue?

I don't know if we should close it, the underlying problem is still there, and can possibly be fixed the same way #11658 was fixed, by using a different classloader. However, I won't be able to work on it soon.

@philwalk
Copy link
Contributor Author

philwalk commented May 5, 2022

PR #15103 provides a fix for this.

bishabosha added a commit that referenced this issue May 19, 2022
fix for #13760 - running script compiled jar no longer restricted to java.base module
bishabosha pushed a commit to dotty-staging/dotty that referenced this issue May 20, 2022
bishabosha pushed a commit to dotty-staging/dotty that referenced this issue Oct 18, 2022
@Kordyjan Kordyjan added this to the 3.2.0 milestone Aug 2, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
5 participants