Nashorn vs Rhino

October 28, 2021

Introduction

While writing some automation scripts for a recent project based on an older version of Maximo, I was reminded of the challenges of transitioning from the Java 7 to Java 8 JavaScript engines. While it has been many years since the transition occurred, I still notice that even in modern implementations the old Rhino style is used with nashorn:mozilla_compat.js compatibility library unnecessarily loaded to support this legacy code. This post will describe the new Nashorn syntax for automation scripts.

Automation scripts written in JavaScript prior to Maximo 7.6.0.6 used Java JDK 7, which included the Mozilla Rhino JavaScript engine https://github.com/mozilla/rhino. Starting with Maximo 7.6.0.6 (released in 2016), the Java 8 JDK became available and with it a new JavaScript engine from Oracle called Nashorn, which implemented JSR 292 and provided numerous performance and compliance enhancements. There were also differences in its interactions with native Java, in particular how Java classes are imported into a script. To ease the transition from Rhino to Nashorn a compatibility library was provided and could be utilized by including load("nashorn:mozilla_compat.js"); at the beginning of a script. While is is convenient, it is also unnecessary and incurs a performance impact.

This post highlights some of the differences between Rhino and Nashorn and demonstrates the recommended ways of importing classes and interacting with Java objects in Nashorn.

Import

Rhino

In Rhino imports for top-level java and javax packages were supported by simply declaring a variable with the fully qualified class name.

var ArrayList = java.util.ArrayList;

For the non java or javax package classes imports were included by prefixing the import with Packages followed by the fully qualified class name.

var MXServer = Packages.psdi.server.MXServer;

Nashorn

While Nashorn still provides special handling for top-level java and javax packages and even supports the Packages object for importing Java classes, a new Java.type object introduces a consistent mechanism for importing Java classes.

var ArrayList = Java.type("java.util.ArrayList");
var MXServer = Java.type("psdi.server.MXServer");

The Java.type syntax has several benefits including better performance and notably that it throws a ClassNotFoundException when a class cannot be resolved rather than just treating unresolved resources as a package name.

Java Arrays

Rhino

In Rhino accessing arrays of Java type objects is a multi-step process using reflection, where the Array type is resolved, the content type is resolved and then a new Array object is created.

var Array = java.lang.reflect.Array;
var intType = java.lang.Integer.TYPE;
var newArray = Array.newInstance(intType, 4);

Nashorn

In Nashorn this has been simplified and made consistent with other class resolution with the same Java.type syntax.

var Array = Java.type("int[]");
var newArray = new Array(4);

Compatibility

Nashorn removed support for the global importClass and importPackage import functions. These have been replaced by assigning a global variable using the Java.type syntax.

While in most cases a script targets a specific version or instance of Maximo, there are times when a script may need to be compatible with Maximo instances running with either the Java 7 or Java 8 JDK. In these cases you can test for the presence of the importClass function and dynamically load the nashorn:mozilla_compat.js compatibility script.

if (typeof importClass !== "function") {
load("nashorn:mozilla_compat.js");
}

You may also use this to select the appropriate import mechanism and avoid loading the compatibility script all together if you do not need to support the prototype functions such as _defineGetter__, __defineSetter__, or __lookupGetter__, which should be avoided anyway since they are deprecated Mozilla and should be replaced with Object.defineProperty and Object.defineProperties.

if (typeof importClass !== "function") {
// Nashorn (Java 8) form
ArrayList = Java.type("java.util.ArrayList");
MXServer = Java.type("psdi.server.MXServer");
} else {
// Rhino (Java 7) form
ArrayList = java.util.ArrayList;
MXServer = Packages.psdi.server.MXServer;
}

Conclusion

This is a short post, but hopefully one that helps ease the transition from Rhino and Nashorn scripts. The differences between Rhino and Nashorn are minimal, but it pays to keep current and avoid technical debt or if you are still on a legacy version of Maximo, prepare for the future and make the transition to a newer version of Maximo that much easier.

In the time it took you to read this blog post...

You could have deployed Opqo, our game-changing mobile solution for Maximo.

Opqo is simple to acquire, simple to deploy and simple to use, with clear transparent monthly pricing that is flexible to your usage.