I want to use a Java object new Train()
as an argument to pass into a JavaScript function, here is the Java code
public void execute() { File script = new File("/Test.js"); ScriptEngine engine = new ScriptEngineManager().getEngineByName("graal.js"); try { engine.eval(new FileReader(script)); Invocable invocable = (Invocable)engine; Object result = invocable.invokeFunction("fun1", new Train()); System.out.println(result); } catch(Exception e) { e.printStackTrace(); } }
public class Train { private double speed = 0.0D; public Train() { this.speed = 10.5D; } public double getSpeed() { return this.speed; } }
JavaScript code
var fun1 = function test(train) { print(train.getSpeed()); return train.getSpeed(); }
As of right now it puts this error in the console
[16:56:42] [INFO]: [STDERR]: javax.script.ScriptException: org.graalvm.polyglot.PolyglotException: TypeError: invokeMember (getSpeed) on ScriptExecutor$Train@429b2a7b failed due to: Unknown identifier: getSpeed [16:56:42] [INFO]: [STDERR]: at com.oracle.truffle.js.scriptengine.GraalJSScriptEngine.toScriptException(GraalJSScriptEngine.java:483) [16:56:42] [INFO]: [STDERR]: at com.oracle.truffle.js.scriptengine.GraalJSScriptEngine.invokeFunction(GraalJSScriptEngine.java:558)
Is there any way to make this work?
Advertisement
Answer
GraalJS (and GraalVM in general) has tight security/access controls by default. GraalJS is not exposing getSpeed()
(or any other field or method) on the Train
instance to JavaScript.
You can open up access to all host fields/methods with a configuration setting:
Bindings bindings = engine.getBindings(ScriptContext.ENGINE_SCOPE); bindings.put("polyglot.js.allowHostAccess", true);
or instead enable it on a more granular level by decorating getSpeed()
in Train
:
import org.graalvm.polyglot.HostAccess; // ... @HostAccess.Export public double getSpeed() { return this.speed; }