问题
I used the following code with the Rhino
JavaScript engine in Java:
@Test
public void testRhino() throws ScriptException {
final ScriptEngineManager factory = new ScriptEngineManager();
final ScriptEngine engine = factory.getEngineByName("rhino");
final String raw = "I am the raw value injected";
final ScriptContext ctx = new SimpleScriptContext();
ctx.setAttribute("raw", raw, ScriptContext.ENGINE_SCOPE);
String script = "var result = 'I am a result';";
script += "java.lang.System.out.println(raw);";
script += "'I am a returned value';";
final Object res = engine.eval(script, ctx);
System.out.println(ctx.getAttribute("result"));
System.out.println(res);
}
The output of the script (using Rhino
) is:
I am the raw value injected
I am a result
I am a returned value
Within the Nashorn
JavaScript engine, I get no value for the result
:
@Test
public void testNashorn() throws ScriptException {
final ScriptEngineManager factory = new ScriptEngineManager();
final ScriptEngine engine = factory.getEngineByName("nashorn");
final String raw = "I am the raw value injected";
final ScriptContext ctx = new SimpleScriptContext();
ctx.setAttribute("raw", raw, ScriptContext.ENGINE_SCOPE);
String script = "var result = 'I am a result';";
script += "java.lang.System.out.println(raw);";
script += "'I am a returned value';";
final Object res = engine.eval(script, ctx);
System.out.println(ctx.getAttribute("result"));
System.out.println(res);
}
returns
I am the raw value injected
null
I am a returned value
How can I access the value of the result
variable of the ScriptContext
using the nashorn
engine?
回答1:
If you use ScriptEngine.createEngine API to create ENGINE_SCOPE Bindings, it'll work as expected:
import javax.script.*;
public class Main {
public static void main(String[] args) throws Exception {
final ScriptEngineManager factory = new ScriptEngineManager();
final ScriptEngine engine = factory.getEngineByName("nashorn");
final String raw = "I am the raw value injected";
final ScriptContext ctx = new SimpleScriptContext();
// **This is the inserted line**
ctx.setBindings(engine.createBindings(), ScriptContext.ENGINE_SCOPE);
ctx.setAttribute("raw", raw, ScriptContext.ENGINE_SCOPE);
String script = "var result = 'I am a result';";
script += "java.lang.System.out.println(raw);";
script += "'I am a returned value';";
final Object res = engine.eval(script, ctx);
System.out.println(ctx.getAttribute("result"));
System.out.println(res);
}
}
回答2:
Nashorn treats the Bindings
stored in ScriptContext
as "read-only".
Any attempt to set a variable stored in a Bindings
object (or to create a new variable) will result in a new variable being created in nashorn.global
which shadows the Bindings
parameter by that name.
You can use the engine to "evaluate" the variable, using this code:
System.out.println( engine.eval("result", ctx) );
This is, however, quite ugly. "result" is first compiled into a script, and then that script is evaluated, to return the variable's value. Fine for testing, but perhaps a little too inefficient for a general solution.
A better, but perhaps more fragile method, is to extract the "nashorn.global" variable, and query it for the desired value.
Bindings nashorn_global = (Bindings) ctx.getAttribute("nashorn.global");
System.out.println( nashorn_global.get("result") );
See also my hack/answer in Capturing Nashorn's Global Variables for automated way of moving nashorn.global
values back to a Map<String,Object>
after evaluating a script.
来源:https://stackoverflow.com/questions/42338239/access-variable-of-scriptcontext-using-nashorn-javascript-engine-java-8