Try this and behold. This prints "undefined" then fails with TypeError: [inner=java.lang.Object@159f197] has no such function "getBar"
Now the problem here is that Nashorn should be able to access data bean properties with their names, without the need to call a function - like, a.b instead of a.getB(). This example, however, shows that this sort of access reads "undefined" instead of String value "localBar"; and the underlying function getBar() is not visible at all! Thanks to the overridden toString(), the exception message proves that calling foo.getBar() from Java works fine.
What is happening?
import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
public class NashornJS {
public static void main(String[] args) throws Exception {
ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
ScriptEngine scriptEngine = scriptEngineManager.getEngineByName("nashorn");
final String localBar = "localBar";
final Object foo = new Object() {
public final String getBar() { return localBar; }
@Override public String toString() { return "[inner="+getBar().toString()+"]"; }
};
try {
scriptEngine.eval("function test(foo) { print(foo.bar); print(foo.getBar()); }");
((Invocable)scriptEngine).invokeFunction("test", foo);
} catch (final ScriptException se) {
se.printStackTrace();
}
}
}
Nashorn allows access only to public methods & public fields of public classes. As you guessed, the anonymous inner class is not public and hence Nashorn won't allow access to the same. Evaluating a non-existent property results in "undefined". That is consistent with JS language. And calling undefined as a function results in TypeError - which is again as per ECMAScript specification.