javascript Rhino:如何将 Java 对象传递给脚本,其中可以引用为“this”
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6709542/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Rhino: How to pass Java object to script, where can be referenced as "this"
提问by mschayna
I am new to JSR-223 Java Scripting, actually I'm switching from MVELto 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:
我是 JSR-223 Java Scripting 的新手,实际上我正在从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 is referenced from script as property bean
. So far so good.
Java 对象作为属性从脚本中引用bean
。到现在为止还挺好。
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:
但是我想在脚本中引用我的对象作为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)");
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
.
我知道this
在 JavaScript 中具有特殊含义(如在 Java 中)但在 MVEL 脚本中可以通过使用 customParserContext
和 custom来完成PropertyHandler
。
Is something like this possible in Rhino?
在 Rhino 中可能有这样的事情吗?
Thanks a lot.
非常感谢。
采纳答案by Pointy
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"):
好吧,在 JavaScript 中,考虑this
在被调用的函数的上下文中进行设置才真正有意义。因此,我认为您应该能够在 ScriptEngine 上使用“invoke”方法(必须将其转换为“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.
现在,“objectForThis”引用(根据我的经验)通常是从先前调用“eval()”(或我猜是“invokeMethod”)返回的;换句话说,它应该是脚本引擎的适当语言的对象。你是否可以在那里传递一个 Java 对象(并让它解决),我不确定。
回答by mschayna
I try to implement this ideafrom 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:
我尝试从 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");
}
}
Why this.getStringValue()/this.stringValue
works and getStringValue()/stringValue
doesn't? Have some point overlooked? Pointy?
为什么this.getStringValue()/this.stringValue
有效而getStringValue()/stringValue
无效?是否忽略了某些点?尖?