/ / Nashorn и "with" контекстът премина от Java - javascript, java-8, nashorn, javascript-engine

Nashorn и контекстът "с" премина от Java - javascript, java-8, nashorn, javascript-engine

Сражавам се nashorn и with блок. Бих искал да премине "контекст" от 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);
}
}

Благодаря ви за помощта.

Отговори:

2 за отговор № 1

Когато кажеш print(ctx.foo); работи, защото ctx е специален Java обект, който се изпълнява Map и изглежда, че Nashorn се справя с този специален случай. Но това не се взема предвид foo да бъде действително свойство на обекта. Така че, когато използвате Object.bindProperties, не се прехвърля foo като собственост. Но причината, вашият втори пример изглежда да работи, е, че тя действително прехвърли toString() метод на картата като функция. Така че при отпечатване на обекта o, виждате изхода на MaptoString() метод, както ако всички копия са копирани.

Когато стартирате следната програма

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 в горния пример.