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?
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.