Доступ к переменной ScriptContext с помощью Nashorn JavaScript Engine (Java 8)
Я использовал следующий код с Rhino
Движок JavaScript в Java:
@Test
public void testRhino() throws ScriptException {
final ScriptEngineManager factory = new ScriptEngineManager();
final ScriptEngine engine = factory.getEngineByName("rhino");
final String raw = "I am the raw value injected";
final ScriptContext ctx = new SimpleScriptContext();
ctx.setAttribute("raw", raw, ScriptContext.ENGINE_SCOPE);
String script = "var result = 'I am a result';";
script += "java.lang.System.out.println(raw);";
script += "'I am a returned value';";
final Object res = engine.eval(script, ctx);
System.out.println(ctx.getAttribute("result"));
System.out.println(res);
}
Вывод скрипта (используя Rhino
) является:
I am the raw value injected
I am a result
I am a returned value
В пределах Nashorn
Движок JavaScript, я не получаю значения для result
:
@Test
public void testNashorn() throws ScriptException {
final ScriptEngineManager factory = new ScriptEngineManager();
final ScriptEngine engine = factory.getEngineByName("nashorn");
final String raw = "I am the raw value injected";
final ScriptContext ctx = new SimpleScriptContext();
ctx.setAttribute("raw", raw, ScriptContext.ENGINE_SCOPE);
String script = "var result = 'I am a result';";
script += "java.lang.System.out.println(raw);";
script += "'I am a returned value';";
final Object res = engine.eval(script, ctx);
System.out.println(ctx.getAttribute("result"));
System.out.println(res);
}
возвращается
I am the raw value injected
null
I am a returned value
Как я могу получить доступ к значению result
переменная ScriptContext
с использованием nashorn
двигатель?
2 ответа
Если вы используете API ScriptEngine.createEngine для создания привязок ENGINE_SCOPE, он будет работать как положено:
import javax.script.*;
public class Main {
public static void main(String[] args) throws Exception {
final ScriptEngineManager factory = new ScriptEngineManager();
final ScriptEngine engine = factory.getEngineByName("nashorn");
final String raw = "I am the raw value injected";
final ScriptContext ctx = new SimpleScriptContext();
// **This is the inserted line**
ctx.setBindings(engine.createBindings(), ScriptContext.ENGINE_SCOPE);
ctx.setAttribute("raw", raw, ScriptContext.ENGINE_SCOPE);
String script = "var result = 'I am a result';";
script += "java.lang.System.out.println(raw);";
script += "'I am a returned value';";
final Object res = engine.eval(script, ctx);
System.out.println(ctx.getAttribute("result"));
System.out.println(res);
}
}
Нашорн лечит Bindings
Хранится в ScriptContext
как "только для чтения". Любая попытка установить переменную, хранящуюся в Bindings
объект (или для создания новой переменной) приведет к созданию новой переменной в nashorn.global
который затеняет Bindings
параметр с этим именем.
Вы можете использовать движок, чтобы "оценить" переменную, используя этот код:
System.out.println( engine.eval("result", ctx) );
Это, однако, довольно некрасиво. "result" сначала компилируется в скрипт, а затем этот скрипт оценивается, чтобы вернуть значение переменной. Хорошо для тестирования, но, возможно, слишком неэффективно для общего решения.
Лучший, но, возможно, более хрупкий метод состоит в том, чтобы извлечь переменную "nashorn.global" и запросить для нее нужное значение.
Bindings nashorn_global = (Bindings) ctx.getAttribute("nashorn.global");
System.out.println( nashorn_global.get("result") );
Смотрите также мой взлом / ответ в Захват глобальных переменных Nashorn для автоматического способа перемещения nashorn.global
значения обратно к Map<String,Object>
после оценки сценария.