Search code examples
javascriptjavanashornjsr223graalvm

Migrate Nashorn to GraalVM


I am using Nashorn JS engine from OpenJDK 12. Nashorn seems to be deprecated. I am looking which are the available alternatives. I found GraalVM, but I am not sure if this is the best. How can I execute a GraalVM JavaScript from Java ? Do you have any example ?

With Nashorn was using from Java:

 NashornScriptEngineFactory nsef = new NashornScriptEngineFactory();
 ScriptEngine engine = nsef.getScriptEngine( BasicDBObject.class.getClassLoader() );
 final Bindings binding = engine.getContext().getBindings(ScriptContext.ENGINE_SCOPE);

In Nashorn I create a WrappedMongoDatabase which extends AbstractJSObject. There I add some 'virtual' methods to simulate the MongoDB Query language, which does for example getCollection('persons').find()... Do you know a way to replace the AbstractJSObject in GraalVM?

I had a look to ProxyObject, somehow I couldn't find a way to override the call(Object thiz, Object... args) like in AbstractJSObject.

public class WrappedMongoDatabase extends AbstractJSObject {

@Override
public boolean hasMember(String name) {
   return "getCollection".equals( name ) || "createCollection".equals(name)||...;
}

@Override
public Object getMember(final String name) {
   if ( hasMember( name ) ){
       return new AbstractJSObject() {
           @Override
            public Object call(Object thiz, Object... args) {
                switch( name ) {
                    case "getCollection":
                            if (args.length == 1 && args[0] instanceof String) {
                                return getCollection((String) args[0]);
                            }
                            break;
                ...
                }
            }   
        }
   }
}
}

Solution

  • Follow GraalVM ScriptEngine

    ScriptEngine engine = new ScriptEngineManager().getEngineByName("JavaScript");
    Bindings bindings = engine.getBindings(ScriptContext.ENGINE_SCOPE);
    bindings.put("polyglot.js.allowHostAccess", true);
    bindings.put("polyglot.js.allowHostClassLookup", (Predicate<String>) s -> true);
    bindings.put("javaObj", new Object());
    engine.eval("(javaObj instanceof Java.type('java.lang.Object'));"); // would not work without allowHostAccess and allowHostClassLookup
    

    Notice nashorn compatibility mode:

    These options control the sandboxing rules applied to evaluated JavaScript code and are set to false by default, unless the application was started in Nashorn compatibility mode (--js.nashorn-compat=true).