Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 67 additions & 21 deletions 10-nashorn.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:

Expand All @@ -23,23 +40,30 @@ 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
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`.

Expand All @@ -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")
Expand All @@ -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")
Expand All @@ -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")
Expand All @@ -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")
Expand All @@ -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
Expand All @@ -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>
Expand All @@ -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
Expand All @@ -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;
Expand All @@ -219,7 +262,6 @@ public class NashornExample1 {
}
```


Using bindings

```java
Expand Down Expand Up @@ -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));
Expand All @@ -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")
Expand All @@ -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
Expand Down