Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Making A Javascript Function Available To Java Code

Problem Description

A somewhat contrived example to illustrate my question. Imagine we have some library of javascript functions that is already maintained and updated daily by an army of frontend devs. To be specific, imagine one such function looks like this:

function employeesForStore(store) {
    var dictionary = {
        "downtown": ["Joe", "Mary", "Steve"],
        "uptown": ["Jules", "Vincent", "Matt"],
        // and so on for hundreds of locations
    };
    return dictionary[store];
}

NOTE: Please ignore the details of this function's implementation. The actual function may be far more complex than simple JSON dictionary lookups, and assume we don't know any implementation details about the js function. All we know is it takes a String argument and returns and array of Strings.

Now we would like to take advantage of this function in our Java code. That is, in our Java code, we'd like to "load" this function, and then be able to call it multiple times, passing it String args and receiving String[] or ArrayList<String> results.

From searching SO and google so far, I understand that this will involve using:

  • javax.script.ScriptEngineManager
  • javax.script.ScriptEngine
  • and perhaps scriptEngine.getContext() for passing values into the function and receiving results.

I am a bit hazy on the details of the above, especially since most examples I've found involve running javascript code a single time, rather than making javascript function available to Java.

Example Code I'd Like To See

  1. Assuming the js function is in the file "my_functions.js", load that file into Java so all of its functions will be available for use.
  2. Call employeesForStore("downtown") and store its results in a native java String[] or List<String> in a variable called downtownResults.
  3. Same as 2, but call employeesForStore("uptown") and store in variable uptownResults
like image 430
Jonah Avatar asked Apr 24 '13 12:04

Jonah


People also ask

Can Java call a JavaScript function?

Calling a JavaScript source in Java is pretty simple. If we develop a Java application in which we must use JavaScript, we will create the script file separately, then include and call it in the Java source to run the desired function.

How do I connect JavaScript to Java?

We'll connect JavaScript to Java by creating a new instance of a Java class using the JavaScript new keyword. Example 1 shows a function named browse() that opens a native "file dialog" using the built-in java. awt. Frame and java.

How do you write a JavaScript function in Java class?

getEngineByName("JavaScript"); // JavaScript code in a String String script1 = "function hello(name) {print ('Hello, ' + name);}"; String script2 = "function getValue(a,b) { if (a===\"Number\") return 1; else return b;}"; // evaluate script engine.

Can Java and JavaScript work together?

JavaScript also includes functions to control Java applets, and Java applets can access JavaScript functions. By integrating these two Web languages, you can have the best of both worlds, allowing for many complicated applications.


1 Answers

Create an interface to act as a facade to your JavaScript code.

Here is an example using the Rhino implementation embedded in Oracle's Java 1.7 implementation:

package demo;
import java.io.*; import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import javax.script.*;

public class StoreData {
  public static interface Stores {
    public String[] employees(String store);
  }

  public static Stores stores() throws IOException, ScriptException {
    ScriptEngineManager sem = new ScriptEngineManager();
    ScriptEngine engine = sem.getEngineByName("JavaScript");
    AtomicReference<Stores> ref = new AtomicReference<>();
    engine.put("ref", ref);
    String adapt = "ref.set("
        + "new Packages.demo.StoreData.Stores({employees:employeesForStore})"
        + ");";
    try (Reader myFns = new FileReader("my_functions.js")) { // TODO encoding
      engine.eval(myFns);
      engine.eval(adapt);
      return ref.get();
    }
  }

  public static void main(String[] args) throws IOException, ScriptException {
    List<String> employees = Arrays.asList(stores().employees("uptown"));
    System.out.println(employees);
  }
}

By specifying an interface we let Rhino coerce the JavaScript types to Java types (String, String[], etc.)

The JRE spec makes no guarantees about what scripting engines should be provided so it may be wise to rely on an external engine. I don't know if Nashorn will change this.

like image 74
McDowell Avatar answered Oct 04 '22 21:10

McDowell