Search code examples
javajsr223nashorn

Reading updated variables after evaluating a script


I am testing some JSR 223 (scripting) code that works with Rhino to see how it works with Nashorn. One area of difference is in the handling of updates to variables passed in via the Bindings argument to engine.eval(). In Rhino, I can use this method to pass in dynamic variable bindings when evaluating a script and then also read out any updated values of these variables after executing the script. In Nashorn, however, this does not work - the values of all variables in the Bindings object are still present with their initial values after executing the script.

To illustrate with a TestNG test case:

@Test
public void shouldSupportReadingVariablesFromBindings() throws Exception {
    // Given
    ScriptEngine engine = new ScriptEngineManager().getEngineByName("javascript");
    Bindings vars = new SimpleBindings();
    vars.put("state", 1);

    // When
    engine.eval("state = 2", vars);
    Number result = (Number) vars.get("state");

    // Then
    assertEquals(result.intValue(), 2);

}

With Rhino (Apple JDK 1.6.0_65 on Mac OS X 10.9.3) the test passes. With Nashorn (Oracle JDK 1.8.0_b132) it fails. I've tried a variety of different approaches to read the variable afterwards - calling engine.get(), engine.getBindings(ScriptContext.ENGINE_SCOPE).get(), engine.getContext().getBindings(...).get() etc. The result is always null.

I can get it to work if I call engine.put("state", 1) and then read it afterwards with engine.get("state"), but this seems a bit messy compared to just passing in the bindings as an argument.

Reading the JSR-223 spec, I cannot find any wording that supports this usage, so is it engine-specific? Is there some other way to accomplish what I want in Nashorn?

Edit: One approach that works is to wrap each variable in an AtomicReference and then call explicit .set(..) methods on those in Javascript. Ugly, but possibly workable.


Solution

  • If you pass a Bindings created with ScriptEngine.createBindings, Nashorn will store the updated value in the Bindings. (I tested.)

    According to the OpenJDK wiki and this OpenJDK bug, this behavior difference between Rhino and Nashorn is expected. Nashorn is not intended to be 100% drop-in compatible with Rhino.