使用Nashorn JavaScript Engine(Java 8)访问ScriptContext的变量

时间:2017-02-20 06:56:15

标签: javascript java rhino nashorn

我在Java中使用了Rhino JavaScript引擎的以下代码:

@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 个答案:

答案 0 :(得分:4)

如果您使用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);
 }
}

答案 1 :(得分:3)

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中的hack / answer,了解在评估脚本后将nashorn.global值移回Map<String,Object>的自动方式。