从 Java 传递的 Nashorn 和 'with' 上下文
Nashorn and 'with' context passed from Java
我正在为 nashorn
和 with
块而苦苦挣扎。我想用 HashMap
从 java 传递 'context' 并在我的代码中使用它。但是,我无法使它正常工作。
待评估JS
with(ctx) {
return a+b;
}
Java 映射为 "passed"
Map<Object, Object> ctx = new HashMap<>();
ctx.put("a", 5)
ctx.put("b", 5)
下面我准备了简短的 class 来演示我面临的错误。
public class Test {
public static void main(String[] args) throws ScriptException {
Map<Object, Object> ctx = new HashMap<>();
ctx.put("foo", 5);
eval("print('1st - :)'); ctx = {'foo':'bar'}; with(ctx) {print(foo);}", new HashMap<>());
// No exception with 'with', o seems to be properly 'in context'..
eval("print('2nd - :)'); var o = {}; print(o); with(Object.bindProperties(o, ctx)) { print(o); } print(o)", ctx);
try {
// ..But it is not
eval("print('3rd - :('); var o = {}; with(Object.bindProperties(o, ctx)) {print(foo);}", ctx);
} catch (Exception e) {
e.printStackTrace();
}
try {
// 'with' failure - context was not event bound
eval("print('4th - :('); with(ctx) {print(foo);}", ctx);
} catch (Exception e) {
e.printStackTrace();
}
}
private static void eval(String code, Map<Object, Object> ctx) throws ScriptException {
ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
engine.getContext().setAttribute("ctx", ctx, ScriptContext.ENGINE_SCOPE);
engine.eval(code);
}
}
感谢您的帮助。
当你说 print(ctx.foo);
时它起作用了,因为 ctx
是一个特殊的 Java 对象实现 Map
并且 Nashorn 似乎处理了这种特殊情况。但它不认为 foo
是对象的实际 属性。因此,当您使用 Object.bindProperties
时,它不会将 foo
转换为 属性。但是,您的第二个示例似乎有效的原因是,它实际上将地图的 toString()
方法作为函数传输。因此,当打印对象 o
时,您会看到 Map
的 toString()
方法的输出,就好像所有映射都被复制了一样。
当你运行下面的程序
Map<Object, Object> ctx = new HashMap<>();
ctx.put("foo", 5);
ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
engine.getContext().setAttribute("ctx", ctx, ScriptContext.ENGINE_SCOPE);
engine.eval("print(ctx.foo);"
+ "with(Object.bindProperties({}, ctx)) {"
+ " print(toString());"
+ " print(get('foo'));"
+ " print(foo); }");
你得到
5
{foo=5}
5
Exception in thread "main" javax.script.ScriptException: ReferenceError: "foo" …
表示调用了方法,不是伪属性foo
。但是对象中方法的存在打开了解决方法的可能性:
Map<Object, Object> ctx = new HashMap<>();
ctx.put("foo", 3);
ctx.put("bar", 7);
ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
engine.getContext().setAttribute("ctx", ctx, ScriptContext.ENGINE_SCOPE);
engine.eval(
"var o={ __noSuchProperty__: function(n) { return this.get(n); } };"
+ "with(Object.bindProperties(o, ctx)) { print( foo + bar ); }");
这将创建一个具有特殊 Nashorn 函数 __noSuchProperty__
的对象,该函数将被调用以处理缺失的属性,并调用我们在本例中从 Map
获得的 get(…)
方法。因此,print( foo + bar );
将在上面的示例中打印 10
。
我正在为 nashorn
和 with
块而苦苦挣扎。我想用 HashMap
从 java 传递 'context' 并在我的代码中使用它。但是,我无法使它正常工作。
待评估JS
with(ctx) {
return a+b;
}
Java 映射为 "passed"
Map<Object, Object> ctx = new HashMap<>();
ctx.put("a", 5)
ctx.put("b", 5)
下面我准备了简短的 class 来演示我面临的错误。
public class Test {
public static void main(String[] args) throws ScriptException {
Map<Object, Object> ctx = new HashMap<>();
ctx.put("foo", 5);
eval("print('1st - :)'); ctx = {'foo':'bar'}; with(ctx) {print(foo);}", new HashMap<>());
// No exception with 'with', o seems to be properly 'in context'..
eval("print('2nd - :)'); var o = {}; print(o); with(Object.bindProperties(o, ctx)) { print(o); } print(o)", ctx);
try {
// ..But it is not
eval("print('3rd - :('); var o = {}; with(Object.bindProperties(o, ctx)) {print(foo);}", ctx);
} catch (Exception e) {
e.printStackTrace();
}
try {
// 'with' failure - context was not event bound
eval("print('4th - :('); with(ctx) {print(foo);}", ctx);
} catch (Exception e) {
e.printStackTrace();
}
}
private static void eval(String code, Map<Object, Object> ctx) throws ScriptException {
ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
engine.getContext().setAttribute("ctx", ctx, ScriptContext.ENGINE_SCOPE);
engine.eval(code);
}
}
感谢您的帮助。
当你说 print(ctx.foo);
时它起作用了,因为 ctx
是一个特殊的 Java 对象实现 Map
并且 Nashorn 似乎处理了这种特殊情况。但它不认为 foo
是对象的实际 属性。因此,当您使用 Object.bindProperties
时,它不会将 foo
转换为 属性。但是,您的第二个示例似乎有效的原因是,它实际上将地图的 toString()
方法作为函数传输。因此,当打印对象 o
时,您会看到 Map
的 toString()
方法的输出,就好像所有映射都被复制了一样。
当你运行下面的程序
Map<Object, Object> ctx = new HashMap<>();
ctx.put("foo", 5);
ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
engine.getContext().setAttribute("ctx", ctx, ScriptContext.ENGINE_SCOPE);
engine.eval("print(ctx.foo);"
+ "with(Object.bindProperties({}, ctx)) {"
+ " print(toString());"
+ " print(get('foo'));"
+ " print(foo); }");
你得到
5
{foo=5}
5
Exception in thread "main" javax.script.ScriptException: ReferenceError: "foo" …
表示调用了方法,不是伪属性foo
。但是对象中方法的存在打开了解决方法的可能性:
Map<Object, Object> ctx = new HashMap<>();
ctx.put("foo", 3);
ctx.put("bar", 7);
ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
engine.getContext().setAttribute("ctx", ctx, ScriptContext.ENGINE_SCOPE);
engine.eval(
"var o={ __noSuchProperty__: function(n) { return this.get(n); } };"
+ "with(Object.bindProperties(o, ctx)) { print( foo + bar ); }");
这将创建一个具有特殊 Nashorn 函数 __noSuchProperty__
的对象,该函数将被调用以处理缺失的属性,并调用我们在本例中从 Map
获得的 get(…)
方法。因此,print( foo + bar );
将在上面的示例中打印 10
。