aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: Java Scripting Programmer's Guide aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0:
aoqi@0: aoqi@0:

Java Scripting Programmer's Guide

aoqi@0: aoqi@0:
aoqi@0: aoqi@0: aoqi@0: aoqi@0:

Who is the Java Scripting API For?

aoqi@0: Some useful characteristics of scripting languages aoqi@0: are: aoqi@0: aoqi@0:

The JavaTM Scripting API aoqi@0: is a scripting language indepedent framework for using script aoqi@0: engines from Java code. With the Java Scripting API, it is possible aoqi@0: to write customizable/extendable applications in the Java language aoqi@0: and leave the customization scripting language choice to the end aoqi@0: user. The Java application developer need not choose the extension aoqi@0: language during development. If you write your application with aoqi@0: JSR-223 API, then your users can use any JSR-223 compliant aoqi@0: scripting language.

aoqi@0:
aoqi@0: aoqi@0:

Scripting Package

aoqi@0:

The Java Scripting functionality is in the javax.script aoqi@0: package. This is a relatively small, simple API. The starting point aoqi@0: of the scripting API is the ScriptEngineManager class. aoqi@0: A ScriptEngineManager object can discover script engines through aoqi@0: the jar file service discovery mechanism. It can also instantiate aoqi@0: ScriptEngine objects that interpret scripts written in a specific aoqi@0: scripting language. The simplest way to use the scripting API is as aoqi@0: follows:

aoqi@0:
    aoqi@0:
  1. Create a ScriptEngineManager aoqi@0: object.
  2. aoqi@0:
  3. Get a ScriptEngine object from the aoqi@0: manager.
  4. aoqi@0:
  5. Evaluate script using the ScriptEngine's aoqi@0: eval methods.
  6. aoqi@0:
aoqi@0:

Now, it is time to look at some sample code. While it is aoqi@0: not mandatory, it may be useful to know a bit of JavaScript to read aoqi@0: these examples.

aoqi@0:
aoqi@0: aoqi@0:

Examples

aoqi@0: aoqi@0:

"Hello, World"

aoqi@0:

From the ScriptEngineManager instance, we aoqi@0: request a JavaScript engine instance using aoqi@0: getEngineByName method. On the script engine, the aoqi@0: eval method is called to execute a given String as aoqi@0: JavaScript code! For brevity, in this as well as in subsequent aoqi@0: examples, we have not shown exception handling. There are checked aoqi@0: and runtime exceptions thrown from javax.script API. aoqi@0: Needless to say, you have to handle the exceptions aoqi@0: appropriately.

aoqi@0:
aoqi@0: 
aoqi@0: // EvalScript.java
aoqi@0: 
aoqi@0: import javax.script.*;
aoqi@0: public class EvalScript {
aoqi@0:     public static void main(String[] args) throws Exception {
aoqi@0:         // create a script engine manager
aoqi@0:         ScriptEngineManager factory = new ScriptEngineManager();
aoqi@0:         // create a JavaScript engine
aoqi@0:         ScriptEngine engine = factory.getEngineByName("nashorn");
aoqi@0:         // evaluate JavaScript code from String
aoqi@0:         engine.eval("print('Hello, World')");
aoqi@0:     }
aoqi@0: }
aoqi@0: 
aoqi@0: 
aoqi@0:
aoqi@0: aoqi@0:

Evaluating a Script File

aoqi@0:

In this example, we call the eval method that aoqi@0: accepts java.io.Reader for the input source. The aoqi@0: script read by the given reader is executed. This way it is aoqi@0: possible to execute scripts from files, URLs and resources by aoqi@0: wrapping the relevant input stream objects as readers.

aoqi@0:
aoqi@0: 
aoqi@0: // EvalFile.java
aoqi@0: 
aoqi@0: import javax.script.*;
aoqi@0: 
aoqi@0: public class EvalFile {
aoqi@0:     public static void main(String[] args) throws Exception {
aoqi@0:         // create a script engine manager
aoqi@0:         ScriptEngineManager factory = new ScriptEngineManager();
aoqi@0:         // create JavaScript engine
aoqi@0:         ScriptEngine engine = factory.getEngineByName("nashorn");
aoqi@0:         // evaluate JavaScript code from given file - specified by first argument
aoqi@0:         engine.eval(new java.io.FileReader(args[0]));
aoqi@0:     }
aoqi@0: }
aoqi@0: 
aoqi@0: 
aoqi@0: Let us assume that we have the file named test.js with the aoqi@0: following text: aoqi@0:

aoqi@0: print("This is hello from test.js");
aoqi@0: 
aoqi@0: 
aoqi@0: We can run the above Java as aoqi@0:

aoqi@0: java EvalFile test.js
aoqi@0: 
aoqi@0: 
aoqi@0:
aoqi@0: aoqi@0:

Script Variables

aoqi@0:

When you embed script engines and scripts with your Java aoqi@0: application, you may want to expose your application objects as aoqi@0: global variables to scripts. This example demonstrates how you can aoqi@0: expose your application objects as global variables to a script. We aoqi@0: create a java.io.File in the application and expose aoqi@0: the same as a global variable with the name "file". The script can aoqi@0: access the variable - for example, it can call public methods on aoqi@0: it. Note that the syntax to access Java objects, methods and fields aoqi@0: is dependent on the scripting language. JavaScript supports the aoqi@0: most "natural" Java-like syntax.

aoqi@0:

aoqi@0: Nashorn script engine pre-defines two global variables named "context" aoqi@0: and "engine". The "context" variable is of type javax.script.ScriptContext aoqi@0: and refers to the current ScriptContext instance passed to script engine's aoqi@0: eval method. The "engine" variable is of type javax.script.ScriptEngine and aoqi@0: refers to the current nashorn script engine instance evaluating the script. aoqi@0: Both of these variables are non-writable, non-enumerable and non-configurable aoqi@0: - which implies script code can not write overwrite the value, for..loop iteration aoqi@0: on global object will not iterate these variables and these variables can not be aoqi@0: deleted by script. aoqi@0:


aoqi@0: // ScriptVars.java
aoqi@0: 
aoqi@0: import javax.script.*;
aoqi@0: import java.io.*;
aoqi@0: 
aoqi@0: public class ScriptVars { 
aoqi@0:     public static void main(String[] args) throws Exception {
aoqi@0:         ScriptEngineManager manager = new ScriptEngineManager();
aoqi@0:         ScriptEngine engine = manager.getEngineByName("nashorn");
aoqi@0: 
aoqi@0:         File f = new File("test.txt");
aoqi@0:         // expose File object as variable to script
aoqi@0:         engine.put("file", f);
aoqi@0: 
aoqi@0:         // evaluate a script string. The script accesses "file" 
aoqi@0:         // variable and calls method on it
aoqi@0:         engine.eval("print(file.getAbsolutePath())");
aoqi@0:     }
aoqi@0: }
aoqi@0: 
aoqi@0: 
aoqi@0: 
aoqi@0:
aoqi@0: aoqi@0:

Invoking Script Functions and Methods

aoqi@0:

Sometimes you may want to call a specific scripting function aoqi@0: repeatedly - for example, your application menu functionality might aoqi@0: be implemented by a script. In your menu's action event handler you aoqi@0: may want to call a specific script function. The following example aoqi@0: demonstrates invoking a specific script function from Java aoqi@0: code.

aoqi@0:

aoqi@0: // InvokeScriptFunction.java
aoqi@0: 
aoqi@0: import javax.script.*;
aoqi@0: 
aoqi@0: public class InvokeScriptFunction {
aoqi@0:     public static void main(String[] args) throws Exception {
aoqi@0:         ScriptEngineManager manager = new ScriptEngineManager();
aoqi@0:         ScriptEngine engine = manager.getEngineByName("nashorn");
aoqi@0: 
aoqi@0:         // JavaScript code in a String
aoqi@0:         String script = "function hello(name) { print('Hello, ' + name); }";
aoqi@0:         // evaluate script
aoqi@0:         engine.eval(script);
aoqi@0: 
aoqi@0:         // javax.script.Invocable is an optional interface.
aoqi@0:         // Check whether your script engine implements it or not!
aoqi@0:         // Note that the JavaScript engine implements Invocable interface.
aoqi@0:         Invocable inv = (Invocable) engine;
aoqi@0: 
aoqi@0:         // invoke the global function named "hello"
aoqi@0:         inv.invokeFunction("hello", "Scripting!!" );
aoqi@0:     }
aoqi@0: }
aoqi@0: 
aoqi@0: 
aoqi@0: 
aoqi@0:

If your scripting language is object based (like JavaScript) or aoqi@0: object-oriented, then you can invoke a script method on a script aoqi@0: object.

aoqi@0:

aoqi@0: // InvokeScriptMethod.java
aoqi@0: 
aoqi@0: import javax.script.*;
aoqi@0: 
aoqi@0: public class InvokeScriptMethod {
aoqi@0:     public static void main(String[] args) throws Exception {
aoqi@0:         ScriptEngineManager manager = new ScriptEngineManager();
aoqi@0:         ScriptEngine engine = manager.getEngineByName("nashorn");
aoqi@0: 
aoqi@0:         // JavaScript code in a String. This code defines a script object 'obj'
aoqi@0:         // with one method called 'hello'.        
aoqi@0:         String script = "var obj = new Object(); obj.hello = function(name) { print('Hello, ' + name); }";
aoqi@0:         // evaluate script
aoqi@0:         engine.eval(script);
aoqi@0: 
aoqi@0:         // javax.script.Invocable is an optional interface.
aoqi@0:         // Check whether your script engine implements or not!
aoqi@0:         // Note that the JavaScript engine implements Invocable interface.
aoqi@0:         Invocable inv = (Invocable) engine;
aoqi@0: 
aoqi@0:         // get script object on which we want to call the method
aoqi@0:         Object obj = engine.get("obj");
aoqi@0: 
aoqi@0:         // invoke the method named "hello" on the script object "obj"
aoqi@0:         inv.invokeMethod(obj, "hello", "Script Method !!" );
aoqi@0:     }
aoqi@0: }
aoqi@0: 
aoqi@0: 
aoqi@0: 
aoqi@0:
aoqi@0: aoqi@0:

Implementing Java Interfaces by Scripts

aoqi@0:

Instead of calling specific script functions from Java, aoqi@0: sometimes it is convenient to implement a Java interface by script aoqi@0: functions or methods. Also, by using interfaces we can avoid having aoqi@0: to use the javax.script API in many places. We can get aoqi@0: an interface implementor object and pass it to various Java APIs. aoqi@0: The following example demonstrates implementing the aoqi@0: java.lang.Runnable interface with a script.

aoqi@0:

aoqi@0: // RunnableImpl.java
aoqi@0: 
aoqi@0: import javax.script.*;
aoqi@0: 
aoqi@0: public class RunnableImpl {
aoqi@0:     public static void main(String[] args) throws Exception {
aoqi@0:         ScriptEngineManager manager = new ScriptEngineManager();
aoqi@0:         ScriptEngine engine = manager.getEngineByName("nashorn");
aoqi@0: 
aoqi@0:         // JavaScript code in a String
aoqi@0:         String script = "function run() { print('run called'); }";
aoqi@0: 
aoqi@0:         // evaluate script
aoqi@0:         engine.eval(script);
aoqi@0: 
aoqi@0:         Invocable inv = (Invocable) engine;
aoqi@0: 
aoqi@0:         // get Runnable interface object from engine. This interface methods
aoqi@0:         // are implemented by script functions with the matching name.
aoqi@0:         Runnable r = inv.getInterface(Runnable.class);
aoqi@0: 
aoqi@0:         // start a new thread that runs the script implemented
aoqi@0:         // runnable interface
aoqi@0:         Thread th = new Thread(r);
aoqi@0:         th.start();
aoqi@0:         th.join();
aoqi@0:     }
aoqi@0: }
aoqi@0: 
aoqi@0: 
aoqi@0:

If your scripting language is object-based or object-oriented, aoqi@0: it is possible to implement a Java interface by script methods on aoqi@0: script objects. This avoids having to call script global functions aoqi@0: for interface methods. The script object can store the "state" aoqi@0: associated with the interface implementor.

aoqi@0:

aoqi@0: // RunnableImplObject.java
aoqi@0: 
aoqi@0: import javax.script.*;
aoqi@0: 
aoqi@0: public class RunnableImplObject {
aoqi@0:     public static void main(String[] args) throws Exception {
aoqi@0:         ScriptEngineManager manager = new ScriptEngineManager();
aoqi@0:         ScriptEngine engine = manager.getEngineByName("nashorn");
aoqi@0: 
aoqi@0:         // JavaScript code in a String
aoqi@0:         String script = "var obj = new Object(); obj.run = function() { print('run method called'); }";
aoqi@0: 
aoqi@0:         // evaluate script
aoqi@0:         engine.eval(script);
aoqi@0: 
aoqi@0:         // get script object on which we want to implement the interface with
aoqi@0:         Object obj = engine.get("obj");
aoqi@0: 
aoqi@0:         Invocable inv = (Invocable) engine;
aoqi@0: 
aoqi@0:         // get Runnable interface object from engine. This interface methods
aoqi@0:         // are implemented by script methods of object 'obj'
aoqi@0:         Runnable r = inv.getInterface(obj, Runnable.class);
aoqi@0: 
aoqi@0:         // start a new thread that runs the script implemented
aoqi@0:         // runnable interface
aoqi@0:         Thread th = new Thread(r);
aoqi@0:         th.start();
aoqi@0:         th.join();
aoqi@0:     }
aoqi@0: }
aoqi@0: 
aoqi@0: 
aoqi@0:
aoqi@0: aoqi@0:

Multiple Scopes for Scripts

aoqi@0:

In the script variables example, we aoqi@0: saw how to expose application objects as script global variables. aoqi@0: It is possible to expose multiple global "scopes" for scripts. A aoqi@0: single scope is an instance of javax.script.Bindings. aoqi@0: This interface is derived from java.util.Map<String, aoqi@0: Object>. A scope a set of name-value pairs where name is aoqi@0: any non-empty, non-null String. aoqi@0: javax.script.ScriptContext interface supports multiple aoqi@0: scopes with associated Bindings for each aoqi@0: scope. By default, every script engine has a default script aoqi@0: context. The default script context has atleast one scope called aoqi@0: "ENGINE_SCOPE". Various scopes supported by a script context are aoqi@0: available through getScopes method.

aoqi@0:

aoqi@0: // MultiScopes.java
aoqi@0: 
aoqi@0: import javax.script.*;
aoqi@0: 
aoqi@0: public class MultiScopes {
aoqi@0:     public static void main(String[] args) throws Exception {
aoqi@0:         ScriptEngineManager manager = new ScriptEngineManager();
aoqi@0:         ScriptEngine engine = manager.getEngineByName("nashorn");
aoqi@0: 
aoqi@0:         engine.put("x", "hello");
aoqi@0:         // print global variable "x"
aoqi@0:         engine.eval("print(x);");
aoqi@0:         // the above line prints "hello"
aoqi@0: 
aoqi@0:         // Now, pass a different script context
aoqi@0:         ScriptContext newContext = new SimpleScriptContext();
aoqi@0:         newContext.setBindings(engine.createBindings(), ScriptContext.ENGINE_SCOPE);
aoqi@0:         Bindings engineScope = newContext.getBindings(ScriptContext.ENGINE_SCOPE);
aoqi@0: 
aoqi@0:         // add new variable "x" to the new engineScope        
aoqi@0:         engineScope.put("x", "world");
aoqi@0: 
aoqi@0:         // execute the same script - but this time pass a different script context
aoqi@0:         engine.eval("print(x);", newContext);
aoqi@0:         // the above line prints "world"
aoqi@0:     }
aoqi@0: }
aoqi@0: 
aoqi@0: 
aoqi@0: 
aoqi@0:
aoqi@0: aoqi@0:

JavaScript Script Engine

aoqi@0:

Oracle's implementation of JDK 8 is co-bundled with the Nashorn ECMAScript aoqi@0: script engine. aoqi@0:


aoqi@0: aoqi@0:

JavaScript to Java Communication

aoqi@0:

For the most part, accessing Java classes, objects and methods aoqi@0: is straightforward. In particular field and method access from aoqi@0: JavaScript is the same as it is from Java. We highlight important aoqi@0: aspects of JavaScript Java access here. aoqi@0: The following examples are JavaScript snippets accessing Java. This aoqi@0: section requires knowledge of JavaScript. This section can be aoqi@0: skipped if you are planning to use some other JSR-223 scripting aoqi@0: language rather than JavaScript.

aoqi@0:
aoqi@0: aoqi@0:

Accessing Java Classes

aoqi@0:
aoqi@0: 
aoqi@0: // javatypes.js
aoqi@0: 
aoqi@0:  var arrayListType = Java.type("java.util.ArrayList")
aoqi@0:  var intType = Java.type("int")
aoqi@0:  var stringArrayType = Java.type("java.lang.String[]")
aoqi@0:  var int2DArrayType = Java.type("int[][]")
aoqi@0: 
aoqi@0: 
aoqi@0: aoqi@0: Note that the name of the type is always a string for a fully qualified name. You can use any of these expressions to create new instances, e.g.: aoqi@0: aoqi@0:

aoqi@0:  var anArrayList = new (Java.type("java.util.ArrayList"))
aoqi@0: 
aoqi@0: aoqi@0: or aoqi@0: aoqi@0:

aoqi@0:  var ArrayList = Java.type("java.util.ArrayList")
aoqi@0:  var anArrayList = new ArrayList
aoqi@0:  var anArrayListWithSize = new ArrayList(16)
aoqi@0: 
aoqi@0: aoqi@0: In the special case of inner classes, you can either use the JVM fully qualified name, meaning using the dollar sign in the class name, or you can use the dot: aoqi@0: aoqi@0:

aoqi@0:  var ftype = Java.type("java.awt.geom.Arc2D$Float")
aoqi@0: 
aoqi@0: aoqi@0: and aoqi@0: aoqi@0:

aoqi@0:  var ftype = Java.type("java.awt.geom.Arc2D.Float")
aoqi@0: 
aoqi@0: aoqi@0: both work. Note however that using the dollar sign is faster, as Java.type first tries to resolve the class name as it is originally specified, and the internal JVM names for inner classes use the dollar sign. If you use the dot, Java.type will internally get a ClassNotFoundException and subsequently retry by changing the last dot to dollar sign. As a matter of fact, it'll keep replacing dots with dollar signs until it either successfully loads the class or runs out of all dots in the name. This way it can correctly resolve and load even multiply nested inner classes with the dot notation. Again, this will be slower than using the dollar signs in the name. An alternative way to access the inner class is as a property of the outer class: aoqi@0: aoqi@0:

aoqi@0:  var arctype = Java.type("java.awt.geom.Arc2D")
aoqi@0:  var ftype = arctype.Float
aoqi@0: 
aoqi@0:

aoqi@0: You can access both static and non-static inner classes. If you want to create an instance of a non-static inner class, remember to pass an instance of its outer class as the first argument to the constructor. aoqi@0:

aoqi@0:

aoqi@0: In addition to creating new instances, the type objects returned from Java.type calls can also be used to access the aoqi@0: static fields and methods of the classes: aoqi@0:


aoqi@0:  var File = Java.type("java.io.File")
aoqi@0:  File.createTempFile("nashorn", ".tmp")
aoqi@0: 
aoqi@0:

aoqi@0: Methods with names of the form isXxx(), getXxx(), and setXxx() can also be used as properties, for both instances and statics. aoqi@0:

aoqi@0:

aoqi@0: A type object returned from Java.type is distinct from a java.lang.Class object. You can obtain one from the other using properties class and static on them. aoqi@0:


aoqi@0:  var ArrayList = Java.type("java.util.ArrayList")
aoqi@0:  var a = new ArrayList
aoqi@0: 
aoqi@0:  // All of the following print true:
aoqi@0:  print("Type acts as target of instanceof: " + (a instanceof ArrayList))
aoqi@0:  print("Class doesn't act as target of instanceof: " + !(a instanceof a.getClass()))
aoqi@0:  print("Type is not same as instance's getClass(): " + (a.getClass() !== ArrayList))
aoqi@0:  print("Type's `class` property is same as instance getClass(): " + (a.getClass() === ArrayList.class))
aoqi@0:  print("Type is same as instance getClass()'s `static` property: " + (a.getClass().static === ArrayList))
aoqi@0: 
aoqi@0:

aoqi@0: You can think of the type object as similar to the class names as used in Java source code: you use them as the aoqi@0: arguments to the new and instanceof operators and as the namespace for the static fields aoqi@0: and methods, but they are different than the runtime Class objects returned by getClass() calls. aoqi@0: Syntactically and semantically, this separation produces code that is most similar to Java code, where a distinction aoqi@0: between compile-time class expressions and runtime class objects also exists. (Also, Java can't have the equivalent of static aoqi@0: property on a Class object since compile-time class expressions are never reified as objects). aoqi@0:

aoqi@0:
aoqi@0: aoqi@0:

Importing Java Packages, Classes

aoqi@0:

The built-in functions importPackage (in compatibility script) and aoqi@0: importClass can be used to import Java packages and aoqi@0: classes.

aoqi@0:

aoqi@0: 
aoqi@0: // importpackageclass.js
aoqi@0: 
aoqi@0: // load compatibility script
aoqi@0: load("nashorn:mozilla_compat.js");
aoqi@0: // Import Java packages and classes 
aoqi@0: // like import package.*; in Java
aoqi@0: importPackage(java.awt);
aoqi@0: // like import java.awt.Frame in Java
aoqi@0: importClass(java.awt.Frame);
aoqi@0: // Create Java Objects by "new ClassName"
aoqi@0: var frame = new java.awt.Frame("hello");
aoqi@0: // Call Java public methods from script
aoqi@0: frame.setVisible(true);
aoqi@0: // Access "JavaBean" properties like "fields"
aoqi@0: print(frame.title);
aoqi@0: 
aoqi@0: 
aoqi@0:

The Packages global variable can aoqi@0: be used to access Java packages. Examples: aoqi@0: Packages.java.util.Vector, aoqi@0: Packages.javax.swing.JFrame. Please note that "java" aoqi@0: is a shortcut for "Packages.java". There are equivalent shortcuts aoqi@0: for javax, org, edu, com, net prefixes, so pratically all JDK aoqi@0: platform classes can be accessed without the "Packages" prefix.

aoqi@0:

Note that java.lang is not imported by default (unlike Java) aoqi@0: because that would result in conflicts with JavaScript's built-in aoqi@0: Object, Boolean, Math and so on.

aoqi@0:

importPackage and importClass aoqi@0: functions "pollute" the global variable scope of JavaScript. To aoqi@0: avoid that, you may use JavaImporter.

aoqi@0:

aoqi@0: 
aoqi@0: // javaimporter.js
aoqi@0: 
aoqi@0: // create JavaImporter with specific packages and classes to import
aoqi@0: 
aoqi@0: var SwingGui = new JavaImporter(javax.swing,
aoqi@0:                             javax.swing.event,
aoqi@0:                             javax.swing.border,
aoqi@0:                             java.awt.event);
aoqi@0: with (SwingGui) {
aoqi@0:     // within this 'with' statement, we can access Swing and AWT
aoqi@0:     // classes by unqualified (simple) names.
aoqi@0: 
aoqi@0:     var mybutton = new JButton("test");
aoqi@0:     var myframe = new JFrame("test");
aoqi@0: }
aoqi@0: 
aoqi@0: 
aoqi@0: 
aoqi@0:
aoqi@0: aoqi@0:

Creating, Converting and Using Java Arrays

aoqi@0:

aoqi@0: Array element access or length access is the same as in Java.

aoqi@0:

aoqi@0: // javaarray.js
aoqi@0: 
aoqi@0: // create Java String array of 5 elements
aoqi@0: var StringArray = Java.type("java.lang.String[]");
aoqi@0: var a = new StringArray(5);
aoqi@0: 
aoqi@0: // Accessing elements and length access is by usual Java syntax
aoqi@0: a[0] = "scripting is great!";
aoqi@0: print(a.length);
aoqi@0: print(a[0]);
aoqi@0: 
aoqi@0: 
aoqi@0:

aoqi@0: It is also possible to convert between JavaScript and Java arrays. aoqi@0: Given a JavaScript array and a Java type, Java.to returns a Java array with the same initial contents, and with the specified array type. aoqi@0:

aoqi@0:

aoqi@0:  var anArray = [1, "13", false]
aoqi@0:  var javaIntArray = Java.to(anArray, "int[]")
aoqi@0:  print(javaIntArray[0]) // prints 1
aoqi@0:  print(javaIntArray[1]) // prints 13, as string "13" was converted to number 13 as per ECMAScript ToNumber conversion
aoqi@0:  print(javaIntArray[2]) // prints 0, as boolean false was converted to number 0 as per ECMAScript ToNumber conversion
aoqi@0: 
aoqi@0:

aoqi@0: You can use either a string or a type object returned from Java.type() to specify the type of the array. aoqi@0: You can also omit the array type, in which case a Object[] will be created. aoqi@0:

aoqi@0:

aoqi@0: Given a Java array or Collection, Java.from returns a JavaScript array with a shallow copy of its contents. Note that in most cases, you can use Java arrays and lists natively in Nashorn; in cases where for some reason you need to have an actual JavaScript native array (e.g. to work with the array comprehensions functions), you will want to use this method. aoqi@0:

aoqi@0:

aoqi@0: var File = Java.type("java.io.File");
aoqi@0: var listCurDir = new File(".").listFiles();
aoqi@0: var jsList = Java.from(listCurDir);
aoqi@0: print(jsList);
aoqi@0: 
aoqi@0:
aoqi@0: aoqi@0:

Implementing Java interfaces

aoqi@0:

A Java interface can be implemented in JavaScript by using a aoqi@0: Java anonymous class-like syntax:

aoqi@0:

aoqi@0: // runnable.js
aoqi@0: 
aoqi@0: var r  = new java.lang.Runnable() {
aoqi@0:     run: function() {
aoqi@0:         print("running...\n");
aoqi@0:     }
aoqi@0: };
aoqi@0: 
aoqi@0: // "r" can be passed to Java methods that expect java.lang.Runnable
aoqi@0: var th = new java.lang.Thread(r);
aoqi@0: th.start();
aoqi@0: th.join();
aoqi@0: 
aoqi@0: 
aoqi@0:

When an interface with a single method is expected, you can pass aoqi@0: a script function directly.(auto conversion)

aoqi@0:

aoqi@0: // samfunc.js
aoqi@0: 
aoqi@0: function func() {
aoqi@0:      print("I am func!");
aoqi@0: }
aoqi@0: 
aoqi@0: // pass script function for java.lang.Runnable argument
aoqi@0: var th = new java.lang.Thread(func);
aoqi@0: th.start();
aoqi@0: th.join();
aoqi@0: 
aoqi@0: 
aoqi@0:
aoqi@0: aoqi@0:

Extending Abstract Java Classes

aoqi@0:

aoqi@0: If a Java class is abstract, you can instantiate an anonymous subclass of it using an argument list that is applicable to any of its public or protected constructors, but inserting a JavaScript object with functions properties that provide JavaScript implementations of the abstract methods. If method names are overloaded, the JavaScript function will provide implementation for all overloads. E.g.: aoqi@0:

aoqi@0: aoqi@0:

aoqi@0:  var TimerTask =  Java.type("java.util.TimerTask")
aoqi@0:  var task = new TimerTask({ run: function() { print("Hello World!") } })
aoqi@0: 
aoqi@0: aoqi@0: Nashorn supports a syntactic extension where a "new" expression followed by an argument is identical to invoking the constructor and passing the argument to it, so you can write the above example also as: aoqi@0: aoqi@0:

aoqi@0:  var task = new TimerTask {
aoqi@0:      run: function() {
aoqi@0:        print("Hello World!")
aoqi@0:      }
aoqi@0:  }
aoqi@0: 
aoqi@0: aoqi@0: which is very similar to Java anonymous inner class definition. On the other hand, if the type is an abstract type with a single abstract method (commonly referred to as a "SAM type") or all abstract methods it has share the same overloaded name), then instead of an object, you can just pass a function, so the above example can become even more simplified to: aoqi@0: aoqi@0:

aoqi@0:  var task = new TimerTask(function() { print("Hello World!") })
aoqi@0: 
aoqi@0: aoqi@0:

aoqi@0: Note that in every one of these cases if you are trying to instantiate an abstract class that has constructors that take some arguments, you can invoke those simply by specifying the arguments after the initial implementation object or function. aoqi@0:

aoqi@0:

aoqi@0: The use of functions can be taken even further; if you are invoking a Java method that takes a SAM type, you can just pass in a function object, and Nashorn will know what you meant: aoqi@0:

aoqi@0:
aoqi@0:  Java.type("java.util.Timer")
aoqi@0:  timer.schedule(function() { print("Hello World!") })
aoqi@0: 
aoqi@0: aoqi@0: Here, Timer.schedule() expects a TimerTask as its argument, so Nashorn creates an instance of a TimerTask subclass and uses the passed function to implement its only abstract method, run(). In this usage though, you can't use non-default constructors; the type must be either an interface, or must have a protected or public no-arg constructor. aoqi@0: aoqi@0:
aoqi@0: aoqi@0:

Extending Concrete Java Classes

aoqi@0:

aoqi@0: To extend a concrete Java class, you have to use Java.extend function. aoqi@0: Java.extend returns a type object for a subclass of the specified Java class (or implementation of the specified interface) that acts as a script-to-Java adapter for it. aoqi@0:

aoqi@0:

aoqi@0: // javaextend.js
aoqi@0: 
aoqi@0: var ArrayList = Java.type("java.util.ArrayList")
aoqi@0: var ArrayListExtender = Java.extend(ArrayList)
aoqi@0: var printSizeInvokedArrayList = new ArrayListExtender() {
aoqi@0:     size: function() { print("size invoked!"); }
aoqi@0: }
aoqi@0: var printAddInvokedArrayList = new ArrayListExtender() {
aoqi@0:     add: function(x, y) {
aoqi@0:         if(typeof(y) === "undefined") {
aoqi@0:             print("add(e) invoked!");
aoqi@0:         } else {
aoqi@0:             print("add(i, e) invoked!");
aoqi@0:         }
aoqi@0:     }
aoqi@0: };
aoqi@0: printSizeInvokedArrayList.size();
aoqi@0: printAddInvokedArrayList.add(33, 33);
aoqi@0: 
aoqi@0:

aoqi@0: The reason you must use Java.extend() with concrete classes is that with concrete classes, there can be a aoqi@0: syntactic ambiguity if you just invoke their constructor. Consider this example: aoqi@0:

aoqi@0:

aoqi@0: var t = new java.lang.Thread({ run: function() { print("Hello!") } })
aoqi@0: 
aoqi@0:

aoqi@0: If we allowed subclassing of concrete classes with constructor syntax, Nashorn couldn't tell if you're creating a new aoqi@0: Thread and passing it a Runnable at this point, or you are subclassing Thread and aoqi@0: passing it a new implementation for its own run() method. aoqi@0:

aoqi@0:
aoqi@0: aoqi@0:

Implementing Multiple Interfaces

aoqi@0:

aoqi@0: Java.extend can in fact take a list of multiple types. At most one of the types can be a class, and the rest must aoqi@0: be interfaces (the class doesn't have to be the first in the list). You will get back an object that extends the class and aoqi@0: implements all the interfaces. (Obviously, if you only specify interfaces and no class, the object will extend java.lang.Object). aoqi@0:


aoqi@0: aoqi@0:

Class-Bound Implementations

aoqi@0:

aoqi@0: The methods shown so far for extending Java classes and implementing interfaces – passing an implementation JavaScript object aoqi@0: or function to a constructor, or using Java.extend with new – all produce classes that take an aoqi@0: extra JavaScript object parameter in their constructors that specifies the implementation. The implementation is therefore always bound aoqi@0: to the actual instance being created with new, and not to the whole class. This has some advantages, for example in the aoqi@0: memory footprint of the runtime, as Nashorn can just create a single "universal adapter" for every combination of types being implemented. aoqi@0: In reality, the below code shows that different instantiations of, say, Runnable have the same class regardless of them having aoqi@0: different JavaScript implementation objects: aoqi@0:

aoqi@0:

aoqi@0: var Runnable = java.lang.Runnable;
aoqi@0: var r1 = new Runnable(function() { print("I'm runnable 1!") })
aoqi@0: var r2 = new Runnable(function() { print("I'm runnable 2!") })
aoqi@0: r1.run()
aoqi@0: r2.run()
aoqi@0: print("We share the same class: " + (r1.class === r2.class))
aoqi@0: 
aoqi@0:

aoqi@0: prints: aoqi@0:

aoqi@0:

aoqi@0: I'm runnable 1!
aoqi@0: I'm runnable 2!
aoqi@0: We share the same class: true
aoqi@0: 
aoqi@0:

aoqi@0: Sometimes, however, you'll want to extend a Java class or implement an interface with implementation bound to the class, not to aoqi@0: its instances. Such a need arises, for example, when you need to pass the class for instantiation to an external API; prime example aoqi@0: of this is the JavaFX framework where you need to pass an Application class to the FX API and let it instantiate it. aoqi@0:

aoqi@0:

aoqi@0: Fortunately, there's a solution for that: Java.extend() – aside from being able to take any number of type parameters aoqi@0: denoting a class to extend and interfaces to implement – can also take one last argument that has to be a JavaScript object aoqi@0: that serves as the implementation for the methods. In this case, Java.extend() will create a class that has the same aoqi@0: constructors as the original class had, as they don't need to take an an extra implementation object parameter. The example below aoqi@0: shows how you can create class-bound implementations, and shows that in this case, the implementation classes for different invocations aoqi@0: are indeed different: aoqi@0:

aoqi@0:

aoqi@0: var RunnableImpl1 = Java.extend(java.lang.Runnable, function() { print("I'm runnable 1!") })
aoqi@0: var RunnableImpl2 = Java.extend(java.lang.Runnable, function() { print("I'm runnable 2!") })
aoqi@0: var r1 = new RunnableImpl1()
aoqi@0: var r2 = new RunnableImpl2()
aoqi@0: r1.run()
aoqi@0: r2.run()
aoqi@0: print("We share the same class: " + (r1.class === r2.class))
aoqi@0: 
aoqi@0:

aoqi@0: prints: aoqi@0:

aoqi@0:

aoqi@0: I'm runnable 1!
aoqi@0: I'm runnable 2!
aoqi@0: We share the same class: false
aoqi@0: 
aoqi@0:

aoqi@0: As you can see, the major difference here is that we moved the implementation object into the invocation of Java.extend aoqi@0: from the constructor invocations – indeed the constructor invocations now don't even need to take an extra parameter! Since aoqi@0: the implementations are bound to a class, the two classes obviously can't be the same, and we indeed see that the two runnables no aoqi@0: longer share the same class – every invocation of Java.extend() with a class-specific implementation object triggers aoqi@0: the creation of a new Java adapter class. aoqi@0:

aoqi@0:

aoqi@0: Finally, the adapter classes with class-bound implementations can still take an additional constructor parameter to further aoqi@0: override the behavior on a per-instance basis. Thus, you can even combine the two approaches: you can provide part of the implementation aoqi@0: in a class-based JavaScript implementation object passed to Java.extend, and part in another object passed to the constructor. aoqi@0: Whatever functions are provided by the constructor-passed object will override the functions in the class-bound object. aoqi@0:

aoqi@0:

aoqi@0: var RunnableImpl = Java.extend(java.lang.Runnable, function() { print("I'm runnable 1!") })
aoqi@0: var r1 = new RunnableImpl()
aoqi@0: var r2 = new RunnableImpl(function() { print("I'm runnable 2!") })
aoqi@0: r1.run()
aoqi@0: r2.run()
aoqi@0: print("We share the same class: " + (r1.class === r2.class))
aoqi@0: 
aoqi@0:

aoqi@0: prints: aoqi@0:

aoqi@0:

aoqi@0: I'm runnable 1!
aoqi@0: I'm runnable 2!
aoqi@0: We share the same class: true
aoqi@0: 
aoqi@0:
aoqi@0: aoqi@0:

Overload Resolution

aoqi@0:

Java methods can be overloaded by argument types. In Java, aoqi@0: overload resolution occurs at compile time (performed by javac). aoqi@0: When calling Java methods from Nashorn, the appropriate method will be aoqi@0: selected based on the argument types at invocation time. You do not need aoqi@0: to do anything special – the correct Java method overload variant aoqi@0: is selected based automatically. You still have the option of explicitly aoqi@0: specifying a particular overload variant. Reasons for this include aoqi@0: either running into a genuine ambiguity with actual argument types, or aoqi@0: rarely reasons of performance – if you specify the actual overload aoqi@0: then the engine doesn't have to perform resolution during invocation. aoqi@0: Individual overloads of a Java methods are exposed as special properties aoqi@0: with the name of the method followed with its signature in parentheses. aoqi@0: You can invoke them like this:

aoqi@0:

aoqi@0: // overload.js
aoqi@0: 
aoqi@0: var out = java.lang.System.out;
aoqi@0: 
aoqi@0: // select a particular print function 
aoqi@0: out["println(Object)"]("hello");
aoqi@0: 
aoqi@0: 
aoqi@0:

aoqi@0: Note that you normally don't even have to use qualified class names in aoqi@0: the signatures as long as the unqualified name of the type is sufficient aoqi@0: for uniquely identifying the signature. In practice this means that only aoqi@0: in the extremely unlikely case that two overloads only differ in aoqi@0: parameter types that have identical unqualified names but come from aoqi@0: different packages would you need to use the fully qualified name of the aoqi@0: class. aoqi@0:

aoqi@0:
aoqi@0: aoqi@0:

Mapping of Data Types Between Java and JavaScript

aoqi@0:

aoqi@0: We have previously shown some of the data type mappings between Java and JavaScript. aoqi@0: We saw that arrays need to be explicitly converted. We have also shown that JavaScript functions aoqi@0: are automatically converted to SAM types when passed as parameters to Java methods. Most other aoqi@0: conversions work as you would expect. aoqi@0:

aoqi@0:

aoqi@0: Every JavaScript object is also a java.util.Map so APIs receiving maps will receive them directly. aoqi@0:

aoqi@0:

aoqi@0: When numbers are passed to a Java API, they will be converted to the expected target numeric type, either boxed or aoqi@0: primitive, but if the target type is less specific, say Number or Object, you can only aoqi@0: count on them being a Number, and have to test specifically for whether it's a boxed Double, aoqi@0: Integer, Long, etc. – it can be any of these due to internal optimizations. Also, you aoqi@0: can pass any JavaScript value to a Java API expecting either a boxed or primitive number; the JavaScript specification's aoqi@0: ToNumber conversion algorithm will be applied to the value. aoqi@0:

aoqi@0:

aoqi@0: In a similar vein, if a Java method expects a String or a Boolean, the values will be aoqi@0: converted using all conversions allowed by the JavaScript specification's ToString and ToBoolean aoqi@0: conversions. aoqi@0:

aoqi@0:

aoqi@0: Finally, a word of caution about strings. Due to internal performance optimizations of string operations, JavaScript strings are aoqi@0: not always necessarily of type java.lang.String, but they will always be of type java.lang.CharSequence. aoqi@0: If you pass them to a Java method that expects a java.lang.String parameter, then you will naturally receive a Java aoqi@0: String, but if the signature of your method is more generic, i.e. it receives a java.lang.Object parameter, you can aoqi@0: end up with an object of private engine implementation class that implements CharSequence but is not a Java String. aoqi@0:

aoqi@0:
aoqi@0: aoqi@0:

Implementing Your Own Script Engine

aoqi@0:

We will not cover implementation of JSR-223 compliant script aoqi@0: engines in detail. Minimally, you need to implement the aoqi@0: javax.script.ScriptEngine and aoqi@0: javax.script.ScriptEngineFactory interfaces. The aoqi@0: abstract class javax.script.AbstractScriptEngine aoqi@0: provides useful defaults for a few methods of the aoqi@0: ScriptEngine interface.

aoqi@0:

Before starting to implement a JSR-223 engine, you may want to aoqi@0: check http://java.net/projects/Scripting aoqi@0: project. This project maintains JSR-223 implementations for many aoqi@0: popular open source scripting languages.

aoqi@0:
aoqi@0: aoqi@0:

References

aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0:

aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0:
Oracle and/or its affiliates
aoqi@0: Java Technology
aoqi@0:

aoqi@0: Copyright © 2013, Oracle and/or its affiliates. All rights reserved. aoqi@0:

aoqi@0:
aoqi@0:

Contact Us

aoqi@0:
aoqi@0:

aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: aoqi@0: