diff --git a/10-nashorn.md b/10-nashorn.md index 4c3215e..c525c73 100644 --- a/10-nashorn.md +++ b/10-nashorn.md @@ -3,12 +3,29 @@ Nashorn: Run JavaScript on the JVM ![Nashorn](https://upload.wikimedia.org/wikipedia/commons/7/7a/Dortmunder_Nashorn_-_Hell_wieherte_der_Hippogryph.jpg) -Nashorn is a high-performance JavaScript runtime written in Java for the JVM. It allows developers to embed JavaScript code inside their Java applications and even use Java classes and methods from their JavaScript code. You can think it as an alternative to Google's V8 JavaScript engine. It is a successor to Rhino JavaScript runtime which came bundled with earlier JDK versions. Nashorn is written from scratch using new language features like JSR 292(Supporting Dynamically Typed Languages) and `invokedynamic`. +Nashorn is a high-performance JavaScript runtime written in Java for the JVM. It +allows developers to embed JavaScript code inside their Java applications and +even use Java classes and methods from their JavaScript code. You can think it +as an alternative to Google's V8 JavaScript engine. It is a successor to Rhino +JavaScript runtime which came bundled with earlier JDK versions. Nashorn is +written from scratch using new language features like JSR 292(Supporting +Dynamically Typed Languages) and `invokedynamic`. From the Nashorn documentation: -> Nashorn uses invokedynamic to implement all of its invocations. If an invocation has a Java object receiver, Nashorn attempts to bind the call to an appropriate Java method instead of a JavaScript function. Nashorn has full discretion about how it resolves methods. As an example, if it can't find a field in the receiver, it looks for an equivalent Java Bean method. The result is completely transparent for calls from JavaScript to Java. -Currently, Nashorn supports [ECMAScript 5.1 specification](http://www.ecma-international.org/ecma-262/5.1/) and work is in progress to support [ECMAScript 6](http://www.ecma-international.org/ecma-262/6.0/) as well. Few ECMAScript 6 features like `let` and `const` are available in latest JDK 8 updates(40 and above) and we will cover them later in this chapter. +> Nashorn uses invokedynamic to implement all of its invocations. If an +> invocation has a Java object receiver, Nashorn attempts to bind the call to an +> appropriate Java method instead of a JavaScript function. Nashorn has full +> discretion about how it resolves methods. As an example, if it can't find a +> field in the receiver, it looks for an equivalent Java Bean method. The result +> is completely transparent for calls from JavaScript to Java. + +Currently, Nashorn supports [ECMAScript 5.1 +specification](http://www.ecma-international.org/ecma-262/5.1/) and work is in +progress to support [ECMAScript +6](http://www.ecma-international.org/ecma-262/6.0/) as well. Few ECMAScript 6 +features like `let` and `const` are available in latest JDK 8 updates(40 and +above) and we will cover them later in this chapter. In this chapter, we will cover the following: @@ -23,15 +40,21 @@ In this chapter, we will cover the following: ## Working with Nashorn command-line -JDK 8 comes bundled with two command-line tools that can be used to work with Nashorn engine. These two command-line tools are `jrunscript` and `jjs`. `jjs` is recommended to be used when working with Nashorn so we will only discuss it. To use `jjs`, you have to add `jjs` to the path. On *nix machines, you can do that adding a symbolic link as shown below. +JDK 8 comes bundled with two command-line tools that can be used to work with +Nashorn engine. These two command-line tools are `jrunscript` and `jjs`. `jjs` +is recommended to be used when working with Nashorn so we will only discuss it. +To use `jjs`, you have to add `jjs` to the path. On *nix machines, you can do +that adding a symbolic link as shown below. ```bash $ cd /usr/bin $ ln -s $JAVA_HOME/bin/jjs jjs ``` + Windows users can add `$JAVA_HOME/bin` to the path for easy access. -Once you have set the symbolic link you can access `jjs` from your terminal. To check version of `jjs`, run the following command. +Once you have set the symbolic link you can access `jjs` from your terminal. To +check version of `jjs`, run the following command. ```bash $ jjs -v @@ -39,7 +62,8 @@ nashorn 1.8.0_60 jjs> ``` -It will render the version and then show `jjs>` prompt. You can view the full version of `jjs` by using `jjs -fv` command. +It will render the version and then show `jjs>` prompt. You can view the full +version of `jjs` by using `jjs -fv` command. To quit the `jjs` shell, you can use `Ctrl-C`. @@ -65,7 +89,8 @@ jjs> add(5,10) ## Accessing Java classes and methods -It is very easy to access Java classes from within Nashorn. Assuming you are inside the `jjs` shell, you can create an instance of HashMap as shown below. +It is very easy to access Java classes from within Nashorn. Assuming you are +inside the `jjs` shell, you can create an instance of HashMap as shown below. ```bash jjs> var HashMap = Java.type("java.util.HashMap") @@ -78,23 +103,29 @@ jjs> userAndAge.get("shekhar") 32 ``` -In the code shown above we have used `Java` global object to create HashMap object. `Java` global object has `type` method that takes a string with the fully qualified Java class name, and returns the corresponding `JavaClass` function object. +In the code shown above we have used `Java` global object to create HashMap +object. `Java` global object has `type` method that takes a string with the +fully qualified Java class name, and returns the corresponding `JavaClass` +function object. ```bash jjs> HashMap [JavaClass java.util.HashMap] ``` -The `var userAndAge = new HashMap()` is used to instantiate `java.util.HashMap` class using the `new` keyword. +The `var userAndAge = new HashMap()` is used to instantiate `java.util.HashMap` +class using the `new` keyword. -You can access values by either calling the `get` method or using the `[]` notation as shown below. +You can access values by either calling the `get` method or using the `[]` +notation as shown below. ```bash jjs> userAndAge["shekhar"] 32 ``` -Similarly, you can work with other Java collections. To use an `ArrayList` you will write code as shown below. +Similarly, you can work with other Java collections. To use an `ArrayList` you +will write code as shown below. ```bash jjs> var List = Java.type("java.util.ArrayList") @@ -113,7 +144,8 @@ rahul ### Accessing static methods -To access static methods you have to first get the Java type using `Java.type` method and then calling method on `JavaClass` function object. +To access static methods you have to first get the Java type using `Java.type` +method and then calling method on `JavaClass` function object. ```bash jjs> var UUID = Java.type("java.util.UUID") @@ -135,7 +167,10 @@ jjs> ## Using external JavaScript libraries -Let's suppose we want to use an external JavaScript library in our JavaScript code. Nashorn comes up with a built-in function -- `load` that loads and evaluates a script from a path, URL, or script object. To use `lodash` library we can write code as shown below. +Let's suppose we want to use an external JavaScript library in our JavaScript +code. Nashorn comes up with a built-in function -- `load` that loads and +evaluates a script from a path, URL, or script object. To use `lodash` library +we can write code as shown below. ``` jjs> load("https://raw.github.com/lodash/lodash/3.10.1/lodash.js") @@ -146,7 +181,9 @@ jjs> _.map([1, 2, 3], function(n) { return n * 3; }); ## Writing scripts -You can use Nashorn extensions that enable users to write scripts that can use Unix shell scripting features. To enable shell scripting features, you have to start `jjs` with `-scripting` option as shown below. +You can use Nashorn extensions that enable users to write scripts that can use +Unix shell scripting features. To enable shell scripting features, you have to +start `jjs` with `-scripting` option as shown below. ```bash jjs -scripting @@ -155,7 +192,9 @@ jjs> Now you have access to Nashorn shell scripting global objects. -**$ARG:** This global object can be used to access the arguments passed to the script +**$ARG:** This global object can be used to access the arguments passed to the +script + ``` $ jjs -scripting -- hello hey jjs> @@ -182,7 +221,9 @@ jjs> $EXEC("pwd") ### Writing executable scripts -You can use shebang(#!) at the beginning of the script to make a script file run as shell executable. Let's write a simple script that reads content of a file. We will use Java's `Files` and `Paths` API. +You can use shebang(#!) at the beginning of the script to make a script file run +as shell executable. Let's write a simple script that reads content of a file. +We will use Java's `Files` and `Paths` API. ```javascript #!/usr/bin/jjs @@ -201,7 +242,9 @@ $ jjs ch10/lines.js -- README.md ## Using Nashorn from Java code -To use Nashorn from inside Java code, you have to create an instance of ScriptEngine from `ScriptEngineManager` as shown below. Once you have `ScriptEngine` you can evaluate expressions. +To use Nashorn from inside Java code, you have to create an instance of +ScriptEngine from `ScriptEngineManager` as shown below. Once you have +`ScriptEngine` you can evaluate expressions. ```java import javax.script.ScriptEngine; @@ -219,7 +262,6 @@ public class NashornExample1 { } ``` - Using bindings ```java @@ -247,7 +289,9 @@ public class NashornExample2 { ## Using Java 8 features like Streams and Lambdas inside JavaScript code -Java 8 supports lambdas and many API in JDK make use of them. Every collection in Java has `forEach` method that accepts a consumer. Consumer is an interface with one method. In Java, you can write following: +Java 8 supports lambdas and many API in JDK make use of them. Every collection +in Java has `forEach` method that accepts a consumer. Consumer is an interface +with one method. In Java, you can write following: ```java Arrays.asList("shekhar","rahul","sameer").forEach(name -> System.out.println(name)); @@ -257,7 +301,8 @@ Arrays.asList("shekhar","rahul","sameer").forEach(name -> System.out.println(nam // sameer ``` -In Nashorn, you can use them same API but you will pass JavaScript function instead as shown below. +In Nashorn, you can use them same API but you will pass JavaScript function +instead as shown below. ```javascript jjs> var Arrays = Java.type("java.util.Arrays") @@ -283,7 +328,8 @@ sameer ## Turning off Java language access -In case you need to disallow Java usage, you can very easily turn off by passing `--no-java` option to `jjs` as shown below. +In case you need to disallow Java usage, you can very easily turn off by passing +`--no-java` option to `jjs` as shown below. ``` → jjs --no-java