繁体   English   中英

Rhino:如何将Java object传递给脚本,这里可以引用为“this”

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

我是 JSR-223 Java 脚本的新手,实际上我正在从MVEL切换到标准Mozilla Rhino JS 我已阅读所有文档,但卡住了。 我试图通过绑定从脚本中引用一些 Java 对象,就像在教程中一样:

    // 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 从脚本中引用为属性bean 到目前为止,一切都很好。

但是我想在脚本中引用我的 object 作为this ,我想使用它的属性和方法而不带任何前缀或明确地使用前缀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)");

我知道this在 JavaScript 中具有特殊含义(如在 Java 中),但在 MVEL 脚本中可以通过使用自定义ParserContext和自定义PropertyHandler来完成。

在 Rhino 中是否有可能发生这样的事情?

非常感谢。

好吧,在 JavaScript 中,考虑在调用 function this上下文中设置它才有意义。 因此,我认为您应该能够在 ScriptEngine 上使用“invoke”方法(必须将其转换为“Invocable”):

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

现在“objectForThis”引用(根据我的经验)通常是从先前调用“eval()”(或者我猜是“invokeMethod”)返回的东西; 换句话说,它应该是一个 object,采用适合脚本引擎的语言。 您是否可以在那里传递 Java object (并解决问题),我不确定。

我尝试从 Pointy 的回答中实现这个想法(再次感谢),但是这种解决方法不适用于没有this前缀的属性,恕我直言,这似乎是相同的。 而不是使用来自 Java API 的 Rhino 1.5,而是来自 Mozilla 的原始 Rhino 1.7。 测试用例在这里:

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");
  }
}

为什么this.getStringValue()/this.stringValue有效而getStringValue()/stringValue无效? 有没有忽略一些要点? 尖尖的?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM