Nashorn和''从Java传递的上下文

时间:2015-10-29 17:19:59

标签: javascript java-8 nashorn javascript-engine

我正在努力解决nashornwith问题。我想通过' context'来自java HashMap并在我的代码中使用它。但是,我无法使其发挥作用。

要评估的JS

with(ctx) {
    return a+b;
}

Java地图将被传递"

Map<Object, Object> ctx = new HashMap<>();
ctx.put("a", 5)
ctx.put("b", 5)

下面我准备了短课来展示我所面临的错误。

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

感谢您的帮助。

1 个答案:

答案 0 :(得分:2)

当你说print(ctx.foo);它有效时,因为ctx是一个实现Map的特殊Java对象,看起来Nashorn处理这个特例。但它并不认为foo是对象的实际属性。因此,当您使用Object.bindProperties时,它不会将foo作为属性进行转移。但是,你的第二个例子似乎有用的原因是它实际上将地图的toString()方法作为一个函数进行了转移。因此,在打印对象o时,您会看到Map的{​​{1}}方法的输出,就好像所有映射都已复制一样。

运行以下程序时

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

这将创建一个具有特殊Nashorn函数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 ); }"); 的对象,该函数将被调用以处理缺少的属性,并调用我们从__noSuchProperty__获取的get(…)方法。因此,Map将在上面的示例中打印print( foo + bar );