我是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对象从脚本引用为属性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中是否可以这样?
非常感谢。
答案 0 :(得分:1)
好吧,在JavaScript中,只考虑在被调用函数的上下文中设置this
才有意义。因此,我认为您应该能够在ScriptEngine上使用“invoke”方法(必须将其强制转换为“Invocable”):
((Invocable) engine).invokeMethod(objectForThis, "yourFunction", arg, arg ...);
现在,“objectForThis”引用(根据我的经验)通常是先前调用“eval()”(或“invokeMethod”)返回的内容;换句话说,它应该是脚本引擎的适当语言中的对象。无论你是否可以在那里传递一个Java对象(并让它成功),我都不确定。
答案 1 :(得分:1)
我尝试从Pointy的回答中实现this idea(再次感谢),但这种解决方法不适用于没有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
没有?忽略了一些观点?尖?