How to use Nashorn in Java 15 and later?

吃可爱长大的小学妹 提交于 2020-12-25 09:25:08

问题


I have an existing Spring Boot application that is non-modular and uses Nashorn. The application works well on Java 14.

After adding the Maven coordinates of the new Nashorn available for Java 15, the application fails while starting the script engine.

public static void main(String[] args) throws ScriptException {
    ScriptEngineManager factory = new ScriptEngineManager();
    ScriptEngine engine = factory.getEngineByName("nashorn"); 
    engine.eval("print('Hello, World!');");
} 

Error message:

Exception in thread "main" java.lang.NullPointerException: Cannot invoke "javax.script.ScriptEngine.eval(String)" because "engine" is null
    at xxxxx.yyyy.service.JavaScriptServiceImpl.main(JavaScriptServiceImpl.java:52)

Is it required to modularize the whole project to make use of Nashorn?


回答1:


According to JEP 372, Nashorn had been removed from JDK 15 but you can get latest nashorn from https://search.maven.org/artifact/org.openjdk.nashorn/nashorn-core/15.0/jar

For Maven, include the below dependency into your pom.xml

<dependency>
  <groupId>org.openjdk.nashorn</groupId>
  <artifactId>nashorn-core</artifactId>
  <version>15.0</version>
</dependency>

For Gradle, include dependency below into your build.gradle

implementation 'org.openjdk.nashorn:nashorn-core:15.0'

Unfortunately, Standalone Nashorn is only usable as a JPMS module. So you might need to follow the solution stated in https://stackoverflow.com/a/46289257 to make it work with a non-modular application.

From the given class xxxxx.yyyy.service.JavaScriptServiceImpl and based on feedback from @JornVernee and @AttilaSzegedi, the command line should look like

jdk-15.0.1/bin/java -classpath /home/nashorn-helloworld/target/classes --module-path /home/org/openjdk/nashorn/nashorn-core/15.0:/home/org/ow2/asm/asm/7.3.1:/home/org/ow2/asm/asm-analysis/7.3.1:/home/org/ow2/asm/asm-commons/7.3.1:/home/org/ow2/asm/asm-tree/7.3.1/home/org/ow2/asm/asm-util/7.3.1 --add-modules org.openjdk.nashorn xxxxx.yyyy.service.JavaScriptServiceImpl



回答2:


Nashorn maintainer here.

It indeed seems to be an issue with Spring Boot not loading Nashorn as a JPMS module. Nashorn exports itself as a scripting engine to be found by the javax.script.ScriptEngineManager through a "provides" entry in its module-info.java. It does not use the older, non-modular export mechanism of declaring itself through a relevant META-INF/services/… entry in its JAR file. This means that if the JAR is not loaded as a JPMS module, script engine manager will not discover it. (NB: even if it redundantly had that META-INF/services entry, it wouldn't help because Nashorn relies on being loaded as a module; as code that used to ship with JDK, it has been a module since Java 9… it'd be somewhat hard to undo that now.)

I created a small test application that confirms this is the case. I'm trying to enlist some people who work on Boot to help me get to the bottom of this. It's complicated by the fact that Boot creates a fat JAR file and packages all of its dependencies into it and then manages their loading, so it's not like you can "just" modify the modulepath yourself on startup.

Hopefully there's a way to tell Boot to load a dependency as a module; my attempts to find it through Google haven't proved fruitful so far.




回答3:


I just released Nashorn 15.1 which makes it possible for Nashorn to function when loaded through classpath instead of through modulepath. I tested it with a small Spring Boot application of my own, and it works.



来源:https://stackoverflow.com/questions/65265629/how-to-use-nashorn-in-java-15-and-later

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!