Pages

Friday, December 31, 2021

Java 8 Nashorn Javascript With Examples

1. Overview

In this tutorial, you will learn how to use javascript in java and how to integrate them with each other.

Usage of javascript in java can be done with the newly added Nashorn JavaScript engine in java 8.

This completely replaces the old version of the Rhino javascript engine and it gives 2 to 10 times better performance than the older one because it does the code compilation in memory and passes the byte code to the JVM directly.

And also it uses the dynamic loading feature is introduced in java 7 to enhance the performance and completely replaces the Rhino Engine.

Java 8 Nashorn Javascript


Let us start writing the examples using the code from the command line, java, and javascript code.

Note: Before using jjs tool,  you should remember that "The jjs tool is planned to be removed from a future JDK release"

2. Nashorn jjs - Command-Line Engine

JDK 1.8 is equipped with the command line interpreter that is called "jjs". jjs is used to run the javascript files as below.

jjs tool can be found at the location $JAVA_HOME/bin

jjs> jjs first_script.js

And also jjs can be used as interactive shells such as REPL. To start a REPL, do not pass any arguments to it.

javprogramto-MacBook-Pro-2$ jjs
Warning: The jjs tool is planned to be removed from a future JDK release
jjs> 
jjs> 

You can print the content on to console using print() method and it takes string content.

jjs> print("Hello World")
Hello World
jjs> print("welocome to javaprogramto.com blog for java 8 tutorial")
welocome to javaprogramto.com blog for java 8 tutorial
jjs> 

3. Running js file as a shell script

As you run the shell script file from the command line like "./hello.sh" in a similar way you can run the javascript file. 

Just add bang pointing to jjs location "#!$JAVA_HOME/bin/jjs"

Let us write a simple code and save it as hello.js file.

#!$JAVA_HOME/bin/jjs
var greeting = "Hello World, Welcome";
print(greeting);

Now, run this script from the command line with "./hello.js" and observe the below output.

$ ./hello.js
Warning: The jjs tool is planned to be removed from a future JDK release
Hello World, Welcome
$ 

Like this, you can use java code from the js file also. In the next, sections you will understand how to use java code in javascript files.

4. Passing Arguments to JJS

jjs command can work with the arguments also. When you use jjs command to start the interactive mode, you can pass as many as arguments you need.

And all of the passed arguments are stored in a variable "arguments". By using this builtin keyword in javascript, you can get all of these argument values.

Note: You need to pass the double hyphen "--" after jjs command.

Let us run the sample code as "jjs -- one two threee"

Arguments Example:

$ jjs -- one two threee
Warning: The jjs tool is planned to be removed from a future JDK release
jjs> print("given  argument  values are "+arguments.join(" , "))
given  argument  values are one , two , threee
jjs>$ 

5. Call JavaScript from Java

Java 8 api is added with a built-in engine that is called an Embedded Script Engine which creates a runtime environment to execute the javascript code on the JVM for a dynamic language.

Use ScriptEngineManager class to get the script engines that are managed by JVM.

Next, get the nashorn script engine using getEngineByName("nashorn") and pass the right name to it.

Finally, call eval() method to run the native javascript code from java and eval() returns an Object if you are executing arithmetic operations. In such cases, you need to use explicit type casting to the right object types. It is the time now to play with the javascript notations.

package com.javaprogramto.java8.nashorn;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

public class CallJavaScriptFromJavaExample {

    public static void main(String[] args) throws ScriptException {

        // creating java script engine
        ScriptEngineManager scriptEngineManager = new ScriptEngineManager();

        // getting the nashorn engine
        ScriptEngine nashorn = scriptEngineManager.getEngineByName("nashorn");

        // evaluating the javascript statement  to  print
        nashorn.eval("print('hello , this is first javascript example in java') ");

        // summing 2  numbers in  js  from  java code.
        Integer i = (Integer) nashorn.eval("1 + 2");
        
        System.out.println("sum from javascript : " + i);
    }
}
 

Output:

hello , this is first javascript example in java
sum from javascript : 3
 

You can observe the output that printed the content using the javascript print() method and the addition of two numbers.

6. Exceptions  from NashornScriptEngine

If you pass the invalid or wrong javascript syntax to eval() method then. it will throw a runtime exception saying "ScriptException" with different reasons.

If you miss the ending or closing quotes. for the print() method then it. will say "<eval> Missing close quote"

 Warning: Nashorn engine is planned to be removed from a future JDK release
 Exception in thread "main" javax.script.ScriptException: <eval>:1:57 Missing close quote
 pirnt('hello , this is first javascript example in java) 
                                                          ^ in <eval> at line number 1 at column number 57
 	at jdk.scripting.nashorn/jdk.nashorn.api.scripting.NashornScriptEngine.throwAsScriptException(NashornScriptEngine.java:477)
 	at jdk.scripting.nashorn/jdk.nashorn.api.scripting.NashornScriptEngine.compileImpl(NashornScriptEngine.java:544)
 	at jdk.scripting.nashorn/jdk.nashorn.api.scripting.NashornScriptEngine.compileImpl(NashornScriptEngine.java:531)
 	at jdk.scripting.nashorn/jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl(NashornScriptEngine.java:409)
 	at jdk.scripting.nashorn/jdk.nashorn.api.scripting.NashornScriptEngine.eval(NashornScriptEngine.java:162)
 	at java.scripting/javax.script.AbstractScriptEngine.eval(AbstractScriptEngine.java:264)
 	at com.javaprogramto.java8.nashorn.CallJavaScriptFromJavaExample.main(CallJavaScriptFromJavaExample.java:16)
 Caused by: jdk.nashorn.internal.runtime.ParserException: <eval>:1:57 Missing close quote
 pirnt('hello , this is first javascript example in java) 
                                                          ^
 	at jdk.scripting.nashorn/jdk.nashorn.internal.parser.Lexer.error(Lexer.java:1860)
 	at jdk.scripting.nashorn/jdk.nashorn.internal.parser.Lexer.scanString(Lexer.java:1006)
 	at jdk.scripting.nashorn/jdk.nashorn.internal.parser.Lexer.lexify(Lexer.java:1717)
 	at jdk.scripting.nashorn/jdk.nashorn.internal.parser.AbstractParser.getToken(AbstractParser.java:135)
 	at jdk.scripting.nashorn/jdk.nashorn.internal.parser.AbstractParser.nextToken(AbstractParser.java:216)
 	at jdk.scripting.nashorn/jdk.nashorn.internal.parser.AbstractParser.nextOrEOL(AbstractParser.java:173)
 	at jdk.scripting.nashorn/jdk.nashorn.internal.parser.AbstractParser.next(AbstractParser.java:160)
 	at jdk.scripting.nashorn/jdk.nashorn.internal.parser.Parser.scanFirstToken(Parser.java:293)
 	at jdk.scripting.nashorn/jdk.nashorn.internal.parser.Parser.parse(Parser.java:323)
 	at jdk.scripting.nashorn/jdk.nashorn.internal.parser.Parser.parse(Parser.java:285)
 	at jdk.scripting.nashorn/jdk.nashorn.internal.runtime.Context.compile(Context.java:1500)
 	at jdk.scripting.nashorn/jdk.nashorn.internal.runtime.Context.compileScript(Context.java:1467)
 	at jdk.scripting.nashorn/jdk.nashorn.internal.runtime.Context.compileScript(Context.java:750)
 	at jdk.scripting.nashorn/jdk.nashorn.api.scripting.NashornScriptEngine.compileImpl(NashornScriptEngine.java:542)
 	... 5 more
 

If you pass the invalid method name then it will give an error.

nashorn.eval("invoke(10, 20)");
 

Error:

Warning: Nashorn engine is planned to be removed from a future JDK release
Exception in thread "main" javax.script.ScriptException: ReferenceError: "invoke" is not defined in <eval> at line number 1
	at jdk.scripting.nashorn/jdk.nashorn.api.scripting.NashornScriptEngine.throwAsScriptException(NashornScriptEngine.java:477)
	at jdk.scripting.nashorn/jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl(NashornScriptEngine.java:461)
	at jdk.scripting.nashorn/jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl(NashornScriptEngine.java:413)
	at jdk.scripting.nashorn/jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl(NashornScriptEngine.java:409)
	at jdk.scripting.nashorn/jdk.nashorn.api.scripting.NashornScriptEngine.eval(NashornScriptEngine.java:162)
	at java.scripting/javax.script.AbstractScriptEngine.eval(AbstractScriptEngine.java:264)
	at com.javaprogramto.java8.nashorn.CallJavaScriptFromJavaExample.main(CallJavaScriptFromJavaExample.java:18)
Caused by: <eval>:1 ReferenceError: "invoke" is not defined
	at jdk.scripting.nashorn/jdk.nashorn.internal.runtime.ECMAErrors.error(ECMAErrors.java:57)
	at jdk.scripting.nashorn/jdk.nashorn.internal.runtime.ECMAErrors.referenceError(ECMAErrors.java:319)
	at jdk.scripting.nashorn/jdk.nashorn.internal.runtime.ECMAErrors.referenceError(ECMAErrors.java:291)
	at jdk.scripting.nashorn/jdk.nashorn.internal.objects.Global.__noSuchProperty__(Global.java:1616)
	at jdk.scripting.nashorn.scripts/jdk.nashorn.internal.scripts.Script$Recompilation$1$\^eval\_/0x00000008001dc040.:program(<eval>:1)
	at jdk.scripting.nashorn/jdk.nashorn.internal.runtime.ScriptFunctionData.invoke(ScriptFunctionData.java:655)
	at jdk.scripting.nashorn/jdk.nashorn.internal.runtime.ScriptFunction.invoke(ScriptFunction.java:513)
	at jdk.scripting.nashorn/jdk.nashorn.internal.runtime.ScriptRuntime.apply(ScriptRuntime.java:527)
	at jdk.scripting.nashorn/jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl(NashornScriptEngine.java:456)
	... 5 more
 

7. Call Java From JavaScript

In the previous section,  we. have seen how to call native javascript code from java classes. 

Next, let us see how to use java classes in JavaScript files.

Let us create a sample javascript code that uses the java class BigDecimal.

Call Java.type() method to use the java classes from javascript and pass the class name along with the package name. Then that class is loaded into the nashorn engine and returns its object. So, we've stored it in the var variable.

Calling Java Methods from JavaScript Example:

var BigDecimalClass = Java.type('java.math.BigDecimal');

function calculate(amount, percentage) {

    var result = new BigDecimalClass(amount).multiply(new BigDecimalClass(percentage)).divide(
        new BigDecimalClass("100"), 2, BigDecimalimalClass.ROUND_HALF_EVEN);

    return result.toPlainString();
}
var result = calculate(1000,20);
print("Final value : "+result);
 

Output:

$ jjs sample.js 
Final value : 200.00
$ 
 

Any java class can be used inside the javascript code such as adding key-value pairs. to HashMap.

Save the below file as hashmap.js

Example to use HashMap from Javascript:

var HashMap = Java.type('java.util.HashMap')
var map = new HashMap()
map.put('hello', 'world')
print("map values : "+map)
 

Output:

$ jjs hashmap.js 
map values : {hello=world}
$ 
 

8. Conclusion

In this article,  you've seen the new javascript engine nashorn added in java 8.

Examples on how to call javascript from java and vice versa.

Now, you can call javascript functions, pass bindings, and use java objects from both languages using jjs tool.

All examples shown are over GitHub.

Examples of Nashorn engine on GitHub

Removal of Nashorn

ScriptEngine API

No comments:

Post a Comment

Please do not add any spam links in the comments section.