3. Why JavaScript on Java
Want to use the powerful library and toolset available
in Java from JavaScript
Want rapid prototyping with JavaScript
Integrate business processes using JavaScript
(Set up a process flow with JavaScript)
Want to develop a combination of services using JavaScript.
JavaScript is one of the most common languages in
the world
4. What is JavaScript support
JSR 223: Scripting for the Java Platform
JavaScript code could access to Java object
Java program could execute JavaScript code
JDK bundles JavaScript engine
Enable to use the familiar Java API in JavaScript program
Securely execute JavaScript without breaking the Java sandbox
(known as javax.script API)
5. History of Supporting JavaScript
20181997 2006 2017
Nashorn supported ECMAScript 6
JDK 9 released
Contained Nashorn based on
ECMAScript 5.1
JDK 8 released
Supported javax.script API
Contained Rhino
JDK 6 released
Nashorn was duplicated
JDK 11 released
Developed by Netscape / Mozilla
Rhino was born
20142011
Nashorn was announced
6. History of Supporting JavaScript
20181997 2006 2017
Nashorn supported ECMAScript 6
JDK 9 released
Contained Nashorn based on
ECMAScript 5.1
JDK 8 released
Supported javax.script API
Contained Rhino
JDK 6 released
Nashorn was duplicated
JDK 11 released
Developed by Netscape / Mozilla
Rhino was born
20142011
Nashorn was announced
7. Rhino
JavaScript Engine written in Java
Developed by Mozilla Foundation
JDK 6/7 contains Rhino as a default JavaScript Engine
JDK also contains jrunscript command
Support javax.script API
8. History of Supporting JavaScript
20181997 2006 2017
Nashorn supported ECMAScript 6
JDK 9 released
Contained Nashorn based on
ECMAScript 5.1
JDK 8 released
Supported javax.script API
Contained Rhino
JDK 6 released
Nashorn was duplicated
JDK 11 released
Developed by Netscape / Mozilla
Rhino was born
20142011
Nashorn was announced
9. Nashorn
JavaScript Engine based on JSR 292 and invokeDynamic
JDK 8+ contains Nashorn as a default JavaScript Engine
Implementation of ECMAScript 5.1/6
jrunscript command was replaced by jjs command
Support javax.script API
10. Java → JavaScript
public class Main {
public static void main(String[] args) {
ScriptEngine scriptEngine =
new ScriptEngineManager().getEngineByName("nashorn");
try {
scriptEngine.eval(" function sum(a, b) { return a + b }");
int v = (Integer)scriptEngine.eval("sum(21, 22)");
System.out.println(v);
} catch (ScriptException e) {
e.printStackTrace();
}
}
}
11. JavaScript → Java
var now = java.time.LocalDateTime.now();
print("now = " + now);
print("1 day later = " + now.plusDays(1));
print("Truncated To Hours = " +
now.truncatedTo(java.time.temporal.ChronoUnit.HOURS));
13. JEP 335: Deprecate the Nashorn JavaScript Engine
Target version: JDK 11
It means this module will be removed in a future release
(still alive in JDK 13)
Annotated with @Deprecated(forRemoval=true)
Contains the jdk.nashorn.api.scripting and jdk.nashorn.api.tree
packages
jdk.scripting.nashorn module
Contains the jjs tool
jdk.scripting.nashorn.shell module
It doesn’t affect the javax.script API
16. GraalVM JavaScript
GraalVM includes an JavaScript engine
Provide js command as a commandline interpreter
Compatible to ECMAScript 2019
Support javax.script API
Fully support Node.js
Implemented using Truffle framework
Also support script mode and REPL mode
17. Java → JavaScript
import org.graalvm.polyglot.*;
public class Main {
public static void main(String[] args) {
try(Engine engine = Engine.create()) {
Source source = Source.create(
"js",
"function sum(a, b) { return a + b }");
Source source2 = Source.create("js", "sum(21, 22)");
try (Context context = Context.newBuilder().engine(engine).build())
{
context.eval(source);
int v = context.eval(source2).asInt();
System.out.println(v);
}
}
}
}
(with polyglot API)
18. Java → JavaScript
import com.oracle.truffle.js.scriptengine.GraalJSScriptEngine;
public class Main {
public static void main(String[] args) {
ScriptEngine scriptEngine =
new ScriptEngineManager().getEngineByName("graal.js");
assert scriptEngine instanceof GraalJSScriptEngine;
try {
scriptEngine.eval("function sum(a, b) { return a + b }");
int v = (Integer) scriptEngine.eval("sum(21, 22)");
System.out.println(v);
} catch (ScriptException e) {
e.printStackTrace();
}
}
}
(with javax.script API)
When use enable Nashorn compatibility mode,
start Java with -Dpolyglot.js.nashorn-
compat=true
19. JavaScript → Java
var now = java.time.LocalDateTime.now();
print("now = " + now);
print("1 day later = " + now.plusDays(1));
print("Truncated To Hours = " +
now.truncatedTo(java.time.temporal.ChronoUnit.HOURS));
$ js --jvm javadate.js
Java classes are only available when the engine started with --jvm
flag.
23. Compatibility with Nashorn
• Conditional catch clauses
• Function expression closures
• For-each expressions
• Anonymous class-like syntax for new expression
• Anonymous function statements
• Multi-line string literal (like Unix shell’s here-doc)
• Expressions inside string literals with ${expression}
• Back-quote exec expressions
• Shell script style hash comments
Nashorn has some syntax extensions.
$ js --js.syntax-extensions --experimental-options A_SCRIPT
We can use these extensions with --js.syntax-extensions flag
in GraalJS
-scripting mode
only
24. Compatibility with Nashorn Syntax Extensions
Sample: Function expression closures
$ js closure.js
SyntaxError: closure.js:1:16 Expected { but found x
function sqr(x) x*x;
^
$ js --js.syntax-extensions --experimental-options closure.js
4
function sqr(x) x*x
print(sqr(2));
25. Compatibility with Nashorn Syntax Extensions
load("nashorn:mozilla_compat.js");
importPackage("java.time");
var now = LocalDateTime.now();
print("now = " + now);
print("1 day later = " + now.plusDays(1));
importPackage("java.time.temporal");
print("Truncated To Hours = " +
now.truncatedTo(ChronoUnit.HOURS));
$ js --jvm --js.nashorn-compat --experimental-options
javadate_import.js
Some functions require --js.nashorn-compat flag to be set.
26. Compatibility with Nashorn -scripting mode
Sample: Expressions inside string literals with ${expression}
$ js string.js
Hello, ${x}
$ js --js.scripting --js.syntax-extensions --experimental-options
string.js
Hello, World
var x = "World"
var str = "Hello, ${x}"
print(str)
This Nashorn extension requires -scripting mode.
In this case, we have to put --js.scripting flag on GraalJS.
27. Compatibility of Java Object
Java global property is also available on GraalJS with --jvm mode
Nashorn GraalVM
Java.type ◯ ◯
Java.from ◯ ◯
Java.to ◯ ◯
Java.extend ◯ ◯
Java.super ◯ ◯
Java.synchronized ◯ ◯
Java.asJSONComparible ◯ ×
Java.isJavaObject ◯ ◯
Java.isType ◯ ◯
Java.typeName ◯ ◯
Java.isJavaFunction ◯ ◯
Java.isScriptObject ◯ ◯
Java.isScriptFunction ◯ ◯
Java.addToClasspath × ◯
28. Compatibility of Java List Element Access
java.util.List elements can be access as array elements on Nashorn
var ArrayList = Java.type("java.util.ArrayList")
var list = new ArrayList()
list.add("Rhino")
list.add("Nashorn")
list.add("GraalJS")
// get by List's get(int) method
print(list.get(0))
print(list.get(1))
print(list.get(2))
// get via indexe access syntax
print(list[0])
print(list[1])
print(list[2])
// prints list.size()
print(list.length); // prints list.size()
29. Compatibility of Java List Element Access
$ jjs List.js
Rhino
Nashorn
GraalJS
Rhino
Nashorn
GraalJS
3
$ js --jvm --js.nashorn-compat --experimental-options List.js
Rhino
Nashorn
GraalJS
Rhino
Nashorn
GraalJS
3
Nashorn: OK
GraalVM JavaScript: OK
30. Compatibility of Java Map Element Access
var HashMap = Java.type("java.util.HashMap")
var map = new HashMap()
// map key-value access by get/put method
map.put('js', 'GraalJS')
print(map.get('js'))
// access keys as properties
print(map['js'])
print(map.js)
// assign new key-value pair as 'property-value'
map['language'] = 'java'
print(map.get("language"))
print(map.language)
print(map['language'])
java.util.Map element can be access as property access with keys
31. Compatibility of Java List Element Access
$ jjs Map.js
GraalJS
GraalJS
GraalJS
java
java
java
$ js --jvm --js.nashorn-compat --experimental-options Map.js
GraalJS
undefined
undefined
null
undefined
undefined
Nashorn: OK
GraalVM JavaScript: NG
32. Conclusion
Nashorn is already deprecated from JDK 11
GraalVM JavaScript is the best choice as the next
JavaScript engine with Java
GraalVM JavaScript has highly compatibility with Nashorn
Must to check the dependency on Nashorn original
extensions
GraalVM JavaScript performance is good
Editor's Notes
Nín hǎo. (你好)
Wǒ jiào shān shān guì zhān. (我叫杉山貴章)
I studied Chinese when I was a collage student.
But I’m sorry, I remember just this two-sentence.
My name is Takaaki Sugiyama.
I am a board member of the Japan Java User Group.
Usually, I’m developing full managed systems for some customers in Japan. Java (Of course), JavaScript, Python, so on.
In our systems, we combine several languages as good.
So, my talk theme is JavaScript support on Java.
This is the agenda.
Why is JavaScript support is important for Java systems?
Because JavaScript is one of the most common programming languages all over the world.
It means that there are a lot of developer who have much experience and know-how.
As a JavaScript programmer, we want to use powerful Java libraries.
As a Java programmer, sometimes, JavaScript may be better for rapid development.
To be honest, we want to choose the best of both languages. (As like cherry-picking.)
What means JavaScript support on Java?
There is a standard specification in JCP about script language support.
It's known as javax.script API.
It is a member of Java SE from Java 6.
The targets of this JSR are not only JavaScript. But actually, the main target is JavaScript.
With this JSR, we can access Java objects from JavaScript code.
And also execute JavaScript code in Java program.
In addition, JDK bundles a default JavaScript engine.
This is the history of JavaScript supporting on standard Java platform.
JDK’s JavaScript support started from JDK 6.
It contains javax.script API and bundles Rhino JavaScript Engine.
Rhino was a Java based JavaScript engine developed by Mozilla Foundation.
Rhino provided supporting javax.script API and jrunscript command.
On JDK 8, Rhino replaced by Nashorn.
Nashorn is another JavaScript engine based on invokeDynamic JVM method invocation.
In addition, Nashorn implements ECMAScript 5.1 and 6.
jrunscript command was replaced by jjs command based on Nashorn.
This is an example that executes JavaScript code in the Java program using javax.script API.
ScriptEngine and ScriptEngineManager are provided by javax.script API.
But the concrete classes are provided by Nashorn.
This is an example that uses Java classes on the JavaScript code.
This is another example that has the same behavior.
Nashorn has some extensions for interop with Java.
Nashorn is a powerful and useful tool.
However, there is a sad news.
OpenJDK team decided to deprecate Nashorn on JDK 11.
Actually, there are two target modules.
They contain the implementation of javax.script API and jjs command-line tool.
The important thing, this deprecation doesn't affect the javax.script API itself.
We can continue to use this API.
However, we must choose the alternative JavaScript engine.
The best alternative is GraalVM JavaScript.
It's well known as GraalJS.
GraalVM is a polyglot virtual machine developed by Oracle.
It supports several languages include JavaScript.
GraalVM includes an JavaScript Engine as default.
It is compatible to recent ECMAScript.
And also support javax.script API.
And provide a commandline interpreter named ”js”.
In addition, GraalJS has fully support Node.js.
This is an example that executes JavaScript code in the Java program using GraalVM’s polyglot API.
It is different from javax.script API.
The Engine class, Source class, and Context class are provided by the polyglot API.
You can also use javax.script API.
In this case, specify “graal.js” as the engine name.
This mode is supported for just backward compatibility.
So, polyglot API should be preferred whenever possible.
Because the type of result is clearer than javax.script API.
This is an example that uses Java classes on JavaScript code.
If you want to use Java classes, --jvm flag is neccessary when starting the engine.
I will talk about the compatibility of GraalVM JavaScript.
This is the rate of compatibility with ECMAScript 6.
GraalVM covers 98% of the basic feature.
Nashorn for JDK 10 covers only 28%.
Regarding more recent ECMAScript, GraalVM covers 97% feature.
It is better than major browser except for Google Chrome.
Of course, we have to care about compatibility with Nashorn for migration.
Nashorn has some useful syntax extensions. Like this.
We can still use these extensions with –js.stntax-extensions flag in GraalJS.
But this mode is an experimental feature, so –experimental-options flag also needs with this.
This is an example of using a Nashorn syntax extension.
Without this flag, the interpreter throws a syntax error.
This is another example.
Some functions require a Nashorn-compat mode flag.
This example shows a Nashorn extension with -scripting mode.
For Nashorn scripting mode, you have to put –js.scripting flag on GraalJS.
Nashorn provides "Java" global property for interrop with Java and JavaScript objects.
GraalVM also provides same property. But it is little bit different from Nashorn’s one. Like this.
Nashorn has a syntax sugar for List element access.
We can access List elements as array elements.
GraalJS also provides this syntax sugar.
Nashorn has similer syntax sugar for Map elements sccess.
However, GraalJS doesn’t support it, yet.
Conclusion.
We have to migrate to altenative JavaScript Engine from Nashorn.
GraalJS is very good.
However, you must check the compatibility carefully.
Especially, you are using some Nashorn original extensions. Because the compatibility is not perfect.