Nashorn allows me to evaluate a JavaScript in a new scope, like this:
public Object evalInNewScope(String code, Bindings bindings) throws Exception {
ScriptContext context = new SimpleScriptContext();
context.setBindings(bindings, ScriptContext.ENGINE_SCOPE);
return engine.eval(code, context);
}
This is great for thread-safety: The engine instance may be re-used across threads, and each thread can make its own call with thread-specific bindings.
However, I have not found a similar capability for Invocable#invokeFunction(String, Object...)
.
Does anyone know how I could do what I want? Is there a good reason for this asymmetry?
invokeFunction
calls functions only from current context, you cannot provide a context directly.
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("nashorn");
ScriptContext ctx = new SimpleScriptContext();
ctx.setBindings(engine.createBindings(), ScriptContext.ENGINE_SCOPE);
engine.eval("function hello() { return 'Hello!'; }", ctx);
engine.setContext(ctx);
((Invocable) engine).invokeFunction("hello");
Removing the engine.setContext(ctx)
line would result in a java.lang.NoSuchMethodException: No such function hello
exception.
Depending on your situation, you may have to re-set the original context!