Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migrated to Confluence 5.3

...


The bound object need not be a script object. It could be a Java object as well - usual Java bean style getter/setter properties will be bound. Also a property only with getter will be bound as read-only property.

Extensions of Error objects, Error.prototype and Error constructor

Nashorn extends ECMAScript Error (or subtype) objects with the following properties.

  • lineNumber - source code line number from which error object was thrown
  • columnNumber  -  source code column number from which error object was thrown
  • fileName  - source script file name
  • stack - script stack trace as a string

In addition to this Error.prototype has the following extension functions as well.

  • Error.prototype.printStackTrace() - prints full stack trace (including all Java frames) from where error was thrown from
  • Error.prototype.getStackTrace() -  returns an array of java.lang.StackTraceElement instance for ECMAScript frames only.

Error constructor includes dumpStack() function property

  • Error.dumpStack() - prints stack trace of the current thread - just like java.lang.Thread.dumpStack()
Code Block
titleError extensions
function func() {
    throw new Error()
}

function f() {
    func()
}

try {
    f()
} catch (e) {
    print(e.stack)
    print(e.lineNumber)
    print(e.columnNumber)
    print(e.fileName)
}

String.prototype extensions

String.prototype.trimLeft - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/TrimLeft

String.prototype.trimRight - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/TrimRight

Function.prototype.toSource

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/toSource

Extension properties, functions in global object

__FILE__ , __LINE__, __DIR__

Current executing script file, line, directory of the script can be accessed by these global (read-only) properties. This is useful in debug/tracing scripts. __DIR__ can be used like Unix 'dirname' command. Script can load script-file relative path resources using __DIR__.

Code Block
title__FILE__ and __LINE__
print(__FILE__, __LINE__, __DIR__)

print function

print function prints it's arguments (after converting those to Strings) on standard output

Code Block
titleprint
print("hello", "world")

...

The source object bound can be a ScriptObject or a ScriptOjectMirror.
null or undefined source object results in TypeError being thrown.

Limitations of property binding:

* Only enumerable, immediate (not proto inherited) properties of the source object are bound.
* If the target object already contains a property called "foo", the source's "foo" is skipped (not bound). * Properties added to the source object after binding to the target are not bound. * Property configuration changes on the source object (or on the target) is not propagated.
* Delete of property on the target (or the source) is not propagated -
only the property value is set to 'undefined' if the property happens to be a data property.
It is recommended that the bound properties be treated as non-configurable
properties to avoid surprises.

Extensions of Error objects, Error.prototype and Error constructor

Nashorn extends ECMAScript Error (or subtype) objects with the following properties.

  • lineNumber - source code line number from which error object was thrown
  • columnNumber  -  source code column number from which error object was thrown
  • fileName  - source script file name
  • stack - script stack trace as a string

In addition to this Error.prototype has the following extension functions as well.

  • Error.prototype.printStackTrace() - prints full stack trace (including all Java frames) from where error was thrown from
  • Error.prototype.getStackTrace() -  returns an array of java.lang.StackTraceElement instance for ECMAScript frames only.

Error constructor includes dumpStack() function property

  • Error.dumpStack() - prints stack trace of the current thread - just like java.lang.Thread.dumpStack()
Code Block
titleError extensions
function func() {
    throw new Error()
}

function f() {
    func()
}

try {
    f()
} catch (e) {
    print(e.stack)
    print(e.lineNumber)
    print(e.columnNumber)
    print(e.fileName)
}

String.prototype extensions

String.prototype.trimLeft - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/TrimLeft

String.prototype.trimRight - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/TrimRight

Function.prototype.toSource

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/toSource

Extension properties, functions in global object

__FILE__ , __LINE__, __DIR__

Current executing script file, line, directory of the script can be accessed by these global (read-only) properties. This is useful in debug/tracing scripts. __DIR__ can be used like Unix 'dirname' command. Script can load script-file relative path resources using __DIR__.

Code Block
title__FILE__ and __LINE__
print(__FILE__, __LINE__, __DIR__)

print function

print function prints it's arguments (after converting those to Strings) on standard output

Code Block
titleprint
print("hello", "world")

Anchor
load
load

load function

Loads and evaluates script from a file or a URL or a script object. Examples:

Code Block
titleload function
// can load script from files, URLs

load("foo.js"); // loads script from file "foo.js" from current directory
load("http://www.example.com/t.js"); // loads script file from given URL

// loads script from an object's properties. 

// Object should have "script" and "name" properties.
//     "script" property contains string code of the script. 
//     "name" property specifies name to be used while reporting errors from script
// This is almost like the standard "eval" except that it associates a name with
// the script string for debugging purpose.

load({ script: "print('hello')", name: "myscript.js"})

// load can also load from pseudo URLs like "nashorn:", "fx:", "classpath:" 

// "nashorn:" pseudo URL scheme
// for nashorn's built-in scripts. 

// load nashorn's parser support script - defines 'parse'
// function in global scope

load("nashorn:parser.js"); 

// load Mozilla compatibility script - which defines global functions
// like importPackage, importClass for rhino compatibility.

load("nashorn:mozilla_compat.js");

// "fx:" pseudo URL scheme for JavaFX support scripts
// "classpath:" pseudo URL scheme to load scripts from jjs classpath jars and directories

load("classpath:foo.js"); // load the first foo.js found in jjs -classpath dir

Anchor
loadWithNewGlobal
loadWithNewGlobal

loadWithNewGlobal function

loadWithNewGlobal is almost like the function "load" in that it loads script from a file or a URL or a script object. But unlike 'load', loadWithNewGlobal creates a fresh ECMAScript global scope object and loads the script into it. The loaded script's global definitions go into the fresh global scope. Also, the loaded script's modifications of builtin objects (like String.prototype.indexOf) is not reflected in the caller's global scope – these are affected in the newly created global scope.

Code Block
titleloadWithNewGlobal
loadWithNewGlobal({
    script: "foo = 333; print(foo)",
    name: "test"
});

// prints undefined as "foo" is defined in the new global and not here
print(typeof foo); 

exit and quit functions

These synonymous functions exit the current process with specified (optional) exit code.

Code Block
titleexit
exit(1); // exit with given exit code
exit();  // exit 0
 
quit(2); // exit with given exit code
quit();  // exit 0

Packages, java, javax, javafx, com, edu, org

Packages and related objects are there to support java package, class access from script. The properties of the Packages variable are all the top-level Java packages, such as java and javax etc.

Code Block
titlePackages
var Vector = Packages.java.util.Vector;

// but short-cuts defined for important package prefixes like
//    Packages.java, Packages.javax, Packages.com
//    Packages.edu, Packages.javafx, Packages.org

var JFrame = javax.swing.JFrame;  // javax == Packages.javax
var List = java.util.List;        // java == Packages.java
Code Block
titlejjs session of Packages, classes
jjs> Packages.java
[JavaPackage java]
jjs> java
[JavaPackage java]
jjs> java.util.Vector
[JavaClass java.util.Vector]
jjs> javax
[JavaPackage javax]
jjs> javax.swing.JFrame
[JavaClass javax.swing.JFrame]

JavaImporter constructor

Many times you may want to import many Java packages – but without having to "pollute" global scope. JavaImporter helps in such situations.

Code Block
titleJavaImporter
// JavaImporter constructor accepts one or more Java Package objects
var imports = new JavaImporter(java.util, java.io);

// a JavaImporter can be used as a "with" expression object
with(imports) {
    // classes from java.util and java.io packages can 
    // can be accessed by unqualified names

    var map = new HashMap(); // refers to java.util.HashMap
    map.put("js", "javascript");
    map.put("java", "java");
    map.put("cpp", "c++");
    print(map);

    var f = new File("."); // refers to java.io.File
    print(f.getAbsolutePath());
}
Code Block
titleJavaImporter in 'with' statement example
// read text content from the given URL

function readText(url) {
    // Using JavaImporter to resolve classes
    // from specified java packages within the
    // 'with' statement below

    with (new JavaImporter(java.io, java.net)) {
        // more or less regular java code except for static types
        var is = new URL(url).openStream();
        try {
            var reader = new BufferedReader(
                new InputStreamReader(is));
            var buf = '', line = null;
            while ((line = reader.readLine()) != null) {
                buf += line;
            }
        } finally {
            reader.close();
        }
        return buf;
    }
}

print(readText("http://google.com?q=jdk8"))

Java object

"Java" global property is a script object that defines useful functions for script-to-Java interface.

Java.type function

Given a name of a Java type, returns an object representing that type in Nashorn. The Java class of the objects used to represent Java types in Nashorn is not Class but rather StaticClass. They are the objects that you can use with the new operator to create new instances of the class as well as to access static members of the class. In Nashorn, Class objects are just regular Java objects that aren't treated specially. Instead of them, StaticClass instances - which we sometimes refer to as "Java type objects" are used as constructors with the new operator, and they expose static fields, properties, and methods. While this might seem confusing at first, it actually closely matches the Java language: you use a different expression (e.g. java.io.File) as an argument in "new" and to address statics, and it is distinct from the Class object (e.g. java.io.File.class). To get StaticClass object corresponding to a Java Class object, you can use "static" property. Below we cover in details the properties of the type objects.

Code Block
titleJava.type
 var arrayListType = Java.type("java.util.ArrayList")
 var intType = Java.type("int")
 var stringArrayType

...

load function

Loads and evaluates script from a file or a URL or a script object. Examples:

Code Block
titleload function
// can load script from files, URLs

load("foo.js"); // loads script from file "foo.js" from current directory
load("http://www.example.com/t.js"); // loads script file from given URL

// loads script from an object's properties. 

// Object should have "script" and "name" properties.
//     "script" property contains string code of the script. 
//     "name" property specifies name to be used while reporting errors from script
// This is almost like the standard "eval" except that it associates a name with
// the script string for debugging purpose.

load({ script: "print('hello')", name: "myscript.js"})

// load can also load from pseudo URLs like "nashorn:", "fx:". "nashorn:" pseudo URL scheme
// for nashorn's built-in scripts. "fx:" pseudo URL scheme for JavaFX support scripts

// load nashorn's parser support script - defines 'parse'
// function in global scope

load("nashorn:parser.js"); 

// load Mozilla compatibility script - which defines global functions
// like importPackage, importClass for rhino compatibility.

load("nashorn:mozilla_compat.js");

...

loadWithNewGlobal function

loadWithNewGlobal is almost like the function "load" in that it loads script from a file or a URL or a script object. But unlike 'load', loadWithNewGlobal creates a fresh ECMAScript global scope object and loads the script into it. The loaded script's global definitions go into the fresh global scope. Also, the loaded script's modifications of builtin objects (like String.prototype.indexOf) is not reflected in the caller's global scope – these are affected in the newly created global scope.

Code Block
titleloadWithNewGlobal
loadWithNewGlobal({
    script: "foo = 333; print(foo)",
    name: "test"
});

// prints undefined as "foo" is defined in the new global and not here
print(typeof foo); 

exit and quit functions

These synonymous functions exit the current process with specified (optional) exit code.

Code Block
titleexit
exit(1); // exit with given exit code
exit();  // exit 0
 
quit(2); // exit with given exit code
quit();  // exit 0

Packages, java, javax, javafx, com, edu, org

Packages and related objects are there to support java package, class access from script. The properties of the Packages variable are all the top-level Java packages, such as java and javax etc.

Code Block
titlePackages
var Vector = Packages.java.util.Vector;

// but short-cuts defined for important package prefixes like
//    Packages.java, Packages.javax, Packages.com
//    Packages.edu, Packages.javafx, Packages.org

var JFrame = javax.swing.JFrame;  // javax == Packages.javax
var List = java.util.List;        // java == Packages.java
Code Block
titlejjs session of Packages, classes
jjs> Packages.java
[JavaPackage java]
jjs> java
[JavaPackage java]
jjs> java.util.Vector
[JavaClass java.util.Vector]
jjs> javax
[JavaPackage javax]
jjs> javax.swing.JFrame
[JavaClass javax.swing.JFrame]

JavaImporter constructor

Many times you may want to import many Java packages – but without having to "pollute" global scope. JavaImporter helps in such situations.

Code Block
titleJavaImporter
// JavaImporter constructor accepts one or more Java Package objects
var imports = new JavaImporter(java.util, java.io);

// a JavaImporter can be used as a "with" expression object
with(imports) {
    // classes from java.util and java.io packages can 
    // can be accessed by unqualified names

    var map = new HashMap(); // refers to java.util.HashMap
    map.put("js", "javascript");
    map.put("java", "java");
    map.put("cpp", "c++");
    print(map);

    var f = new File("."); // refers to java.io.File
    print(f.getAbsolutePath());
}
Code Block
titleJavaImporter in 'with' statement example
// read text content from the given URL

function readText(url) {
    // Using JavaImporter to resolve classes
    // from specified java packages within the
    // 'with' statement below

    with (new JavaImporter(java.io, java.net)) {
        // more or less regular java code except for static types
        var is = new URL(url).openStream();
        try {
            var reader = new BufferedReader(
                new InputStreamReader(is));
            var buf = '', line = null;
            while ((line = reader.readLine()) != null) {
                buf += line;
            }
        } finally {
            reader.close();
        }
        return buf;
    }
}

print(readText("http://google.com?q=jdk8"))

Java object

"Java" global property is a script object that defines useful functions for script-to-Java interface.

Java.type function

Given a name of a Java type, returns an object representing that type in Nashorn. The Java class of the objects used to represent Java types in Nashorn is not Class but rather StaticClass. They are the objects that you can use with the new operator to create new instances of the class as well as to access static members of the class. In Nashorn, Class objects are just regular Java objects that aren't treated specially. Instead of them, StaticClass instances - which we sometimes refer to as "Java type objects" are used as constructors with the new operator, and they expose static fields, properties, and methods. While this might seem confusing at first, it actually closely matches the Java language: you use a different expression (e.g. java.io.File) as an argument in "new" and to address statics, and it is distinct from the Class object (e.g. java.io.File.class). To get StaticClass object corresponding to a Java Class object, you can use "static" property. Below we cover in details the properties of the type objects.

Code Block
titleJava.type
 var arrayListType = Java.type("java.util.ArrayList")
 var intType = Java.type("int")
 var stringArrayType = Java.type("java.lang.String[]")
 var int2DArrayType = Java.type("int[][]")
 
 // 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.:
  
 var anArrayList = new Java.type("java.util.ArrayList")
 
 // or

 var ArrayList = Java.type("java.util.ArrayList")
 var anArrayList = new ArrayList
 var anArrayListWithSize = new ArrayList(16)


 var BoolArray = Java.type("boolean[]");
 var arr = new BoolArray(10);
 arr[0] = true;

 // In the special case of inner classes, you can either use the JVM fully 
 // qualified name, meaning using $ sign in the class name, or you can
 // use the dot:

 var ftype = Java.type("java.awt.geom.Arc2D$Float")
 
 // and this works too:
  
 var ftype = Java.type("java.awt.geom.Arc2D.Float")

 // Java Class object to type:
 // similar to Java.type("java.util.Vector")

 var Class = Java.type("java.lang.ClassString[]")
 var VectorClassint2DArrayType = ClassJava.forNametype("java.util.Vectorint[][]")
 
 // Note varthat Vectorthe = VectorClass.static; 

If the type 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.:

Code Block
titlenew on abstract class
var TimerTask =  Java.type("java.util.TimerTask")
var task = new TimerTask({ run: function() { print("Hello World!") } })

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:

Code Block
titleanonymous class like expression
var task = new TimerTask {
    run: function() {
       print("Hello World!")
    }
}

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:

Code Block
titleSAM
 var task = new TimerTask(function() { print("Hello World!") })

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:

Code Block
titleSAM function conversion
 var Timer =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.:
  
 var anArrayList = new Java.type("java.util.ArrayList")
 
 // or

 var ArrayList = Java.type("java.util.ArrayList")
 var anArrayList = new ArrayList
 var anArrayListWithSize = new ArrayList(16)


 var BoolArray = Java.type("boolean[]");
 var arr = new BoolArray(10);
 arr[0] = true;

 // In the special case of inner classes, you can either use the JVM fully 
 // qualified name, meaning using $ sign in the class name, or you can
 // use the dot:

 var ftype = Java.type("java.awt.geom.Arc2D$Float")
 
 // and this works too:
  
 var ftype = Java.type("java.awt.geom.Arc2D.Float")

 // Java Class object to type:
 // similar to Java.type("java.util.TimerVector")

 var timerClass = new Timer()
 timer.schedule(function() { print("Hello World!") }, 1000)
 java.lang.System.in.read()

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.

...

Java.type("java.lang.Class")
 var VectorClass = Class.forName("java.util.Vector")
 var Vector = VectorClass.static; 

If the type 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.:

Code Block
titlenew on abstract class
var TimerTask =  

...

Java.extend function

Java.extend function 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. Note that you can also implement interfaces and subclass abstract classes using new operator on a type object for an interface or abstract class. However, to extend a non-abstract class, you will have to use this method. Example:

Code Block
titleJava.extend examples
var ArrayList = Java.type("java.util.ArrayListTimerTask")
var ArrayListExtender = Java.extend(ArrayList)
var printSizeInvokedArrayListtask = new ArrayListExtenderTimerTask() {
    sizerun: function() { print("sizeHello invokedWorld!"); }
}

var printAddInvokedArrayList })

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:

Code Block
titleanonymous class like expression
var task = new ArrayListExtender()TimerTask {
    addrun: function(x, y) {
       if(typeof(y) === "undefined") {print("Hello World!")
          print("add(e) invoked!");
      } else {
          print("add(i, e) invoked!");
      }
    }
}

...

}
}

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:

Code Block
titleSAM
 var task = new TimerTask(function() { print("Hello World!") })

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:

Code Block
titleSAM function conversion
 var Timer = Java.type("java.util.Timer")
 var timer = new Timer()
 timer.schedule(function() { print("Hello World!") }, 1000)
 java.lang.System.in.read()

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.

Anchor
java_extend
java_extend

Java.extend function

Java.extend function 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. Note that you can also implement interfaces and subclass abstract classes using new operator on a type object for an interface or abstract class. However, to extend a non-abstract class, you will have to use this method. Example:

Code Block
titleJava.extend examples
var ArrayList

...

Code Block
titleJava.extend - larger example
#// Usage: jjs javafoovars.js -- <directory>

// This example demonstrates Java subclassing by Java.extend
// and javac Compiler and Tree API. This example counts number
// of variables called "foo" in the given java source files!
if (arguments.length == 0) {
    print("Usage: jjs javafoovars.js -- <directory>");
    exit(1);
}

// Java types used
var File = Java.type("java.io.File");
var Files = Java.type("java.nio.file.Files");
var FileVisitOption = Java.type("java.nio.file.FileVisitOption");
var StringArray = Java.type("java.langutil.String[]ArrayList");
var ToolProviderArrayListExtender = Java.type("javax.tools.ToolProvider");extend(ArrayList)
var TreeprintSizeInvokedArrayList = new Java.type("com.sun.source.tree.Tree");
var TreeScanner = Java.type("com.sun.source.util.TreeScanner");
var VariableTree = Java.type("com.sun.source.tree.VariableTree");

// count "foo"-s in the given .java files
function countFoo(ArrayListExtender() {
    size: function() { print("size invoked!"); }
}

var printAddInvokedArrayList = new ArrayListExtender() {
    add: function(x, y) {
    // get the system compiler tool
 if(typeof(y) === "undefined") {
        var compiler = ToolProvider.systemJavaCompiler print("add(e) invoked!");
    // get standard} fileelse manager{
    var fileMgr    = compiler.getStandardFileManager(null, null, null print("add(i, e) invoked!");
     // Using}
 Java.to convert  }
}

Anchor
Java_extend_javac_example
Java_extend_javac_example

Code Block
titleJava.extend - larger example
#// Usage: jjs javafoovars.js -- <directory>

// This example demonstrates Java subclassing by Java.extend
// and javac Compiler and Tree API. This example counts number
// of variables called "foo" in the given java source files!
if (arguments.length == 0) {
    print("Usage: jjs javafoovars.js -- <directory>");
    exit(1);
}

// Java types used
var File = Java.type("java.io.File");
var Files = Java.type("java.nio.file.Files");
var FileVisitOption = Java.type("java.nio.file.FileVisitOption");
var StringArray = Java.type("java.lang.String[]");
var ToolProvider = Java.type("javax.tools.ToolProvider");
var Tree = Java.type("com.sun.source.tree.Tree");
var TreeScanner = Java.type("com.sun.source.util.TreeScanner");
var VariableTree = Java.type("com.sun.source.tree.VariableTree");

// count "foo"-s in the given .java files
function countFoo() {
    // get the system compiler tool
    var compiler = ToolProvider.systemJavaCompiler;
    // get standard file manager
    var fileMgr = compiler.getStandardFileManager(null, null, null);
    // Using Java.to convert script array (arguments) to a Java String[]
    var compUnits = fileMgr.getJavaFileObjects(
        Java.to(arguments, StringArray));
    // create a new compilation task
    var task = compiler.getTask(null, fileMgr, null, null, null, compUnits);
    // subclass SimpleTreeVisitor - to count variables called "foo"
    var FooCounterVisitor = Java.extend(TreeScanner);
    var fooCount = 0;

    var visitor = new FooCounterVisitor() {script array (arguments) to a Java String[]
    var compUnits = fileMgr.getJavaFileObjects(
        Java.to(arguments, StringArray));
    // create a new compilation task
    var task = compiler.getTask(null, fileMgr, null, null, null, compUnits);
    // subclass SimpleTreeVisitor - to count variables called "foo"
    var FooCounterVisitor = Java.extend(TreeScanner);
    var fooCount = 0;

    var visitor = new FooCounterVisitor() {
        visitVariable: function (node, p) {
            if (node.name.toString() == "foo") {
                fooCount++;
            }
        }
    }

    for each (var cu in task.parse()) {
        cu.accept(visitor, null);
    }
    return fooCount;
}

// for each ".java" file in directory (recursively) count "foo".
function main(dir) {
    var totalCount = 0;
    Files.walk(dir.toPath(), FileVisitOption.FOLLOW_LINKS).
      forEach(function(p) {
        var name = p.toFile().absolutePath;
        if (name.endsWith(".java")) {
            var count = 0;
        visitVariable: function   try(node, p) {
                count = countFoo(p.toFile().getAbsolutePath());
   if (node.name.toString() == "foo") {
         } catch (e) {
    fooCount++;
            print(e);}
        }
    }

    for each (var cu     if (count != 0in task.parse()) {
          cu.accept(visitor, null);
    }
    return  print(name + ": " + count);fooCount;
}

// for each ".java" file in directory (recursively) count "foo".
function main(dir) {
    var totalCount = 0;
     }
   Files.walk(dir.toPath(), FileVisitOption.FOLLOW_LINKS).
      forEach(function(p) {
        var totalCountname += countp.toFile().absolutePath;
        if  }
(name.endsWith(".java")) {
       });
    print("Total foovar count: " + totalCount);
}

main(new File(arguments[0]));

 

Java.from function

Given a Java array or Collection, this function 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. Example:

Code Block
titleJava.from examples
var File = Java.type("java.io.File")
var listHomeDir = new File("~").listFiles()

// Java array to JavaScript array conversion by Java.from
var jsListHome = Java.from(listHomeDir)

var jpegModifiedDates = jsListHome
    .filter(function(val) { return val.getName().endsWith(".jpg") })
    .map(function(val) { return val.lastModified() })

...

 = 0;
            try {
                count = countFoo(p.toFile().getAbsolutePath());
            } catch (e) {
                print(e);
            }
            if (count != 0) {
                print(name + ": " + count);
            }
            totalCount += count;
        }
      });
    print("Total foo count: " + totalCount);
}

main(new File(arguments[0]));

 

Java.from function

Given a Java array or Collection, this function 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

...

Java.to function

Given a script object and a Java type, converts the script object into the desired Java type. Currently it performs shallow creation of Java arrays, as well as wrapping of objects in Lists and Dequeues. Example:

Code Block
titleJava.to examplefrom examples
var anArrayFile = [1, "13", false]Java.type("java.io.File")
var listHomeDir = new File("~").listFiles()

// Java.to usedarray to convert scriptJavaScript array toconversion aby Java int array.from
var javaIntArrayjsListHome = Java.to(anArray, "int[]"from(listHomeDir)

var jpegModifiedDates = jsListHome
    .filter(function(val) { return val.getName().endsWith(".jpg") })
    .map(function(val) { return val.lastModified() })

Anchor
java_to
java_to

Java.to function

Given a script object and a Java type, converts the script object into the desired Java type. Currently it performs shallow creation of Java arrays, as well as wrapping of objects in Lists and Dequeues. Example:

Code Block
titleJava.to example
var anArray = [1, "13", false]

// Java.to used to convert script array to a Java int array
var javaIntArray = Java.to(anArray, "int[]")

print(javaIntArray[0])  // prints 1
print(javaIntArray[1])  // prints 13, as string "13" was converted to number 13 
                        //print(javaIntArray[0])  // prints 1
print(javaIntArray[1])  // prints 13, as string "13" was converted to number 13 
                        // as per ECMAScript ToNumber conversion
print(javaIntArray[2])  // prints 0, as boolean false was converted to number 0
                        // as per ECMAScript ToNumber conversion

...

Code Block
titleJava.extend and Java.super - larger example
#// Usage: jjs -fx filebrowser.js -- <start_dir>

// Uses -fx and javafx TreeView to visualize directories
if (!$OPTIONS._fx) {
    print("Usage: jjs -fx filebrowser.js -- <start_dir>");
    exit(1);
}

// Java classes used
var File = Java.type("java.io.File");
var Files = Java.type("java.nio.file.Files");

// check directory argument, if passed
var dir = arguments.length > 0? new File(arguments[0]) : new File(".");
if (! dir.isDirectory()) {
    print(dir + " is not a directory!");
    exit(2);
}

// JavaFX classes used
var FXCollections = Java.type("javafx.collections.FXCollections");
var Scene     = Java.type("javafx.scene.Scene");
var TreeItem  = Java.type("javafx.scene.control.TreeItem");
var TreeView  = Java.type("javafx.scene.control.TreeView");

// create a subclass of JavaFX TreeItem class
var LazyTreeItem = Java.extend(TreeItem);

// lazily filling children of a directory LazyTreeItem
function buildChildren(dir) {
    var children = FXCollections.observableArrayList();
    var stream = Files.list(dir.toPath());
    stream.forEach(function(path) {
        var file = path.toFile();
        var item = file.isDirectory()?
            makeLazyTreeItem(file) : new TreeItem(file.name);
        children.add(item);
    });
    stream.close();
    return children;
}

// create an instance LazyTreeItem with override methods
function makeLazyTreeItem(dir) {
    var item = new LazyTreeItem(dir.name) {
        expanded: false,
        isLeaf: function() false,
        getChildren: function() {
            if (! this.expanded) {
            getChildren: function() {
            if (! this.expanded) {
                // call super class (TreeItem) method
                Java.super(item).getChildren().setAll(buildChildren(dir));
                this.expanded = true;     // call super class (TreeItem) method
                Java.super(item).getChildren().setAll(buildChildren(dir));
                this.expanded = true;
            }
            // call super class (TreeItem) method
            return Java.super(item).getChildren();
        }
    }
    return item;
}

// JavaFX start method
function start(stage) {
    stage.title = dir.absolutePath;
    var rootItem = makeLazyTreeItem(dir);
    rootItem.expanded = true;
    var tree = new TreeView(rootItem);
    stage.scene = new Scene(tree, 300, 450);
    stage.show();
}

Anchor
Java_synchronized
Java_synchronized

Java.synchronized function

Returns synchronized wrapper version of the given ECMAScript function.

Code Block
languagejavascript
titleJava.synchronized example
var Thread = Java.type("java.lang.Thread");
var sum = 0;
var lock = {};

function run() {
    Thread.sleep(Math.floor(Math.random()*700) + 300);

    // create synchronized wrapper of given function
    // and use the second param as the synchronization lock
    Java.synchronized(function() sum++, lock)();
}

var threads = [];
for (var i = 0; i < 4; i++) {
    var t = new Thread(run);
    threads.push(t);
    t.start();
}

for (var i in threads) {
   threads[i].join();
}

// always prints 4
print(sum);

Anchor
Java.asJSONCompatible
Java.asJSONCompatible

Java.asJSONCompatible function

This function accepts a script object and returns an object that is compatible with Java JSON libraries expectations; namely, that if it itself, or any object transitively reachable through it is a JavaScript array,then such objects will be exposed as JSObject that also implements the List interface for exposing the array elements.

An explicit API is required as otherwise Nashorn exposes all objects externally as JSObjects that also implement the Map interface instead. By using this method, arrays will be exposed as Lists and all other objects as Maps.

This API is since jdk 8u60+ and jdk 9. A simple example that uses Java.asJSONCompatible function:

Code Block
languagejava
titleJava.asJSONCompatible example
import javax.script.*;
import java.util.*;
public class JSONTest {
    public static void main(String[] args) throws Exception {
        ScriptEngineManager m = new }ScriptEngineManager();
        ScriptEngine e =  // call super class (TreeItem) method
            return Java.super(item).getChildren();
        }m.getEngineByName("nashorn");
        Object obj = e.eval("Java.asJSONCompatible({ x: 343, y: 'hello', z: [2,4, 5] })");
        Map<String, Object> map = (Map<String, Object>)obj;
    }
    return item;
}

// JavaFX start method
function start(stage) {
    stage.title = dir.absolutePath;
    var rootItem = makeLazyTreeItem(dir);
    rootItem.expanded = true;
    var tree = new TreeView(rootItem);
    stage.scene = new Scene(tree, 300, 450);
    stage.show();System.out.println(map.get("x"));
        List<Object> array = (List<Object>)map.get("z");
        for (Object elem : array) {
            System.out.println(elem);
        }
    }
}

Special treatment of objects of specific Java classes

Anchor
map_as_object
map_as_object

Java Map keys as properties

...

Code Block
titlejava.util.Map keys as properties example
var HashMap = Java.type("java.util.HashMap")
var map = new HashMap()
// map key-value access by java get/put method calls
map.put('js', 'nashorn')
print(map.get('js'))
// access keys of map as properties
print(map['js'])
print(map.js)
// also assign new key-value pair 
// as 'property-value'
map['language'] = 'java'
print(map.get("language"))
print(map.language)
print(map['language'])
map.answer = 42
print(map.get("answer"))
print(map.answer)
print(map['answer'])['answer'])

Anchor
list_as_array
list_as_array

Java List element access/update via array index access/update syntax

Elements of java.util.List objects can be access as though those are array elements - array like indexed element access and update is supported. "length" property can be used on List objects to get size of the list.

Code Block
titleJava List elements via array index access
// Java List elements accessed/modified via
// array element access/update syntax
var ArrayList = Java.type("java.util.ArrayList")
var list = new ArrayList()
// add elements to list by List's add method calls
list.add("js")
list.add("ecmascript")
list.add("nashorn")
// get by List's get(int) method
print(list[0])
print(list[1])
print(list[2])
// access list elements by indexed access as well
print(list[0])
print(list[1])
print(list[2])
// assign to list elements by index as well
list[0] = list[0].toUpperCase()
list[1] = list[1].toUpperCase()
list[2] = list[2].toUpperCase()
print(list.get(0))
print(list.get(1))
print(list.get(2))
print(list[0])
print(list[1])
print(list[2])
print(list.length); // prints list.size()

Lambdas, SAM types and Script functions

...

Explicit constructor selection (jdk9, jdk8u65)

With jdk9 and jdk8u65, explicit constructor overload selection is also supported. See Index selection of overloaded java new constructors and Explicit constructor overload selection should work with StaticClass as well

Code Block
titleExplicit constructor selection (jdk9 only, jdk8u65)
// With jdk9, you can select a specific constructor as well.

var C = java.awt["Color(int,int,int)"];
print(new C(255, 0, 0);

var F = Java.type("java.io.File")["(String)"];
print(new F("foo.txt"));

...

If the command does not require any input, you can launch a process using the backtick string notation. For example, instead of $EXEC("ls -l"), you can use `ls -l`.

$OUT (-scripting mode only)

This global object is used to store the latest standard output (stdout) of the process spawned by $EXEC. For example, the result of $EXEC() is saved to $OUT.

$ERR (-scripting mode only)

This global object is used to store the latest standard error (stderr) of the process spawned by $EXEC.

-l`.

$OUT $EXIT (-scripting mode only)

This global object is used to store the exit code latest standard output (stdout) of the process spawned by $EXEC. If the exit code is not zero, then the process failedFor example, the result of $EXEC() is saved to $OUT.

Code Block
title$EXEC example with $OUT usage
var Arrays = Java.type("java.util.Arrays")

// use curl to download JSON weather data from the net
var str = `curl http://api.openweathermap.org/data/2.5/forecast/daily?q=Chennai&amp;mode=json&amp;units=metric&amp;cnt=7`

// parse JSON
var weather = JSON.parse($OUT)

// pull out humidity as array
var humidity = weather.list.map(function(curVal) {
    return curVal.humidity
})

// Stream API to print stat
print("Humidity")
print(Arrays["stream(int[])"](humidity).summaryStatistics())

// pull maximum day time temperature
var temp = weather.list.map(function(curVal) {
    return curVal.temp.max
})

// Stream API to print stat
print("Max Temperature")
print(Arrays["stream(double[])"](temp).summaryStatistics())

$ERR (-scripting mode only)

This global object is used to store the latest standard error (stderr) of the process spawned by $EXEC.

$EXIT (-scripting mode only)

This global object is used to store the exit code of the process spawned by $EXEC. If the exit code is not zero, then the process failed

$OPTIONS (-scripting mode only)

...

Nashorn  supports callsite tracing and profile jjs (jjs tool) options via command line options -tcs and -pcs. You can pass these to jjs tool or set these options via "nashorn.args" System property. But these options produce trace, profile output for all scripts that are run. To avoid having to look at too many much trace outputs output (or too big NashornProfile.txt file to scan!), nashorn allows per script or per function tracing, profiling via user directives.

You can include nashorn specific user directives (  directive prologues ) at the start of a source script or at the start of a script function as shown below:

...

profiling is enabled per script or per function only rather than globally. These nashorn directives are enabled only in nashorn debug mode. So, these are effective only when jjs is run  -J-Dnashorn.debug option set or script engine is initialized after "nashorn.debug" system property is set to true. Also, this feature is available only on jdk 8u40 + and jdk 9 only.