An earlier post showed how to run JavaScript using the GraalJS engine and optimize it for performance. Now, let’s see how to run Javascript using Nashorn. This helps maintain existing Java applications that use it and migrate to GraalJS if needed.
If your application runs on Java 11 or earlier, Nashorn comes as part of it and uses the package names jdk.nashorn and jdk.scripting.nashorn.
Nashorn standalone can be used in Java version 14 and above in which the package name changes to org.openjdk.nashorn. Let’s see how you can use Nashorn standalone and execute Javascript now.
Adding Nashorn as dependency for your project
Add the following dependency in your pom.xml, if you use Maven as your build tool. Do the equivalent if you use Gradle or any other build tool.
<dependency>
<groupId>org.openjdk.nashorn</groupId>
<artifactId>nashorn-core</artifactId>
<version>${nashorn.version}</version>
</dependency>
${nashorn.version} is a property pointing to Nashorn version we use – for example – 15.4
Sample Code
Here is a simple Java code showing how we can run Javascript snippet that adds two integers.
// import javax.script.ScriptEngine;
// import javax.script.ScriptEngineManager;
ScriptEngineManager factory = new ScriptEngineManager();
ScriptEngine engine = factory.getEngineByName("nashorn");
int a = 10;
int b = 10;
int c;
engine.put ("a", a);
engine.put ("b", b);
c = engine.eval ("var c = a + b; c");
System.out.println(String.format("%d + %d = %d", a, b, c));
Line 5 – ScriptEngineManager defined by JSR-223. Factory class from which users can obtain an instance of ScriptEngine.
Line 7 – Using the literal “nashorn” to obtain the ScriptEngine instance. In older versions of Java that had Nashorn in-built, using the literal “js” would also work.
Line 15 – Running the simple script for adding 2 integers.
Security, Performance
Access to Java classes can be controlled using NashornScriptEngineFactory and our implementation of ClassFilter interface. See the example below.
// import javax.script.ScriptEngine;
// import org.openjdk.nashorn.api.scripting.NashornScriptEngineFactory;
class CustomClassFilter implements ClassFilter {
@Override
public boolean exposeToScripts(String s) {
if (s.compareTo("java.io.File") == 0) {
return false;
}
return true;
}
}
NashornScriptEngineFactory factory = new NashornScriptEngineFactory ();
ScriptEngine engine = factory.getScriptEngine(new CustomClassFilter());
int a = 10;
int b = 10;
int c;
engine.put ("a", a);
engine.put ("b", b);
c = engine.eval ("var c = a + b; c");
System.out.println(String.format("%d + %d = %d", a, b, c));
Unlike Graal Polyglot Context, a single instance of ScriptEngine can be used in multiple threads provided the Javascript doesn’t use the ‘global’ scope. Though there is no new object creation needed per thread in Nashorn, GraalJS is performing better than Nashorn.
Stay tuned for the performance comparison results of Nashorn vs GraalJS.