1

我正在努力nashorn阻止with。我想从java中传递'context'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);
    }
}

感谢您的任何帮助。

4

1 回答 1

2

当您说它print(ctx.foo);有效时,因为它ctx是一个特殊的 Java 对象实现Map,并且 Nashorn 似乎处理了这种特殊情况。但它不认为foo是对象的实际属性。因此,当您使用 时Object.bindProperties,它不会foo作为属性转移。但是,您的第二个示例似乎有效的原因是它实际上将toString()map 的方法作为函数传输。因此,在打印 object 时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__将被调用以处理缺失的属性,并调用get(…)我们从Map案例中获得的方法。因此,将在上面的示例中print( foo + bar );打印。10

于 2015-10-29T19:31:30.263 回答