2017-02-20 23 views
2

Я использовал следующий код двигателя Rhino JavaScript в Java:переменного Доступ ScriptContext использования Насхорн JavaScript Engine (Java 8)

@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

Если вы используете ScriptEngine.createEngine API для создания 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); 
} 
} 
+0

'NashornScriptEngine # createBindings()' возвращает либо новый SimpleBindings() ', если установлен параметр global-per-engine, либо' createGlobalMirror() ', если он не установлен. Запуск с помощью '-Dnashorn.args = - global-per-engine' или добавление строки' System.setProperty («nashorn.args», «-global-per-engine»); 'перед созданием движка , вызовут 'ctx.getAttribute (" result ")', чтобы снова возвратить 'null'. Работа над глобальным Nashorn является одной из самых больших проблем в внедрении Nashorn в Java-приложении. – AJNeufeld

1

Nashorn обрабатывает Bindings, хранящийся в ScriptContext как «только для чтения». Любая попытка установить переменную, хранящуюся в объекте Bindings (или создать новую переменную), приведет к созданию новой переменной в nashorn.global, которая под этим именем изменяет параметр Bindings.

Вы можете использовать двигатель, чтобы «оценить» переменной, используя этот код:

System.out.println(engine.eval("result", ctx)); 

Это, однако, весьма некрасиво. «результат» сначала скомпилирован в скрипт, а затем этот скрипт оценивается, чтобы вернуть значение переменной. Отлично подходит для тестирования, но, возможно, слишком малоэффективен для общего решения.

Лучшим, но, возможно, более хрупким методом является извлечение переменной «nashorn.global» и запрос на требуемое значение.

Bindings nashorn_global = (Bindings) ctx.getAttribute("nashorn.global"); 
System.out.println(nashorn_global.get("result")); 

Смотрите также мой хак/ответ в Capturing Nashorn's Global Variables для автоматизированного способа перемещения nashorn.global значения обратно к Map<String,Object> после оценки сценария.

+0

Можно создать новый объект Bindings с помощью ScriptEngine.createBindings API. Это создает привязку, которая напрямую поддерживается Глобальным экземпляром Nashorn, который всегда отражает чтение/запись в глобальную область JS. –

+0

@ A.Sundararajan Если задано '-Dnashorn.args = - global-for-engine', проблема остается, даже если вы используете' ScriptEngine.createBindings() '. – AJNeufeld

+0

С -globals-per-engine существует только один базовый объект JS/Nashorn для каждого движка. Все привязки ENGINE_SCOPE будут иметь один и тот же основной глобальный экземпляр Nashorn! Как вы видели выше, engine.createBindings() в -global-for-engine случае просто вернет SimpleBindings (а не привязки, поддерживаемые новым экземпляром Nashorn Global). –

 Смежные вопросы

  • Нет связанных вопросов^_^