I recently ran into a situation where we wanted to provide extensibility to end-users without development team getting involved – think you are writing a generic framework where you want to provide ability to users to receive a Java object & produce different output formats & pass back the resulting object to Java. The formats users want to produce could be different for each use-case, if there was only one format, you could code it up in factory – no problem, but when users want to format it entirely different based on whatever it is they wanted – we figured it’d be wonderful to allow users to write their Javascript code, drop in their files & pass back & forth objects.
We are still in the middle of designing things – I may write back more once done, but here’s a quick hack prototype of how to create an object instance in Java, pass it to Javascript & interact with that object as a javascript object. I’ll provide two code samples – one for omnipresent “Person” & other one for actually pulling a JSON response by making an HTTP call & dealing with response as a JSON object in Javascript (while running inside JVM)
Example 1: Using a Java object in Javascript
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
public class JavaToJavaScript {
static public class Person {
private String first_name;
private String last_name;
public Person() {
}
public Person(String f, String l) {
first_name = f;
last_name=l;
}
public String getFirstName() {
return first_name;
}
public String getLastName() {
return last_name;
}
public String toString() {
return first_name + " " + last_name;
}
}
public static void main(String... args) {
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("nashorn");
Person james = new Person("James", "Bond");
String script = "var jsInstance = passedFromJava;"
.concat("var fname = jsInstance.getFirstName();")
.concat("var lname = jsInstance.getLastName();")
.concat("print ('Person object set in Java but accessed from Javascript: ' + fname + ' ' + lname)");
try {
engine.put("passedFromJava", james);
engine.eval(script);
}
catch (Exception e){
System.out.println(e.getMessage());
}
}
}
Example 2: Using HTTP response from a URL in Javascript
(URL used in this example has usage limits, don’t run it multiple times … I have not dealt with error handling – whatsoever!)
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.stream.Collectors;
public class JavaToJavaScript2 {
public static void main(String... args) {
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("nashorn");
String response;
String url = "http://api.geonames.org/postalCodeLookupJSON?postalcode=6600&country=AT&username=demo";
try {
InputStreamReader is = new InputStreamReader(new URL(url).openStream());
BufferedReader reader = new BufferedReader(is);
response = reader.lines().collect(Collectors.joining());
engine.put("response", response);
System.out.println(engine.eval("var obj = JSON.parse(response); print(obj.postalcodes[0].placeName);"));
}
catch (Exception e){
System.out.println(e.getMessage());
}
}
}
References:
- Nashorn Javadocs
- Practical Nashorn: (By: Przemyslaw Piotrowski)