Search code examples
nashorn

Add Java-implemented function into Nashorn's global scope


I'm trying to migrate/update my project to use Nashorn from Rhino. I have some global utility functions implemented in Java and added into global scope of the target script engine, typical example is log(message).

In Rhino it is implemented via

public static class LogFunction extends org.mozilla.javascript.BaseFunction {
    @Override
    public Object call(Context cx, Scriptable scope, Scriptable thisObj, Object[] args) {
        ...
    }
}

whose instance added into target scope. What has to be done in case of Nashorn? I can't find how standalone function can be implemented for Nashorn.


Solution

  • You can easily implement script functions in Java. You just implement any @FunctionalInterface (https://docs.oracle.com/javase/8/docs/api/java/lang/FunctionalInterface.html) interface using a lambda and expose the same as a global variable by calling ScriptEngine.put (https://docs.oracle.com/javase/8/docs/api/javax/script/ScriptEngine.html#put-java.lang.String-java.lang.Object-) method. The following example implements two such script 'functions' implemented in Java code.

    import javax.script.*;
    import java.util.function.*;
    import java.util.Random;
    
    public class Main {
      public static void main(String[] args) throws Exception {
         ScriptEngineManager m = new ScriptEngineManager();
         ScriptEngine e = m.getEngineByName("nashorn");
    
         // expose 'log' function - any @FunctionInterface Java
         // object can be exposed as 'function'
         e.put("log", (Consumer<String>)System.out::println);
    
         Random r = new Random();
         // expose 'next gaussian' as script global function
         e.put("gaussian", (Supplier<Double>)r::nextGaussian);
    
         // call functions implemented in Java!
         e.eval("log('hello')");
         e.eval("print(gaussian())");
         e.eval("print(gaussian())");
      }
    }