Search code examples
javanashorn

Inconsistent output in Nashorn after accessing undefined value


I'm trying to create a console interface to a Java program using Nashorn. So I want some input to be evaluated against some default imports. The problem is when it accesses an undefined value. Ideally, engine.eval should throw a ReferenceError, or return null, but I'm getting inconsistent values later on:

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;

public class Main {
    public static void main(String[] args) throws Exception {
        ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
        System.out.println(engine.eval("with(JavaImporter(java.util)) { x }"));
        System.out.println(engine.eval("with(JavaImporter(java.util)) { x = 1 }"));
        System.out.println(engine.eval("with(JavaImporter(java.util)) { x }"));
    }
}

The result on ideone and Windows Oracle JDK 1.8.0_101 is:

null
1
null

The last output is null, but adding x == null gives false.

I get this output if I add any spaces to the first string:

null
1
1

It seems that the last value is null if the first and last engine.eval parameters are exactly the same, including whitespace.

The value of x can go back between null and 1 so it looks like some kind of caching in the engine:

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;

public class Main {
    public static void main(String[] args) throws Exception {
        ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
        System.out.println(engine.eval("with(JavaImporter(java.util)) { x }"));
        System.out.println(engine.eval("with(JavaImporter(java.util)) { x = 1 }"));
        System.out.println(engine.eval("with(JavaImporter(java.util)) { x }"));
        System.out.println(engine.eval("with(JavaImporter(java.util)) { x  }"));
        System.out.println(engine.eval("with(JavaImporter(java.util)) { x + x }"));
        System.out.println(engine.eval("with(JavaImporter(java.util)) { x }"));
    }
}

Gives:

null
1
null
1
2.0
null

Is there someway to get this to consistently give the null, 1, 1 results?


Solution

  • There is a class cache within the engine, which can be disabled by creating it with:

    NashornScriptEngineFactory factory = new NashornScriptEngineFactory();
    ScriptEngine engine = factory.getScriptEngine(new String[] { "--class-cache-size = 0" });
    

    By forcing each expression to be recompiled, it seems to solve the issue. It looks like the same expression is compiled differently depending on which variables are in scope.