Adventures in GraalVM: invoke Java code from JS in native-image
Thre’s a lot of interest about GraalVM’s native-image recently so I give it a try but instead of "just" trying to compile some java code to a native binary I went to the edge trying to make the native binary extensible via JavaScript.
In a Java application make some java objects available to the JS runtime is trivial and you only need to do something like:
try(Context context = Context.create()) {
MyBean bean = new MyBean();
context.getBindings("js").putMember("bean", bean);
context.eval("js", "bean.saySomething()")
}
But when a native binary is generated this does not work anymore as GraalVM as of RC5 does not yet support reflective access to Java code from JS (and other languages) so we need to use some proxy object GraalVM SDK provides.
The javadoc for the proxy packages is:
http://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/proxy/package-summary.html
So let’s write an example:
try(Context ctx = Context.create()) {
final Map<String, Object> proxy = new HashMap<>(); // (1)
proxy.put("sayHello", new ProxyExecutable() { // (2)
@Override
public Object execute(Value... arguments) {
if (arguments.length != 1) {
throw new IllegalArgumentException();
}
System.out.printf("Hello, %s\n", arguments[0].asString());
return null;
}
});
ProxyObject bean = ProxyObject.fromMap(proxy); // (3)
ctx.getBindings("js").putMember("bean", bean); // (4)
ctx.eval("js", "bean.sayHello('World!')"); // (5)
}
Use a map to describe our bean
Wrap the function we want to invoke using a
which mimics a guest language objects that are executableProxyExecutable
Wrap our map using
builtinProxyObject
fromMap
Bind our proxy to a variable named
the scripting engine can the accessbean
Finally Invoke our
from JSProxyExecutable
Caution | I’m unable to have a stable base for going further because of the following issues: |