Rhino: How to pass Java object to script, where can be referenced as “this”

安稳与你 提交于 2019-12-05 04:51:19

问题


I am new to JSR-223 Java Scripting, actually I'm switching from MVEL to standard Mozilla Rhino JS. I have read all documentation, but get stuck. I have tried to reference some Java objects from script by bindings just like in tutorial:

    // my object
    public class MyBean {
       public String getStringValue() { return "abc" };
    }

    // initialization
    ScriptEngineManager manager = new ScriptEngineManager();
    ScriptEngine engine = manager.getEngineByName("JavaScript");

    // add bindings
    engine.put("bean", new MyBean());

    // evaluate script, output is "abc"
    engine.eval("print(bean.stringValue)");

Java object is referenced from script as property bean. So far so good.

But I want to reference my object in script as this, I want to use its properties and methods without any prefix or explicitely with prefix this. Just like this:

    // add bindings
    engine.put(....., new MyBean()); // or whatever ???

    // evaluate scripts, all have the same output "abc"
    engine.eval("print(stringValue)");
    engine.eval("print(this.stringValue)");

I know that this in JavaScript has special meaning (as in Java) but in MVEL scripting that could be done by using custom ParserContext and custom PropertyHandler.

Is something like this possible in Rhino?

Thanks a lot.


回答1:


Well, in JavaScript it really only makes sense to think about this being set in the context of a function being invoked. Thus I think you should be able to use the "invoke" method on the ScriptEngine (which has to be cast to "Invocable"):

  ((Invocable) engine).invokeMethod(objectForThis, "yourFunction", arg, arg ...);

Now the "objectForThis" reference is (in my experience) generally something that was returned from a prior call to "eval()" (or "invokeMethod" I guess); in other words, it's supposed to be an object in the appropriate language for the script engine. Whether you could pass in a Java object there (and have it work out), I don't know for sure.




回答2:


I try to implement this idea from answer from Pointy (thanks again), but this workaround doesn't work for properties without this prefix, which seems to be IMHO the very same. Instead of using Rhino 1.5 from Java API, there is original Rhino 1.7 from Mozilla. Test case is here:

import org.junit.Test;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.Function;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.ScriptableObject;
import org.mozilla.javascript.Wrapper;

public class RhinoTest2 {

  private Obj obj = new Obj();

  public class Obj {
    public String getStringValue() {
      return "abc";
    }
  }

  private Object eval(String expression) {
    Context cx = Context.enter();
    try {
      ScriptableObject scope = cx.initStandardObjects();

      // convert my "this" instance to JavaScript object  
      Object jsObj = Context.javaToJS(obj, scope);

      // prepare envelope function run()    
      cx.evaluateString(scope, 
        String.format("function run() { %s }", expression), 
        "<func>", 1, null);

      // call method run()
      Object fObj = scope.get("run", scope);
      Function f = (Function) fObj;
      Object result = f.call(cx, scope, (Scriptable) jsObj, null);
      if (result instanceof Wrapper)
        return ((Wrapper) result).unwrap();
      return result;

    } finally {
      Context.exit();
    }
  }

  @Test
  public void test() {

    // works
    eval("return this.getStringValue()");
    eval("return this.stringValue");

    // doesn't work, throws EcmaError: ReferenceError: "getStringValue" is not defined.
    eval("return getStringValue()");
    eval("return stringValue");
  }
}

Why this.getStringValue()/this.stringValue works and getStringValue()/stringValue doesn't? Have some point overlooked? Pointy?



来源:https://stackoverflow.com/questions/6709542/rhino-how-to-pass-java-object-to-script-where-can-be-referenced-as-this

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!