javascriptjavaembedrhino

How to invoke Rhino compiled JavaScript methods (class files) in the Java program?


I compiled following JavaScript file, "test.js", into the "test.class" :

var test = (function () {
  var that = {};

  that.addNumbers = function (a, b) {
    return a+b;
  };

  return that;
}());

I would like to call the compiled JavaScript function, "test.addNumbers(1,2)", in the simple Java program "run.java" as follows :

public class run {

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

    Context cx = Context.enter();
    
    try {
      Scriptable scope = cx.initStandardObjects();
    
      // HOW TO CALL THE METHOD, Test.addNumbers(1,2)?  Please help me!
        
    } finally {
      Context.exit();
    }
  }
}

I tried many ways, but failed. I read Rhino tutorial and examined many articles and examples, BUT they only show how to call JavaScript methods from the command line or the source file, "test.js". I need to call the method from the compiled "test.class" file.


Solution

  • Using javap, I believe that the JavaScript type test does not mean that the resultant Java type is this class. The generated Java type invokes the script code in its constructor; this will not result in exposing addNumbers as a Java method.

    >javap -classpath . test
    public class test extends org.mozilla.javascript.NativeFunction implements org.m
    ozilla.javascript.Script{
        public test(org.mozilla.javascript.Scriptable, org.mozilla.javascript.Contex
    t, int);
        public test();
        public static void main(java.lang.String[]);
        public final java.lang.Object exec(org.mozilla.javascript.Context, org.mozil
    la.javascript.Scriptable);
        public final java.lang.Object call(org.mozilla.javascript.Context, org.mozil
    la.javascript.Scriptable, org.mozilla.javascript.Scriptable, java.lang.Object[])
    ;
        public int getLanguageVersion();
        public java.lang.String getFunctionName();
        public int getParamCount();
        public int getParamAndVarCount();
        public java.lang.String getParamOrVarName(int);
        public java.lang.String getEncodedSource();
        public boolean getParamOrVarConst(int);
    }
    

    Reading between the lines, I'd say you need to map to Java types to do what you want. From the jsc doc:

    -implements java-intf-name

    Specifies that a java class implementing the Java interface java-intf-name should be generated from the incoming JavaScript source file. Each global function in the source file is made a method of the generated class, implementing any methods in the interface by the same name.

    Define this interface:

    //Adder.java
    public interface Adder {
      public int addNumbers(int a, int b);
    }
    

    Write this implementation:

    //AdderImpl.js
    function addNumbers(a, b) {
      return a+b;
    }
    

    Compile the JavaScript with the arguments -implements Adder AdderImpl.js. Invoke the method like so:

    Adder adder = new AdderImpl();
    int n = adder.addNumbers(1, 2);
    System.out.println(n);
    

    I'd hazard a guess that it was probably necessary to do it this way because of differences in the languages' type systems.

    I used Rhino 1.7R2. For the sake of brevity, I've avoided using packages, etc.