Javascript inside Java

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: