These messages look similar, but notice the first one refers to a specific application and the second one generally refers to the java command-line tool. In either case, there is software trying to launch at startup and at other times which is requiring Java. Are you Apple Certified? PM the Mods with a GCX. Unsolved Why am I seeing random 'To use the 'java' command-line tool you need to install a JDK.' Isn't a big problem. Just wondering why I'm seeing it. Is there some app behind the scenes that could be requesting java command line use? How would I see that? I don't have Java.
Originally published in the January/February 2014 issue of Java Magazine. Subscribe today. |
Oracle Nashorn: A Next-Generation JavaScript Engine for the JVM
by Julien Ponge
Scenarios for using Oracle Nashorn as a command-line tool and as an embedded interpreter in Java applications
Until Java SE 7, JDKs shipped with a JavaScript scripting engine based on Mozilla Rhino. Java SE 8 will instead ship with a new engine called Oracle Nashorn, which is based on JSR 292 and invokedynamic. It provides better compliance with the ECMA normalized JavaScript specification and better runtime performance through invokedynamic-bound call sites.
This article is an introduction to using Oracle Nashorn in several ways. It covers using the standalone engine through the jjs command-line tool as well as using Oracle Nashorn as an embedded scripting engine inside Java applications. It shows the Java-to-JavaScript interoperability and how Java types can be implemented and extended from JavaScript, providing a seamless integration between the two languages.
The examples can be run using a recent JDK 8 early-access release. You can also use a custom build of OpenJDK 8. This is very simple to do thanks to the new OpenJDK build infrastructure (for example, sh configure && make images on a Mac OS X operating system with the XCode command-line tools installed).
[Editor's Note: Java SE 8 is now available from the OTN download page.]
[Editor's Note: Java SE 8 is now available from the OTN download page.]
It’s Just JavaScript
A simple way to get started with Oracle Nashorn is to run JavaScript programs from the command line. To do so, builds of Oracle’s JDK or OpenJDK include a command-line tool called jjs. It can be found in the bin/ folder of a JDK installation along with the well-known java, javac, or jar tools.
The jjs tool accepts a list of JavaScript source code files as arguments. Consider the following hello.js file:
Evaluating it is as simple as this:
Listing 1
Oracle Nashorn is an ECMA-compliant implementation of the language; hence, we can run more-elaborate snippets, such as the one shown in Listing 1, which prints a filtered list in which only the even numbers remain from the original list. It also prints the sum of those even numbers:
While Oracle Nashorn runs ECMA-compliant JavaScript, it is important to note that objects normally accessible in a web browser are not available, for example, console, window, and so on.
Scripting Extensions
If you run jjs -help to get a comprehensive list of the jjs command-line tool commands, you will notice a few interesting features:
- It can run scripts as JavaFX applications.
- JavaScript strict mode can be activated.
- Additional classpath elements can be specified for the Java Virtual Machine (JVM).
- An intriguing scripting mode can be enabled.
The scripting mode is interesting if you plan to take advantage of jjs to run system scripts written in JavaScript, just as you would do in Python, Ruby, or Bash. The scripting mode mainly consists of two language extensions: heredocs and shell invocations.
A simple way to get started with Oracle Nashorn is to run JavaScript programs from the command line.
Heredocs. Heredocs are simply multiline strings, and they use a syntax that is familiar to Bash, Perl, and Ruby programmers (see Listing 2). Text begins with << followed by a special termination marker, which is EOF in our case. The formatting is left intact until the termination marker. Also, JavaScript expressions can be embedded in ${...} expressions. Running this program yields the output shown in Listing 3.
Listing 2
Listing 3
Note that in scripting mode, double-quoted strings can embed expressions that will be evaluated: 'Hello ${name}' will evaluate against the value of name, while 'Hello ${name}' will not.
Shell invocations. Shell invocations allow the invocation of external programs in which the command is put between back-tick characters. Consider the following example:
It runs the ls -lsa command. A shell invocation returns the standard console output as a string, which enables us to split lines and print them prepended with '|> ', as shown in Listing 4. If you need more-elaborate control over invoked processes, you should know that a $EXEC function exists, which provides access to the standard input, output, and error streams.
Listing 4
Other goodies. The scripting mode provides further goodies:
Why Is My Mac Calling For Java Command Line Tool Message
- The $ENV variable provides the shell environment variables.
- The $ARG variable is an array of the program command-line arguments.
- Comments can start with #, which is useful for making scripts executable on UNIX-like systems. exit(code) and quit() functions can terminate the current JVM process.
Consider the following executable.js file:
We can make it executable and invoke it (arguments are passed after --), as shown in Listing 5.
Listing 5
Embedding Oracle Nashorn
The public API to embed Oracle Nashorn is simply javax.script. When Oracle Nashorn is available, its scripting engine is accessible through the nashorn identifier.
Listing 6 shows how you can access Oracle Nashorn from a Java application to define a sum function, call it, and then display the result.
Listing 6
The scripting engine object is the sole entry point to the Oracle Nashorn interpreter. It can be cast to the javax.script.Invocable interface, too:
The Invocable interface also provides a method to convert evaluated code to a reference on a Java interface. Suppose that there exists some interface Adder as follows:
The evaluated code defines a sum function with two arguments; hence, we can use it as an implementation as follows:
This is a convenient way to extend Java types from JavaScript, but fortunately it’s not the only one, as we will see in the next sections.
Not every JavaScript code is to be evaluated from a String: java.io.Reader; instances can be used, too, as shown in Listing 7.
Listing 7
You should consult the complete javax.script APIs for more details, including the information about the ability to define scopes and bindings of script engines.
mustache.js
Let’s now call a real-world JavaScript library from a Java application. To do so, let’s use the popular mustache.js template library, which is commonly used to render view fragments in HTML applications. Briefly, given a JSON data object {'name':'Bean'} and a template 'Hello {{name}}', Mustache renders 'Hello Bean'. The template engine can do more than that, though, because it also supports conditions, collection iteration, and more.
Suppose that we downloadedmustache.js. Listings 8a and 8b show our Java integration example.
Listing 8a
Listing 8b
After getting a scripting engine reference for Oracle Nashorn, we evaluate the mustache.js code. We then define the Mustache template as a String. The data model needs to be a JSON object. In our case, we first have to define it as a String and call JSON.parse to have it as a JSON object. We can then call Mustache.render. Running this program yields the following output, calling mustache.js for template rendering:
Java Seen from Oracle Nashorn
In most cases, calling Java APIs from Oracle Nashorn is straightforward, with the resulting code being Java written in JavaScript.
Listing 9
Basic example. We can call the System.currentTimeMillis() static method, as shown in Listing 9. And Java objects can be instantiated using the new operator:
Note that although java.io.File does not define an absolutePath method or public field, Oracle Nashorn inferred a property for it, so the expression file.absolutePath is equivalent to file.get AbsolutePath(). In fact, Oracle Nashorn treats the getXY() and setXY(value) methods as properties.
Dealing with arrays. The following snippet populates a queue as an instance of java.util.LinkedList:
This produces the following output, confirming that we are directly manipulating Java objects from JavaScript:
We can also take a tour through the new Java 8 stream APIs to sort the collection, although in this case, this is not the most efficient way to do so:
This time, it prints something like [Ljava.lang.Object;@473b46c3, which indicates a Java native array. However, a Java array is not a JavaScript array. Internally, Oracle Nashorn provides JavaScript arrays using a custom class that also implements java.util.Map. Conversions can be performed using the to and from methods of the Oracle Nashorn–provided Java object:
which prints:
Imports. By default, all references to Java types need to be fully qualified (for example, java.lang.String, java.util.LinkedHashSet, and so on). Oracle Nashorn does not import the java package by default, because references to String or Object conflict with the corresponding types in JavaScript. Hence, a Java string is java.lang.String, not String.
Mozilla Rhino was the predecessor of Oracle Nashorn as the JavaScript engine implementation provided with Oracle’s JDK releases. It featured a load(path) function to load a third-party JavaScript file. This is still present in Oracle Nashorn. You can use it to load a special compatibility module that provides importClass to import a class (like an explicit import in Java) and importPackage to import a package (like a wildcard import in Java):
It is important to note that these functions import the symbolic references into the global scope of the JavaScript code being interpreted. While they are still supported for compatibility reasons, the use of mozilla_compat.js and importClass is discouraged. Instead, it is recommended that you use another function coming from the Mozilla Rhino heritage--JavaImporter—as shown in Listing 10.
Listing 10
JavaImporter takes a variable number of arguments as Java packages, and the returned object can be used in a with statement whose scope includes the specified package imports. The global JavaScript scope is not affected, making JavaImporter a much better alternative to importClass and importPackage.
Overloaded methods. Java allows method overloading, that is, the definition within a single class of several methods that have the same names but different signatures. The java.io.PrintStream class is a good example, providing many print and println methods for objects, strings, arrays, and primitive types.
Oracle Nashorn properly selects the most suitable target at runtime on a per-invocation basis. This means that you should never have to worry about overloaded methods when dealing with Java APIs. Still, there is a way to precisely select the required target if you need to. This need mainly occurs with ambiguous parameters when you are passing a function object in which different interface types are permitted by overloaded methods, such as with the submit methods of java.util.concurrent executors.
In the following code, the first call to println will select the println(String) overloaded method. The second call uses a JavaScript object property to access the println(Object) variant. The string to be passed provides a signature that Oracle Nashorn uses at resolution time. Note that as an exception, classes from the java package need not be qualified; hence, we can write println(Object) instead of the valid, but longer, println(java.lang.Object).
Type objects. The Java.type function can be used to obtain references to precise Java types. These include not just objects but also primitive types and arrays:
The returned objects are an Oracle Nashorn–specific representation of mappings to Java types. It is important to note that they differ from instances of java.lang.Class. Type objects are useful as constructors and for instanceof-based comparisons. Let’s look at Listing 11.
Listing 11
It is possible to go back and forth between a type object and a Java class reference. The class property of type objects returns their java.lang.Class counterpart. Similarly, the static property is made available to java.lang.Class instances to get their corresponding type objects.
The code in Listing 12 would print the following:
Extending Java Types
Oracle Nashorn provides simple mechanisms for extending Java types from JavaScript code. It is important to be able to provide interface implementations and concrete subclasses.
Implementing interfaces. Given a Java interface, a simple way to provide an implementation is to instantiate it, and pass its constructor function a JavaScript object in which the methods to be implemented are given as properties.
Listing 13 provides a concrete implementation of java.util.Iterator, giving implementations of the next and hasNext methods (the remove method is provided by a default method in Java 8). We can run it, and check that it works as expected (see Listing 14).
Listing 13
Listing 14
When interfaces consist of a single method, a function object can be directly given with no need to perform an explicit new operator call. The example in Listing 15 illustrates this on collection streams.
Listing 15
Running the code in Listing 15 prints the following:
Note that Oracle Nashorn also provides a language extension in the form of Oracle Nashorn functions, which provides an abridged syntax for small lambda functions. This works everywhere a single abstract-method type is expected from Java APIs, too. Therefore, we can rewrite the following code from Listing 15:
Like this:
This language extension is useful when dealing with the new Java SE 8 APIs that provide support for lambda expressions, because JavaScript functions can be used wherever a Java lambda is expected. Also, note that this shorter form is to be supported by JavaScript 1.8 engines.
The case of abstract classes is the same as interfaces: you provide a JavaScript object with the required method implementations to its constructor function. Or, directly pass a function when an instance of a single abstract-method class is required.
Using instance-bound implementations. To extend concrete classes, you have to use the Java.extend function. It takes a type object as a first argument to denote the base class to be extended. If the parameter is an interface type, it assumes that the base class is java.lang.Object. Further types can be given as extra parameters to specify a set of implemented interfaces.
Consider the example shown in Listing 16. The Java.extend function returns a type object, also called an extender. It can be invoked to create concrete subclasses; in our case, instance is a subclass of java.lang.Object that implements the two interfaces java.lang .Comparable and java.io.Serializable. Implementations are passed to instances being created through a JavaScript object passed to the constructors.
Listing 16
Running the code in Listing 16 yields the following console output:
Using class-bound implementations. Instances created from the same extender type share the same class although their implementations differ on a per-instance basis (see Listing 17).
Listing 17
While this is fine in many cases, passing the implementation to each instance might not always be convenient. Indeed, there are cases where objects must be instantiated through some form of inversion-of-control mechanism, such as those found in dependency injection APIs. In such cases, the third-party APIs typically require a reference to the implementation class, which makes the previous extender mechanism unsuitable.
Fortunately, Java.extend allows implementations to be bound to a class definition rather than being specified for each instance. To do so, you simply need to pass an implementation JavaScript object as the last parameter.
Learn More |
Consider Listing 18, which defines two extender types: FooCallable and BarCallable. When creating instances foo and bar, there is no need to pass implementations. We can also check that instances do not have the same class definition. In fact, FooCallable.class or BarCallable.class can be passed to third-party Java APIs that need instances of java.lang.Class definitions.
Listing 18
Although not illustrated by this example, classes defined with class-bound implementations provide constructors inherited from their superclass. In this example, our objects implicitly extend java.lang.Object and implement java.util.concurrent.Callable; hence, the corresponding class definition simply has a public no-arguments constructor.
Using instance-bound and class-bound implementations. Last but not least, it is possible to combine both instance-bound and class-bound implementations. You can refine the class-bound implementation of all or some of the methods by passing an implementation object to its constructor, as shown in Listing 19.
Listing 19
Conclusion
This article covered various scenarios for using Oracle Nashorn as a command-line tool and as an embedded interpreter in Java applications. It also covered the interoperability between Java and JavaScript, including the ability to implement and extend Java types from JavaScript.
Oracle Nashorn is an excellent way to take advantage of a scripting language for polyglot applications on the JVM. JavaScript is a popular language, and the interaction between Java and JavaScript is both seamless and straightforward for a wide range of use cases.
Julien Ponge (@jponge) is a longtime open source craftsman who is currently an associate professor in computer science and engineering at INSA de Lyon. He focuses his research on programming languages, virtual machines, and middleware as part of the CITI Laboratory activities.