October 28, 2021
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.
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;
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.
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);
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);
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) formArrayList = Java.type("java.util.ArrayList");MXServer = Java.type("psdi.server.MXServer");} else {// Rhino (Java 7) formArrayList = java.util.ArrayList;MXServer = Packages.psdi.server.MXServer;}
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.