3

I'm trying to find a workaround for Nashorn to be compatible with every version of Java from 1.8 upwards as said in another question I asked earlier.
I'm currently trying to catch UnsupportedClassVersionError in order to find out if the system is able to run the standalone Nashorn for Java 15 like this (Kotlin code):

scriptEngine = try {
            
    // Java >= 15

    org.openjdk.nashorn.api.scripting.NashornScriptEngineFactory().scriptEngine
} catch(e: UnsupportedClassVersionError) {

    // Java < 15

    @Suppress("DEPRECATION")
    jdk.nashorn.api.scripting.NashornScriptEngineFactory().scriptEngine
}

However it looks like the error is not caught. The stack trace is as follows:

java.lang.UnsupportedClassVersionError: org/openjdk/nashorn/api/linker/NashornLinkerExporter has been compiled by a more recent version of the Java Runtime (class file version 59.0), this version of the Java Runtime only recognizes class file versions up to 55.0

I also have tried to catch NoClassDefFoundError inverting the previous try/catch (load Java < 15 Nashorn, if it doesn't exist load the standalone one) but the error is the same.

Edit: looks like the error is thrown by the Java < 15 Nashorn itself.

ZhekaKozlov
  • 36,558
  • 20
  • 126
  • 155
iamgio
  • 83
  • 9

3 Answers3

6

Nashorn maintainer here! I just released Nashorn 15.2, which is identical to 15.1.1 but is now compiled with Java 11. This means you can now use standalone Nashorn with Java 11 and above and don't have to switch for < 15 and >= 15. I wrote a page to explain how to use it on Java 11-14 where both built-in and standalone Nashorn are present.

Attila Szegedi
  • 4,405
  • 26
  • 24
2

How about something like this (sorry, I'm not a Kotlin developer, so pure Java):

public static ScriptEngine getJSScriptEngine() {
    if (Double.parseDouble(System.getProperty("java.specification.version")) < 15) {
        return new ScriptEngineManager().getEngineByName("js");
    } else {
        return new org.openjdk.nashorn.api.scripting.NashornScriptEngineFactory()
            .getScriptEngine();
    }
}
ZhekaKozlov
  • 36,558
  • 20
  • 126
  • 155
1

Error is thrown by the JVM itself. It's thrown from inside catch block, cause during classloading of old Nashorn it for some reason (name clashing?) ends up with loading a class (NashornLinkerExporter) from stand-alone version of Nashorn, which seems to be present in classpath too, and since it was compiled with jvmTarget=15, it couldn'd be loaded in earlier JVM.

For JVM<15 you need to exclude this library from your bundle (creating separate artifact by your build tool), or at least from runtime classpath. In this case NoClassDefFoundError will be thrown from inside try block, and no errors will be thrown from inside catch block.