Rhino:如何将 Java 对象传递给脚本,其中可以引用“this”

发布于 2024-11-23 22:12:44 字数 1493 浏览 2 评论 0原文

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

但我想在脚本中将我的对象引用为 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)");

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

Rhino 中可能有这样的事情吗?

非常感谢。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

ι不睡觉的鱼゛ 2024-11-30 22:12:44

我尝试实现 这个想法来自 Pointy 的回答(再次感谢),但是这个解决方法不适用于没有 this 前缀的属性,恕我直言,这似乎是非常一样。 Mozilla 没有使用来自 Java API 的 Rhino 1.5,而是使用原始的 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 无效?是否忽略了某些点?尖尖的?

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?

我爱人 2024-11-30 22:12:44

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

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

现在“objectForThis”引用(根据我的经验)通常是从先前调用返回的东西到“eval()”(或者我猜是“invokeMethod”);换句话说,它应该是脚本引擎适当语言的对象。我不确定是否可以在那里传递一个 Java 对象(并让它发挥作用)。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文