fgb fgb - 3 months ago 13
Java Question

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?

fgb fgb
Answer

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.