Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use Nashorn in Java 15 and later?

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?

like image 276
Aswath Murugan Avatar asked Dec 12 '20 13:12

Aswath Murugan


People also ask

What can I use instead of Nashorn?

The Nashorn engine has been deprecated in JDK 11 as part of JEP 335 and and has been removed from JDK15 as part of JEP 372. GraalVM can step in as a replacement for JavaScript code previously executed on the Nashorn engine. GraalVM provides all the features for JavaScript previously provided by Nashorn.

Why is Nashorn deprecated?

With the release of Java 11, Nashorn was deprecated citing challenges to maintenance, and has been removed from JDK 15 onwards. Nashorn development continues on GitHub as a standalone OpenJDK project and the separate release can be used in Java project from Java 11 and up.

What is the use of Nashorn in Java?

Java Nashorn. Nashorn is a JavaScript engine. It is used to execute JavaScript code dynamically at JVM (Java Virtual Machine). Java provides a command-line tool jjs which is used to execute JavaScript code. You can execute JavaScript code by using jjs command-line tool and by embedding into Java source code.

What programming language is Nashorn written in?

It was fully developed in the Java language as part of the Nashorn Project. The code is based on the new features of the Da Vinci Machine, which is the reference implementation of Java Specification Request (JSR) 292: Supporting Dynamically Typed Languages on the Java Platform. The Nashorn engine is included in the Java SE Development Kit (JDK).

Is Nashorn compatible with GraalVM JavaScript?

To learn more, please read Migration Guide from Nashorn to GraalVM JavaScript. This series of articles introduces Nashorn, a blazing fast JavaScript runtime engine that shipped with Java SE 8 to provide a lightweight environment for extending, supplementing, and often even replacing Java code.

What is Nashorn and why should I Care?

This series of articles introduces Nashorn, a blazing fast JavaScript runtime engine that shipped with Java SE 8 to provide a lightweight environment for extending, supplementing, and often even replacing Java code.


2 Answers

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
like image 163
MK Tan Avatar answered Oct 25 '22 13:10

MK Tan


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.

like image 20
Attila Szegedi Avatar answered Oct 25 '22 13:10

Attila Szegedi