Nashorn is the official JavaScript Engine in the Java Virtual Machine since Version 8. It supports and implements the ECMAScript 5.1 specification and competes among others directly with Google V8 (the script engine behind Node.js). Nashorn compiles JavaScript to Java Bytecode during runtime and thus provides high interoperability of Java and JavaScript.

Nashorn

In this script I want to dig into some of the (IMO) most used options, functions, features, and use-cases. After working through this tutorial you’ll be able to use Nashorn and its dynamic scripting features in your daily Java business.

Another good starting point for Nashorn resources might be the Official Project Nashorn Website with links to the mailing-list, the blog and the wiki pages. Check it out!

Nashorn in JDK 8 implements, as mentioned above, the ECMAScript 5.1 specification. But it’s Nashorn’s strategy to follow the ECMAScript spec. So the follow up major releases of Nashorn will implement ECMAScript 2015 spec.

1. Nashorn at the Command Line Interface (CLI)

Nashorn comes with a command line client named jjs.

This client is located in $JAVA_HOME/bin, but there’s no shortcut/link/path integration after installation of Java 8. So, if you want to work with jjs - and that’s what we want to do here - you should create a link to the tool:

$ cd /usr/bin
$ ln -s $JAVA_HOME/bin/jjs jjs
$ jjs
jjs> print('Hello World');

You can now evaluate JavaScript code directly in the jjs shell.

jjs> var x = 10;
jjs> print(x);
10

Additionally you can load and execute JavaScript files with the jjs tool:

test.js
var x = 10;
var y = 20;
print(x + y);
$ jjs test.js
30

Exiting

The jjs client can be exited by calling

jjs> exit()  // regular exit
jjs> exit(1) // exit with an exit-code

jjs> quit()  // regular exit
jjs> quit(1) // exit with an exit-code

Help / Options

List all options of jjs by calling it with the -help option:

$ jjs -help

1.1. Scripting mode

In addition to the ECMAScript 5.1 specification, Nashorn implements a number of its own syntax and API extensions as well (see one of the next chapters). Many of these extensions are only available in scripting mode. Scripting mode is turned on by using the cli option --scripting:

$ jjs --scripting

In scripting mode, Nashorn accepts shell style # single line comments:

test.js
# style line comment -scripting mode
# prints hello

print('hello');

1.2. Shebang

Nashorn supports shebang scripting. So, instead of calling your JavaScript file like the traditional way:

test.js
print('hello');
$ jjs test.js

Just write your JavaScript file like the following with a shebang at first line:

test.js
#!/usr/bin/jjs
print('hello');

make it executable and call it from the command line, like any other shell script:

$ chmod 755 test.js
$ ./test.js
You’ll need to have a link to jjs as mentioned at the beginning of this chapter.
Scripting mode is automatically enabled when running shebang Nashorn scripts.

2. Nashorn JavaScript Engine from within Java

The Nashorn Engine is a JavaScript implementation of the JSR-223 (Scripting for the Java Platform). It implements the javax.script API. So, for being able to evaluate JavaScript code from Java, we just create a new Nashorn javax.script.ScriptEngine.

ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");(1)
engine.eval("print('Hello World');");
1 The Nashorn engine names you can use here are "nashorn", "javascript" and "js".

As seen above, JavaScript code can be evaluated directly by passing it as a string to the eval() method of the engine object. Alternatively you can parse (and evaluate) a .js-file by passing a FileReader object pointing to your file:

ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
engine.eval(new FileReader("test.js"));

2.1. Invoking JavaScript functions from Java

It’s not only possible to run single JS statements or evaluate complete JS files, but it’s also possible to invoke JavaScript functions from within Java code. Additionally you can pass Java objects as function arguments and return data back from the function to the calling Java method.

Let’s assume our JavaScript file:

example.js
var sayHello = function(name) {
  print('Hello, ' + name + '!');
  return 'hello from javascript';
};

To be able to call our defined sayHello function, we first have to cast the engine object to the Invocable interface, which is implemented by the NashornScriptEngine implementation. The Invocable interface provides the invokeFunktion() method, which allows to call JavaScript functions for a given name and pass arguments:

ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
engine.eval(new FileReader("example.js"));

// cast the script engine to an invocable instance
Invocable invocable = (Invocable) engine;

Object result = invocable.invokeFunction("sayHello", "John Doe");
System.out.println(result);
System.out.println(result.getClass());

// Hello, John Doe!
// hello from javascript
// class java.lang.String

Our code prints three lines to the console: The JavaScript function print() pipes the result to System.out, afterwards, the two Java System.out.println() methods are evaluated.

2.2. Invoking Java methods from JavaScript

Calling or invoking Java methods from JavaScript code is just as easy as vice-versa. Let’s assume a Java class with two methods:

MyJavaClass.java
package my.package;

public class MyJavaClass {

    public static String sayHello(String name) {
        return String.format("Hello %s from Java!", name);
    }

    public int add(int a, int b) {
        return a + b;
    }

}

Our Java class can be referenced from JavaScript via the Java.type API extension. This is similar to the import statement in Java. After referencing our Java class, we can call the static method and print the result to System.out. Since the sayHello() method is static, we don’t have to create an instance as we have to do for calling the add() method.

var MyJavaClass = Java.type('my.package.MyJavaClass');

// call the static method
var greetingResult = MyJavaClass.sayHello('John Doe');
print(greetingResult);

// create a new intance of MyJavaClass
var myClass = new MyJavaClass();
var calcResult = myClass.add(1, 2);
print(calcResult);

// Hello John Doe from Java!
// 3

2.2.1. Nashorn type conversions

With this little example, you can find out how Nashorn handles type conversions between Java and JavaScript, when calling Java methods from JavaScript.

public static void printType(Object object) {
    System.out.println(object.getClass());
}

Now, call this static method with different JavaScript types:

MyJavaClass.printType('Hello');
// class java.lang.String

MyJavaClass.printType(123);
// class java.lang.Integer

MyJavaClass.printType(12.34);
// class java.lang.Double

MyJavaClass.printType(true);
// class java.lang.Boolean

MyJavaClass.printType(new Number(123));
// class jdk.nashorn.internal.objects.NativeNumber
// class jdk.nashorn.api.scripting.ScriptObjectMirror

MyJavaClass.printType(new Date());
// class jdk.nashorn.internal.objects.NativeDate
// class jdk.nashorn.api.scripting.ScriptObjectMirror

MyJavaClass.printType(new RegExp());
// class jdk.nashorn.internal.objects.NativeRegExp
// class jdk.nashorn.api.scripting.ScriptObjectMirror

MyJavaClass.printType({foo: 'bar'});
// class jdk.nashorn.internal.scripts.J04
// class jdk.nashorn.api.scripting.ScriptObjectMirror
  • Primitive JavaScript types are converted to the appropriate Java wrapper class.

  • Native JavaScript objects are represented by internal adapter classes, respectively to ScriptObjectMirror.

Don’t rely on programming against / using internal classes in jdk.nashorn.internal as they are likely subject to change!

2.3. ScriptObjectMirror

The ScriptObjectMirror is part of the jdk.nashorn.api and is intended to be used in client-code instead of the internal classes. This mirror object is a representation of the underlying JavaScript object and provides access to it and its methods and properties. The ScriptObjectMirror implements the Map interface.

We edit our last method slightly to

public static void printObjectMirror(ScriptObjectMirror mirror) {
    System.out.println(mirror.getClassName() + ": " + Arrays.toString(mirror.getOwnKeys(true)));
}

When we call this method now with our last four JS function calls (number, date, regexp and object literal):

MyJavaClass.printType(new Number(123));
MyJavaClass.printType(new Date());
MyJavaClass.printType(new RegExp());
MyJavaClass.printType({
    foo: 'bar',
    bar: 'foo'
});

we now get this result:

Number: []
Date: []
RegExp: [lastIndex, source, global, ignoreCase, multiline]
Object: [foo, bar]

Also, we can call member functions on JavaScript objects from Java.
Let’s assume a JavaScript type Person with some properties and a function getFullName().

function Person(firstName, lastName) {
  this.firstName = firstName;
  this.lastName = lastName;
  this.getFullName = function() {
    return this.firstName + ' ' + this.lastName;
  }
}

The function getFullName() can be called on ScriptObjectMirror via callMember():

public static void getFullName(ScriptObjectMirror person) {
    System.out.println("Full name is: " + person.callMember("getFullName"));
}

Now, our JavaScript code looks like this:

var person = new Person('John', 'Doe');
MyJavaClass.getFullName(person);

// Full name is: John Doe

2.4. Options for the script engine

Nashorn script engine customization can be done by using nashorn.args system properties. Just specify the options you want with -Dnashorn.args=…​ E.g. enabling the scripting mode:

$ java -Dnashorn.args=-scripting MyJavaClass

You can also create a Nashorn engine by passing customization options programmatically. In this case, you’ll have to instantiate NashornScriptEngineFactory directly:

NashornScriptEngineFactory factory = new NashornScriptEngineFactory();
ScriptEngine engine = factory.getScriptEngine(new String[] { "-scripting" });
Available options can be determined from the command line when calling jjs -help.

2.5. Bindings / Context

A ScriptContext contains one or more bindings, each associated to a scope. By default, there are two scopes:

  • ENGINE_SCOPE

  • GLOBAL_SCOPE

When a Nashorn engine is created, it creates a default context:

ScriptContext defaultContext = engine.getContext();

The default context’s ENGINE_SCOPE is the scope where ECMAScript "global" objects and functions (Object, Function, Math, RegExp, parseInt, etc.) are stored. The GLOBAL_SCOPE is shared between all engines created by the same ScriptEngineManager.

You can store variables in the context (use of the scope is optional, default is ENGINE_SCOPE):

ScriptContext context = engine.getContext();
// stores an object under the key `myKey` in the (engine scoped) context
context.setAttribute("myKey", object, ScriptContext.ENGINE_SCOPE);
// retrieves the object with key `myKey` from (engine scoped) context
context.getAttribute("myKey", ScriptContext.ENGINE_SCOPE);

Bindings b = context.getBindings(ScriptContext.ENGINE_SCOPE);
b.get("Object");    // gets ECMAScript "Object" constructor
b.get("undefined"); // ECMAScript 'undefined' value

If a variable is not found in ENGINE_SCOPE, GLOBAL_SCOPE bindings are being searched.

There’s a confusion due to ECMAScript "global" properties being in ENGINE_SCOPE (top-level "this" in script) and not in GLOBAL_SCOPE.

3. API and Language Extensions

Nashorn comes along with quite a few language and API extensions, in addition to the ECMAScript standard. Most of the API extensions exist due to backward compatibility to Rhino.

Let’s have a look at some of the IMHO most useful and interesting ones.

3.1. Print Function

Nashorn comes with a handy print function, which prints its arguments (after converting it to a string) to standard out (stdout):

print("Hello", "World");
// Hello World
echo() is an equivalent to the print() function.
Nashorn does not have a console object, where browsers do logging!

3.2. Reading Stdin

If you want to read from the stdin, there’s the readLine() function:

jjs> var name = readLine("What is your name? ")
What is your name? John
jjs> print("Hello, ${name}!")
Hello, John!

3.3. Reading Files

If stdin is just not enough, you can use readFully() to read complete file contents into a variable:

var content = readFully('text.txt');

3.4. String Interpolation

You can specify expressions inside string literals with the ${expression} syntax. The string value is computed by substituting the name of the ${expr} expression with the value of the corresponding variable.

var name = "World";
var str = "Hello, ${name}!";
print(str);
// Hello, World!

3.5. Back-quote exec expressions

Nashorn supports Unix shell like back quote strings. Back quoted strings are evaluated by executing the programs mentioned in the string and returning value produced by the 'exec'-ed program.

var files = `ls -l`;  // get file listing as a string
var lines = files.split("\n");
for (var l in lines) {
    var line = lines[l];
    print(line);
}
Don’t mix this up with the new back quote string templates in ES6, they are similar to String interpolation mentioned above!

3.6. Java Beans

With Nashorn, you get direct access to the properties of a Java bean, no need to use getters and setters any more:

var Date = Java.type('java.util.Date');
var date = new Date();
date.year += 1900; // -> no setter!
print(date.year);  // -> no getter!
// 2016

3.7. Function Literals

For simple, one-line functions, we don’t necessarily have to use curly braces (and can also omit the return keyword):

function add(a, b) a + b;

print(add(1, 2));  // 3

3.8. Binding Properties

You can bind properties from one object to another object:

var o1 = {};
var o2 = { foo: 'bar' };

Object.bindProperties(o1, o2);

print(o1.foo);    // bar
o1.foo = 'John';
print(o2.foo);    // John

3.9. Trimming Strings

Additionally to .trim(), you can just trim your string object on the left or the right:

print("   bar".trimLeft());           // bar
print("foo   ".trimRight() + "bar");  // foobar

3.10. Whereis

In case you get lost while programming:

print(__FILE__, __LINE__, __DIR__);

3.11. Import Scopes

Sometimes it’s useful to import many Java packages at once. We can use the class JavaImporter to be used in conjunction with the with statement. All class files from the imported packages are accessible within the local scope of the with statement:

var imports = new JavaImporter(java.io, java.lang);
with (imports) {
    var file = new File(__FILE__);
    System.out.println(file.getAbsolutePath());  // /path/to/my/script.js
}

3.12. Packages

Packages and related objects are there to support Java package, class access from script. The properties of the Packages variable are all the top-level Java packages, such as java, javax etc.

var Vector = Packages.java.util.Vector;

// but short-cuts defined for important package prefixes like
//    Packages.java, Packages.javax, Packages.com
//    Packages.edu, Packages.javafx, Packages.org

var JFrame = javax.swing.JFrame;  // javax == Packages.javax
var List = java.util.List;        // java == Packages.java

Let’s test it in jjs:

jjs> Packages.java
[JavaPackage java]
jjs> java
[JavaPackage java]
jjs> java.util.Vector
[JavaClass java.util.Vector]
jjs> javax
[JavaPackage javax]
jjs> javax.swing.JFrame
[JavaClass javax.swing.JFrame]

3.13. Typed Arrays

Native JavaScript arrays are untyped. Nashorn implements typed arrays as specified at https://www.khronos.org/registry/typedarray/specs/latest/.

For example, create an array of `int`s:

var IntArray = Java.type('int[]');

var array = new IntArray(3);
array[0] = 3;
array[1] = 2;
array[2] = 1;

try {
    array[3] = 0;  // would be possible in pure JS
} catch (e) {
    print(e.message);  // Array index out of range: 3
}

array[0] = '42';
print(array[0]);  // 42

array[0] = 'some wrong type';
print(array[0]);  // 0

array[0] = '3.14';
print(array[0]);  // 3

Our int[] array behaves like a real Java int array. Additionally, Nashorn performs implicit type conversion when trying to add some non-integer values. Strings will automatically be converted to int, if possible.

3.14. Collections and For-Each

Array handling in JavaScript is sometimes annoying. Let’s use Java collections instead!
(BTW: this has become much better with ES6)

var ArrayList = Java.type('java.util.ArrayList');
var myList = new ArrayList();
myList.add('John');
myList.add('Jack');
myList.add('Joe');

for each (var e in list) print(e);  // John, Jack, Joe

Nashorn’s for each statement works like the foreach in Java.

Or, let’s use a HashMap:

var map = new java.util.HashMap();
map.put('foo', 'red');
map.put('bar', 'green');

for each (var e in map.keySet()) print(e);  // foo, bar

for each (var e in map.values()) print(e);  // red, green

3.15. Convert Arrays

Some packages like java.util (and java.lang) can be accessed directly without utilizing Java.type or JavaImporter:

var list = new java.util.ArrayList();
list.add('John');
list.add('Jack');
list.add('Joe');

This code converts the Java list to a native JavaScript array:

var jsArray = Java.from(list);
print(jsArray);                                  // John,Jack,Joe
print(Object.prototype.toString.call(jsArray));  // [object Array]

And vice versa:

var javaArray = Java.to([1, 2, 3, 5, 8, 13], "int[]");

3.16. Lambdas and Streams

As Lambdas and Streams are available since Java 8, it’s also possible to work with them in Nashorn! \o/

Although ECMAScript 5.1 lacks the compact arrow syntax from the Java 8 lambda expressions, we can use function literals where ever lambda expressions are accepted.

var list = new java.util.ArrayList();
list.add('a1');
list.add('b1');
list.add('c1');
list.add('a3');
list.add('b3');
list.add('c3');
list.add('a2');
list.add('b2');
list.add('c2');

list
    .stream()
    .filter(function(entry) {
        return entry.startsWith('a');
    })
    .sorted()
    .forEach(function(entry) {
        print(entry);
    });
// a1, a2, a3
Where ever a Java 8 Lambda or SAM (single-abstract-method) type is required, an ECMAScript function can be passed as argument!

3.16.1. Every Lambda is a JavaScript Function

Any Java object that is an instance of lambda type can be treated like a script function.

var JFunction = Java.type('java.util.function.Function')

var obj = new JFunction() {
   apply: function(x) { print(x * x) }
}

print(typeof obj); // prints "function"

// 'calls' lambda as though it is a function
obj(23);

3.17. Extending Classes

Java types can simply be extended with the Java.extend extension.

var Runnable = Java.type('java.lang.Runnable');
var Printer = Java.extend(Runnable, {
    run: function() {
        print('printed from a separate thread');
    }
});

var Thread = Java.type('java.lang.Thread');
new Thread(new Printer()).start();

new Thread(function() {
    print('printed from another thread');
}).start();

// printed from a separate thread
// printed from another thread
As you can see, even multi-threaded code is possible in Nashorn.

3.18. Calling Super

Accessing overridden members in JavaScript is traditionally awkward because Java’s super keyword doesn’t exist in ECMAScript. Luckily Nashorn comes to the rescue.

First we define a super type in Java code:

class SuperRunner implements Runnable {
    @Override
    public void run() {
        System.out.println("super run");
    }
}

Next we override SuperRunner from JavaScript. Pay attention to the extended Nashorn syntax when creating a new Runner instance: The syntax of overriding members is borrowed from Java’s anonymous objects.

var SuperRunner = Java.type('my.package.SuperRunner');
var Runner = Java.extend(SuperRunner);

var runner = new Runner() {
    run: function() {
        Java.super(runner).run();
        print('local run');
    }
}
runner.run();

// super run
// local run

We call the overridden method SuperRunner.run() by utilizing the Java.super extension.

3.19. Loading Scripts

Loading and evaluating additional script files from Nashorn is quite easy with the load function. We can load local and external files.

In our example, we load the moment.js library to calculate some dates and times:

load('https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.11.1/moment.min.js');

var now = new moment();
print(now);
// Thu Dec 31 2015 23:59:59 GMT+0100

The (external) script will be evaluated in the same context, so we can access the moment function directly.

3.19.1. Load in new Global Context

Loading external files can break your own code, when it is using same variable names as your code! To avoid this, files can be loaded into a new global scope:

loadWithNewGlobal('script.js');

Of course, the script is then only available in the Nashorn global context (not current engine context).

3.20. Error Object

Nashorn extends the ECMAScript standard Error object with a few more interesting properties.

function func() {
    throw new Error();
}

function f() {
    func();
}

try {
    f();
} catch (e) {
    print(e.stack);
    print(e.lineNumber);
    print(e.columnNumber);
    print(e.fileName);

    // of course, also this is possible
    e.printStackTrace();
}

3.21. Scripting Mode Extension Objects

There are some global objects defined in Nashorn, when -scripting mode is enabled.

Most of them are self-explaining, so I provide just some source code examples:

3.21.1. $ARG

$ jjs -scripting -- arg1 arg2 arg3
jjs> $ARG
arg1,arg2,arg3
jjs> $ARG[1]
arg2
arguments
$ jjs -scripting -- arg1 arg2 arg3
jjs> arguments
arg1,arg2,arg3
jjs> arguments[1]
arg2

3.21.2. $ENV

// print $JAVA_HOME and $PATH from the OS shell
print($ENV["JAVA_HOME"])
print($ENV["PATH"])
print($ENV.JAVA_HOME)
print($ENV.PATH)

3.21.3. $EXEC

Launch processes to run commands.

jjs> $EXEC("ls -l")
total 0
drwxr-xr-x+ 1 johndoe staff 4096 Dec 31 12:34 dir
-rwxrw-r--  1 johndoe staff  168 Dec 31 13:37 file.txt

jjs> $EXEC("cat", "Send this to stdout")
Send this to stdout

3.21.4. $OUT

Store the latest standard output (stdout) of the process spawned by $EXEC.

// use curl to download JSON weather data from the net
var str = `curl http://api.openweathermap.org/data/2.5/weather?q=Hamburg,de&units=metric&appid=44db6a862fba0b067b1930da0d769e98`;

// parse JSON and print the current temperature
var weather = JSON.parse($OUT);
print(weather.main.temp);

3.21.5. $ERR

Store the latest standard error (stderr) of the process spawned by $EXEC.

3.21.6. $EXIT

Store the exit code of the process spawned by $EXEC.

3.21.7. $OPTIONS

This property exposes command line options, which are passed (explicitly or implicitly) to Nashorn "command line".

print("-scripting = " + $OPTIONS._scripting);         // -scripting = true
print("--compile-only = " + $OPTIONS._compile_only);  // --compile-only = false
print("-timezone = " + $OPTIONS._timezone.ID);        // -timezone = Europe/Berlin

An explicit description of all language and API extensions in Nashorn can be found at the Wiki page.

4. Working with Package Managers & Repositories

When working with Nashorn, you probably don’t want to develop every function from scratch. There are already libraries which provide the functionalities you need. Just like using a dependency lib from Maven, you can use libraries with Nashorn. And more than that, you can choose out of various repositories and package managers, as there is Java, JavaScript and the perfect symbiosis of both.

4.1. NPM

Node Package Manager - https://npmjs.org

  • NPM is the package manager of choice when working with JavaScript only, no matter if for browser only or also server-side with Node.js.

  • The NPM registry is a public collection of packages of open-source code.

  • NPM is also a command line client.

You can use packages from NPM within Nashorn! But…​

4.1.1. JVM-NPM

Most/many packages rely on CommonJS with the require() syntax (kind like an import in Java). As Nashorn is just a JavaScript engine, it unfortunately doesn’t have support for a package manager and/or a dependency loading mechanism.

Luckily there is a project called npm-jvm (a NPM compliant CommonJS module loader for the JVM), which brings the require() function to Nashorn. So it becomes possible to use packages which rely on CommonJS in Nashorn and also load other modules by using the require() function into your Nashorn script context.

Usage

Using the global load() function supplied by Nashorn to load jvm-npm.js into the global execution context. Then it’s possible to load any module with require():

nashorn> load('./jvm-npm.js');
nashorn> var x = require('some_module');

Alternatively there’s also a project called commonjs-modules-javax-script which should do similar things.

4.1.2. Polyfill.js

Many libraries registered in NPM, make use of the Node.js and/or the common browser APIs. As Nashorn isn’t Node.js nor a browser, we have to add some glue to make it work. This glue is called polyfill, to provide functions to an environment, where these functions aren’t available by default.

For most use cases, this nashorn-polyfill.js polyfill should work:

nashorn-polyfill.js
var global = this;(1)
var window = this;(2)
var process = {env:{}};(3)

var console = {};(4)
console.debug = print;
console.log = print;
console.warn = print;
console.error = print;
1 Node.js has a global variable, which we have to provide - it’s just the global context.
2 Browsers have a window variable, referring the global context, we have to provide it also.
3 Some packages make use of the process.env object of Node.js, as this is also not available, we just provide an empty object.
4 Nashorn doesn’t have a console and arbitrary log statements, so we assign the print function to the most used/common console output functions.

4.1.3. Native API access

Nashorn doesn’t have access to native language (C/C++) APIs. NPM packages using native APIs can’t be used in Nashorn.

There are discussions out in the wild, if it is possible to use Jython to run Python-based NPM packages inside the JVM, but I don’t know of any approach/project testing this.

4.2. Maven

When using Nashorn within a Java project, it’s obvious to use Maven as repository and package manager. This is possible without problems, but with a few plugins and helpers!

4.2.1. Maven and NPM, Grunt, Gulp, etc.

If you don’t want to work without the Node.js ecosystem, NPM and frontend build tools like Grunt, Gulp and Webpack, there’s a handy Maven plugin, which solves all your problems:

Please refer to the GitHub page to get a detailed description and documentation of this plugin!

4.2.2. WebJars

Many of the most popular and most used NPM packages are provided as WebJars. With WebJars, you can use NPM packages just as regular Maven dependencies in your project.

Example for using Moment.js as Maven dependency:

<dependency>
    <groupId>org.webjars.npm</groupId>
    <artifactId>moment</artifactId>
    <version>2.11.2</version>
</dependency>

If there is no WebJar of your favourite NPM package available, it’s easy to create one. There’s a detailed documentation on the website, on how to do it.

4.2.3. Nasven

Nasven.js is a server, desktop, and shell-script application runtime for apps written in Javascript possibly dependent on Maven artifacts.

Nasven = Nashorn + Maven. A tool to get Maven artifacts in scope for Nashorn script execution.

$ nasven package.json
nashorn full version 1.8.0_72-b15
[NASVEN] Building temporary Apache Maven project to find dependencies ...
[NASVEN] Done!
[NASVEN] About to run your nasven.js application under /Users/Niko/nasven/nasven-samples/camel/index.js ...

[NASVEN] Calling jjs for your application ...
Some examples

Nearly everything that I wrote about Maven is somehow available in similar ways/plugins for e.g. Gradle or any other popular build system. Just have a look around in the proper ecosystem!

5. Isomorphic JavaScript

5.1. What does Isomorphic mean, what can I do with it and why should I use it?

Isomorphic comes from the Greek "isos" for "equal" and "morph" for "shape". So, it’s about the same or equal shape of something.

Isomorphism describes that if you look at the same entity <1> in two different contexts <2>, you should get the same thing <3>.

1 code
2 client and server
3 result, html, DOM, etc.

In our case:

If we use the same code on client and server, we should get the same result/html.

Isomorphic

5.1.1. Isomorphic code

Isomorphic code supports you to code with the DRY principle (Don’t Repeat Yourself), as you can share the same logic on client and server side. You only have to develop your application logic once and maintain only one codebase. In cases of errors, there is only one single point of truth (or failure) to lookup for the fix. And last, but not least, isomorphic code leads you and your developers to be able to focus on a single technology, so you don’t have to be experts on multiple programming languages.

Example

Think of your perfect password validation function, which you developed in JavaScript for the usage in the browser.

function isPasswordValid(password) {
    var score = scorePasswordStrength(password);
    return score >= 3;
}

This works pretty well, but to prevent that users disable JavaScript in the browser and pass an invalid password to the server, you’ll have to develop the same logic again in the programming language used on the server, perhaps Java. This is additional effort, can lead to implementation errors, something may be forgotten in implementation, latest on maintenance. Why not re-use the above logic in your Java code?

public Boolean isPasswordValid(String password) {
    try {
        return (Boolean) nashorn.invokeFunction("isPasswordValid", password);
    } catch (ScriptException | NoSuchMethodException e) {
        throw new RuntimeException(e);
    }
}

5.1.2. SPAs

Most of modern Single Page Web Applications (SPA), only consist of just a html skeleton and one or more JavaScript libraries, which render the whole application UI and is responsible for all transitions, path routings, navigations and logic:

index.html
<html>
<head>
    <title>Awesome Website</title>
    <script src="./app-bundle.js"></script>
</head>
<body></body>
</html>

These applications are (mostly) awesome, but have some drawbacks:

Cons
  1. UX / Performance - The user doesn’t see anything before the whole script code is loaded, evaluated and executed on the client/browser.

    1. Long wait time, even on fast internet connections.

    2. Users will possibly go away (3sec. rule!).

    3. Think of slow internet connections!?

  2. Legacy Browsers (and there are still a lot out there!) can’t evaluate your fancy new JavaScript stuff.

  3. SEO - Search engines can’t index your website, because there is no content!

    1. Even if Google can now evaluate JavaScript on websites, it’s still error-prone, a mess and you can’t rely on proper evaluation!

So, perhaps it’s better to render the web pages on the server!?

Pros

But what about

  • UX - cool transition effects (which are required nowadays to be able to compete on the market!)

  • Performance - faster rendering of only parts/fragments of the entire page

  • Performance - only send the needed data over the wire, instead of the whole html page

These advantages can only be achieved by running the application and rendering the pages on the client!

Possible Solution
  1. User requests (first) URL

  2. Server fetches content for that URL

  3. Server renders content to a response

  4. User enjoys the content

  5. in the meantime, the client is initialized

  6. User nagivates to a different URL

  7. Client fetches content for that URL

  8. Client renders content to the DOM

So, every time a user makes an intial request to the app or an app path, the server should render the page and send it to the client. From that moment on, the client can take over control and proceed with rendering the content. This bridges the gap to initialize the client while the user can consume the initial server-side rendered page. Additionally, search engines get valid html with already rendered content if they want to index your site. And legacy browsers are also able to consume your site, if not only the client is able to render your pages.

5.2. React.js

React.js is a JavaScript library for building user interfaces, invented by Facebook. It’s not a full-stack client framework for building apps. In means of MVC or MVVM, React.js only reflects the V(iew) part.

React is component based and has a virtual DOM. With this virtual DOM and building diffs, it’s possible to have page/content transitions and updates without flickering. Additionally, React supports server-side rendering of templates.

5.2.1. Flux

For building full-stack apps with React, there’s an architecture approach, called Flux. This architecture is a straight-forward approach and relies on immutable entities and collections. The state of the application is stored in a so called Store, the store represents the data for rendering the templates. The store may only be modified by a Dispatcher, which will get events (with data) from an Action. Actions are the (only) ones, who may/should communicate with the outside-world (e.g. service calls).

Flux Architecture
The Flux Architecture Principle

The currently most popular Flux implementation library is called Redux, but there are a lot of others, too.

5.2.2. JSX

React.js makes heavy use of JSX, a new JavaScript dialect, mixed with HTML elements. Perhaps it’s a bit strange when using it first, but it comes handy while using it more and more.

app.jsx
class Book extends React.Component {
    render() {
        return (
            <div className="book">
                <h3>{this.props.author}</h3>
                <div className="lead">{this.props.children.toString()}</div>
            </div>
        );
    }
}

(Some people might be reminded of JSP when reading the code above…​)

JSX will be transpiled (transformed) to executable JavaScript (ES5) by using Babel.js. (Formerly this was done by JSXTransformer, a library from Facebook, but they switched to Babel, b/c it’s more powerful.)

app.js
var Book = React.createClass({displayName: "Book",
    render: function () {
        return (
            React.createElement("div", {className: "book"},
                React.createElement("h3", null, this.props.author),
                React.createElement("div", {className: "lead"}, this.props.children.toString())
            )
        );
    }
});

At runtime, this JavaScript code will be rendered to proper HTML.

app.html
<div class="book" data-reactid=".1c3dv7jhtco.1.$0">
    <h3 data-reactid=".1c3dv7jhtco.1.$0.0">George Orwell</h3>
    <div class="lead" data-reactid=".1c3dv7jhtco.1.$0.1">1984</div>
</div>

With the data-reactid attributes, React is able to locate the parts of the (virtual) DOM which have to be changed upon data change.

To learn more about React.js, JSX and Flux, please refer to their appropriate websites!

5.3. Spring Boot MVC for Isomorphic Apps

There are several demos using Spring (Boot) MVC and React.js for server-side rendering:

Please refer to these links, if you are more interested in building isomorphic applications with Spring MVC.

5.4. Java EE 8 MVC 1.0 for Isomorphic Apps

For the new to come Action-based Web-Framework MVC 1.0 in Java EE 8 and its reference implementation Ozark, I wrote a ViewEngine based on React.js, and also a working example, based on the React.js tutorial.

The following, simplified(!) code fragments are taken from the two above mentioned repositories to show, how an isomorphic JavaScript/Java EE application is realized.

Ensure to use the original code from the above mentioned repository when building applications with a React-based ViewEngine. These are much more flexible and powerful than this simplified example!

The ReactController is a standard MVC Controller, decorated with the new @Controller annotation.

ReactController.java
@Controller(1)
@Path("/react")
public class ReactController {

    @Inject
    private Models models;(2)

    @Inject
    private BookService service;(3)

    @GET
    public String index() throws Exception {
        List<Book> books = service.getBooks();
        models.put("data", books);(4)
        return "react:react.jsp";(5)
    }

}
1 MVC Controller annotation
2 MVC internal models entity, just a Map
3 some service to retrieve (and store) data
4 get a List of books and put the Java representation into the models Map
5 return the path to the template to use, with the react: prefix we’re saying that the ReactViewEngine should be used

This is the actual ViewEngine implementation, interacting with React.js

ReactViewEngine.java
public class ReactViewEngine extends ServletViewEngine {

    private static final String viewPrefix = "react:";

    @Inject
    React react;(1)

    ObjectMapper mapper = new ObjectMapper();

    @Override
    public boolean supports(String view) {(2)
        return view.startsWith(viewPrefix);
    }

    @Override
    public void processView(ViewEngineContext context) throws ViewEngineException {(3)
        // parse view and extract the actual template
        String template = context.getView().substring(viewPrefix.length());

        // get "data" from model
        Models models = context.getModels();
        Object data = models.get("data");

        // call js function on data to generate html
        String content = react.render(data);

        // and put results as string in model
        models.put("content", content);
        try {
            // additionally put the data as JSON also to the model
            // this overrides the List data stored previously under the same key
            models.put("data", mapper.writeValueAsString(data));
        } catch (JsonProcessingException e) {
            throw new ViewEngineException(e);
        }

        // create a new context with the actual view and forward to ServletViewEngine
        ViewEngineContext ctx = new ViewEngineContextImpl(template, models,
                context.getRequest(), context.getResponse(), context.getUriInfo(),
                context.getResourceInfo(), context.getConfiguration());

        try {
            forwardRequest(ctx, "*.jsp", "*.jspx");
        } catch (ServletException | IOException e) {
            throw new ViewEngineException(e);
        }
    }

}
1 The React class will interact with the React.js JavaScript code, see next class for details.
2 The supports() method determines, if this class can be used as an appropriate ViewEngine for a return string of a controller.
3 The processView() method actually handles the things to process the view, see inline comments for details.

The React class for interacting with React.js JavaScript code.

React.java
public class React {

    private ThreadLocal<ScriptEngine> engineHolder = ThreadLocal.withInitial(() -> {(1)
        ScriptEngine nashorn = new ScriptEngineManager().getEngineByName("nashorn");
        try {
            nashorn.eval(read("/nashorn-polyfill.js"));
            nashorn.eval(read("/META-INF/resources/webjars/react/0.14.2/react.min.js"));
            nashorn.eval(read(
                    "/META-INF/resources/webjars/showdown/0.3.1/compressed/showdown.js"));
            nashorn.eval(read("/js/bookBox.js"));
        } catch (ScriptException e) {
            throw new RuntimeException(e);
        }
        return nashorn;
    });

    public String render(Object object) {(2)
        try {
            Object html =
                    ((Invocable) engineHolder.get()).invokeFunction("renderServer", object);
            return String.valueOf(html);
        } catch (Exception e) {
            throw new IllegalStateException("failed to render react component", e);
        }
    }

    private Reader read(String path) {(3)
        return new InputStreamReader(getClass().getClassLoader().getResourceAsStream(path));
    }

}
1 initializes a new ThreadLocal<ScriptEngine> with all the needed JS libs, b/c React.js is not thread-safe, so we have to use a dedicated ScriptEngine in each request
2 call the renderServer function of our JSX/JS code and return the result as string (see next)
3 just a private method for reducing redundant code

The original JSX code (which will be rendered to JS before loading it into Nashorn, this can be made during build, or at runtime loading the Babel.js library into the Nashorn ScriptEngine, but this may be lead to even longer load times).

bookBox.jsx
...(1)

var renderClient = function (books) {(2)
    var data = books || [];
    React.render(
        <BookBox data={data} url='books.json' pollInterval={5000} />,(4)
        document.getElementById("content")
    );
};

var renderServer = function (books) {(3)
    var data = Java.from(books);
    return React.renderToString(
        <BookBox data={data} url='books.json' pollInterval={5000} />(4)
    );
};
1 there’s of course more code before, but that’s not interesting for us at this point
2 this function will be called by the client to initialize the application and to render the content
3 this function will be called by the server (see above) to render the content
4 the <BookBox/> component is the code from <1>, which is omitted here, but the actual isomorphic code!

The HTML skeleton, which will be enriched by the server-side rendered code, and send to the client.

react.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>ReactJS Bookstore with Ozark</title>
    <script src="${mvc.contextPath}/webjars/react/0.14.2/react.min.js"></script>(1)
    <script src="${mvc.contextPath}/webjars/showdown/0.3.1/compressed/showdown.js"></script>
    <script src="${mvc.contextPath}/webjars/jquery/1.11.3/jquery.min.js"></script>
    <link href="${mvc.contextPath}/webjars/bootstrap/3.3.5/css/bootstrap.css" rel="stylesheet">
</head>

<body>
    <div id="content" class="container">${content}</div>(2)
    <script type="text/javascript" src="${mvc.contextPath}/js/bookBox.js"></script>(3)
    <script type="text/javascript">
        $(function () {
            renderClient(${data});(4)
        });
    </script>
</body>
</html>
1 JS libraries referenced as WebJars (dependency specified in Maven/Gradle build file)
2 the div in which the rendered content will be put, regardless if client or server
3 the actual application script (see above)
4 the function which will be called, when the application is executed/initialized on the client-side (the function resides also in bookBox.js

If the application is started without calling the ReactViewEngine in ReactController (e.g. by returning only "react.jsp", this yields in using the standard JSP ViewEngine), there will be no HTML code visible in the <div id="content"/> element if you look at the initial source code received from the server. But the content will nevertheless be rendered and displayed in the browser, because of the client-side function call to renderClient().

As soon the application uses the ReactViewEngine, you will see the rendered content also in the <div id="content"/> element, received as source code from the server.

The client-side execution of renderClient() is also performed, but as there is no change to the (virtual) DOM, the page stays as it is, there’s no re-rendering of DOM elements (and thus no flickering).

Use two different browsers and play with the application. Have a look at the application updating itself every 5 seconds and how the source code relates to these updates (or not).

6. JavaFX with JavaScript

Nashorn comes with a special support for JavaFX. This support can be activated by using the -fx flag on the command-line when using jjs. Thus, no additional compile step for the scripted JavaFX and no additional bootstrapping is needed!

The -fx flag on jjs will bootstrap scripts using a javafx.application.Application.

Let’s assume this "Hello World" example written in plain old Java code:

HelloWorldFX.java
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class HelloWorldFX extends Application {
    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) {
        primaryStage.setTitle("Hello World!");
        Button btn = new Button();
        btn.setText("Say 'Hello World'");
        btn.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                System.out.println("Hello World!");
            }
        });
        StackPane root = new StackPane();
        root.getChildren().add(btn);
        primaryStage.setScene(new Scene(root, 300, 200));
        primaryStage.show();
    }
}

This is how it looks like in Nashorn JavaScript:

fxscript.js
var Button = Java.type("javafx.scene.control.Button");
var StackPane = Java.type("javafx.scene.layout.StackPane");
var Scene = Java.type("javafx.scene.Scene");

function start(stage) {
    stage.title = "Hello World!";
    var button = new Button();
    button.text = "Say 'Hello World'";
    button.onAction = function() {print("Hello World!");}
    var root = new StackPane();
    root.children.add(button);
    stage.scene = new Scene(root, 300, 200);
    stage.show();
}

Run the script with

$ jjs -fx fxscript.js

As seen above, a JavaFX script application contains a start() function, which is equivalent to the start() method in its Java counterpart. It also can contain the init() and stop() functions.

In Nashorn, the explicit usage of the start() function is optional. You can use the global $STAGE variable instead of the stage argument of the start() function, which is the primary stage. Thus, our script looks like this:

fxscript.js
var Button = Java.type("javafx.scene.control.Button");
var StackPane = Java.type("javafx.scene.layout.StackPane");
var Scene = Java.type("javafx.scene.Scene");

$STAGE.title = "Hello World!";
var button = new Button();
button.text = "Say 'Hello World'";
button.onAction = function() {print("Hello World!");}
var root = new StackPane();
root.children.add(button);
$STAGE.scene = new Scene(root, 300, 200);
$STAGE.show();

For further convenience, there are some predefined includes in the fx: namespace for all of the JavaFX classes. With these includes, our script now looks like this:

fxscript.js
load("fx:base.js");
load("fx:controls.js");
load("fx:graphics.js");

$STAGE.title = "Hello World!";
var button = new Button();
button.text = "Say 'Hello World'";
button.onAction = function() {print("Hello World!");}
var root = new StackPane();
root.children.add(button);
$STAGE.scene = new Scene(root, 300, 200);
$STAGE.show();
It’s highly recommended to use/add only the classes needed by the application. But it can be convenient for prototyping and during development, to have all the includes at hand.

6.1. List of includes

Table 1. FX Includes
Script Includes

fx:base.js

javafx.stage.Stage
javafx.scene.Scene
javafx.scene.Group
javafx/beans
javafx/collections
javafx/events
javafx/util

fx:graphics.js

javafx/animation
javafx/application
javafx/concurrent
javafx/css
javafx/geometry
javafx/print
javafx/scene
javafx/stage

fx:controls.js

javafx/scene/chart
javafx/scene/control

fx:fxml.js

javafx/fxml

fx:web.js

javafx/scene/web

fx:media.js

javafx/scene/media

fx:swing.js

javafx/embed/swing

fx:swt.js

javafx/embed/swt

Official Oracle documentation including some more examples: https://docs.oracle.com/javase/8/docs/technotes/guides/scripting/nashorn/javafx.html

7. Testing and Debugging of Nashorn Scripts

7.1. Testing

Testing of Nashorn scripts is not that hard as it may look like when you’re not yet used to it.

7.1.1. Function(al) testing with JUnit

Because every JavaScript function has a return value (yes, every JavaScript function, even functions which have no explicit return value will return undefined), these values can be asserted. Just build up your JavaScript file properly and working with testable, independent, hopefully atomic, functions, just as you would develop your Java methods. Then, you can just call a JS function in your test and assert the result.

Let’s assume we have the following JavaScript code:

calculator.js
var add = function(a, b) {
    return a + b;
}

var square = function(a) {
    return a * a;
}

You can then test the functions with a standard JUnit test

CalculatorTest.java
public class CalculatorTest {

    ScriptEngine nashorn;

    @Before
    public void setup() {
        nashorn = new ScriptEngineManager().getEngineByName("nashorn");
        nashorn.eval(new InputStreamReader(
                getClass().getClassLoader().getResourceAsStream("/calculator.js")));
    }

    @Test
    public void testAdd() throws Exception {
        Object result = ((Invocable) nashorn).invokeFunction("add", 1, 2);
        Assert.assertEquals(1, result);
    }

    @Test
    public void testSquare() throws Exception {
        Object result = ((Invocable) nashorn).invokeFunction("square", 2);
        Assert.assertEquals(4, result);
    }
}

7.1.2. Mocking JavaScript functions & using Spock

A much more nicer (and also more powerful) way of testing Nashorn scripts is to use Spock instead of JUnit. Spock is based on Groovy code and since Groovy is also a dynamic language, it’s easier to handle objects and functions created with Groovy between Nashorn and your tests (or specs, as tests are called in Spock).

With Spock it becomes very easy to mock functions, which aren’t under your control or which are not available in Nashorn. This could be callback functions (which are widely used in JavaScript), which you don’t want to execute during your test, or e.g. the alert() function, which Nashorn doesn’t know.

Callback.groovy
class CallbackSpec {

    @Shared ScriptEngine nashorn = new ScriptEngineManager().getEngineByName('nashorn');

    def "callback"() { (1)
        given:
        nashorn.eval('function callMe(callback) { return callback("") + " Doe"; }')

        when:
        def result = nashorn.invokeFunction('callMe', { return 'John' } as Function)

        then:
        result == 'John Doe'
    }

    def "mocked callback"() { (2)
        given:
        nashorn.eval('function callMe(callback) { return callback("") + " Doe"; }')
        def callback = Mock(Function)

        when:
        def result = nashorn.invokeFunction('callMe', callback)

        then:
        1 * callback.apply('') >> 'John'
        result == 'John Doe'
    }

    def "alert"() { (3)
        given:
        nashorn.eval('function alertMe() { alert("Huh!"); }')
        def alert = Mock(Function)
        nashorn.put('alert', alert)

        when:
        nashorn.invokeFunction('alertMe')

        then:
        1 * alert.apply('Huh!')
    }

}
1 This function gets a another callback function (of type java.util.function.Function) injected when invoking the test.
2 In this function the callback function is being mocked and afterwards it’s being tested, if the mock function was called once with value "John".
3 Because there is no alert() function available in Nashorn, we have to mock it also and add it to the Nashorn context before invoking the actual function.
Further examples with Spock and Nashorn can be found in the GitHub repository dasniko/nashorn-spock-jasmine.

7.2. Debugging

Debugging of Nashorn JavaScript is supported by major IDEs like

8. Contact

Niko Köbler IT-Beratung

E-Mail: info@n-k.de

Twitter: @dasniko