sundar@68: sundar@68: sundar@68: sundar@68: Java Scripting Programmer's Guide sundar@68: sundar@68: sundar@68: sundar@68: sundar@68: sundar@68: sundar@68: sundar@68: sundar@68:
sundar@68: sundar@68:

Java Scripting Programmer's Guide

sundar@68: sundar@68:
sundar@68: sundar@68: sundar@68: sundar@68:

Who is the Java Scripting API For?

sundar@68: Some useful characteristics of scripting languages sundar@68: are: sundar@68: sundar@68:

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

sundar@68:
sundar@68: sundar@68:

Scripting Package

sundar@68:

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

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

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

sundar@68:
sundar@68: sundar@68:

Examples

sundar@68: sundar@68:

"Hello, World"

sundar@68:

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

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

Evaluating a Script File

sundar@68:

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

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

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

sundar@68: java EvalFile test.js
sundar@68: 
sundar@68: 
sundar@68:
sundar@68: sundar@68:

Script Variables

sundar@68:

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

sundar@68:

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

Invoking Script Functions and Methods

sundar@68:

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

sundar@68:

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

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

sundar@68:

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

Implementing Java Interfaces by Scripts

sundar@68:

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

sundar@68:

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

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

sundar@68:

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

Multiple Scopes for Scripts

sundar@68:

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

sundar@68:

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

JavaScript Script Engine

sundar@68:

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


sundar@68: sundar@68:

JavaScript to Java Communication

sundar@68:

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

sundar@68:
sundar@68: sundar@68:

Accessing Java Classes

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

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

sundar@68:  var ArrayList = Java.type("java.util.ArrayList")
sundar@68:  var anArrayList = new ArrayList
sundar@68:  var anArrayListWithSize = new ArrayList(16)
sundar@68: 
sundar@68: sundar@68: In the special case of inner classes, you need to use the JVM fully qualified name, meaning using $ sign in the class name: sundar@68: sundar@68:

sundar@68:  var ftype = Java.type("java.awt.geom.Arc2D$Float")
sundar@68: 
sundar@68: sundar@68: sundar@68: However, once you retrieved the outer class, you can access the inner class as a property on it: sundar@68: sundar@68:

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

sundar@68: 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. sundar@68:

sundar@68:
sundar@68: sundar@68:

Importing Java Packages, Classes

sundar@68:

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

sundar@68:

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

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

sundar@68:

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

sundar@68:

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

sundar@68:

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

Creating, Converting and Using Java Arrays

sundar@68:

While creating a Java object is the same as in Java, to create sundar@68: Java arrays in JavaScript we can use Java reflection sundar@68: explicitly. But once created the element access or length access is sundar@68: the same as in Java. Also, a script array can be used when a Java sundar@68: method expects a Java array (auto conversion). So in most cases we sundar@68: don't have to create Java arrays explicitly.

sundar@68:

sundar@68: // javaarray.js
sundar@68: 
sundar@68: // create Java String array of 5 elements
sundar@68: var a = java.lang.reflect.Array.newInstance(java.lang.String.class, 5);
sundar@68: 
sundar@68: // Accessing elements and length access is by usual Java syntax
sundar@68: a[0] = "scripting is great!";
sundar@68: print(a.length);
sundar@68: print(a[0]);
sundar@68: 
sundar@68: 
sundar@68:

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

sundar@68:

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

sundar@68: Given a Java array or Collection, Java.toJavaScriptArray 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.i sundar@68:

sundar@68:

sundar@68: var File = Java.type("java.io.File");
sundar@68: var listCurDir = new File(".").listFiles();
sundar@68: var jsList = Java.toJavaScriptArray(listCurDir);
sundar@68: print(jsList);
sundar@68: 
sundar@68:
sundar@68: sundar@68:

Implementing Java Interfaces

sundar@68:

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

sundar@68:

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

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

sundar@68:

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

Extending Java classes

sundar@68:

sundar@68: 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.: sundar@68:

sundar@68: sundar@68:

sundar@68:  var TimerTask =  Java.type("java.util.TimerTask")
sundar@68:  var task = new TimerTask({ run: function() { print("Hello World!") } })
sundar@68: 
sundar@68: sundar@68: 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: sundar@68: sundar@68:

sundar@68:  var task = new TimerTask {
sundar@68:      run: function() {
sundar@68:        print("Hello World!")
sundar@68:      }
sundar@68:  }
sundar@68: 
sundar@68: sundar@68: 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: sundar@68: sundar@68:

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

sundar@68: 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. sundar@68:

sundar@68:

sundar@68: 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: sundar@68:

sundar@68:
sundar@68:  Java.type("java.util.Timer")
sundar@68:  timer.schedule(function() { print("Hello World!") })
sundar@68: 
sundar@68: sundar@68: 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. sundar@68: sundar@68:

sundar@68: To extend a concrete Java class, you have to use Java.extend function. sundar@68: 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. sundar@68:

sundar@68:

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

Overload Resolution

sundar@68:

Java methods can be overloaded by argument types. In Java, sundar@68: overload resolution occurs at compile time (performed by javac). sundar@68: When calling Java methods from a script, the script sundar@68: interpreter/compiler needs to select the appropriate method. With sundar@68: the JavaScript engine, you do not need to do anything special - the sundar@68: correct Java method overload variant is selected based on the sundar@68: argument types. But, sometimes you may want (or have) to explicitly sundar@68: select a particular overload variant.

sundar@68:

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

Implementing Your Own Script Engine

sundar@68:

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

sundar@68:

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

sundar@68:
sundar@68: sundar@68:

References

sundar@68: sundar@68: sundar@68: sundar@68: sundar@68:

sundar@68: sundar@68: sundar@68: sundar@68: sundar@68: sundar@68: sundar@68: sundar@68:
Oracle and/or its affiliates
sundar@68: Java Technology
sundar@68:

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

sundar@68:
sundar@68:

Contact Us

sundar@68:
sundar@68:

sundar@68: sundar@68: sundar@68: sundar@68: sundar@68: sundar@68: sundar@68: sundar@68: sundar@68: sundar@68: sundar@68: sundar@68: sundar@68: sundar@68: sundar@68: