我正在尝试迁移/更新我的项目以使用Rhino的Nashorn。我有一些用Java实现的全局实用程序函数,并添加到目标脚本引擎的全局范围内,典型示例是log(message)
。
在Rhino中,它是通过
实现的public static class LogFunction extends org.mozilla.javascript.BaseFunction {
@Override
public Object call(Context cx, Scriptable scope, Scriptable thisObj, Object[] args) {
...
}
}
其实例已添加到目标范围中。在Nashorn的情况下需要做些什么?我找不到如何为Nashorn实现独立功能。
答案 0 :(得分:5)
您可以使用Java轻松实现脚本函数。您只需使用lambda实现任何@FunctionalInterface(manual)接口,并通过调用ScriptEngine.put(https://docs.oracle.com/javase/8/docs/api/java/lang/FunctionalInterface.html)方法将其作为全局变量公开。以下示例实现了两个这样的脚本函数'用Java代码实现。
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())");
}
}
答案 1 :(得分:1)
在提问之后的一段时间我再次搜索了一下,发现了这篇文章:http://mail.openjdk.java.net/pipermail/nashorn-dev/2013-December/002520.html
*)在JDK(或您自己的)中实现任何@FunctionalInterface接口 @FunctionalInterface)和传递/放置相同的对象 javax.script.Bindings甚至是全局范围。脚本可以访问这些 虽然这些都是功能。
*)在你的类中实现jdk.nashorn.api.scripting.JSObject 在它上面实现“调用”方法。再次,nashorn的灵活dynalink基础 链接器将处理您的JSObject impl。好像它是一个功能。这个 也可以用来在Java中实现“构造函数”(newObject方法) 代码等等。
我决定使用JSObject实现,我的代码看起来更像Rhino,并且比Sundararajan的答案推荐的方法更接近原始代码。不确定它们之间是否有任何性能差异。
import jdk.nashorn.api.scripting.AbstractJSObject;
public static class PrintFunction extends AbstractJSObject {
public PrintFunction() {
}
@Override
public boolean isFunction() {
return true;
}
@Override
public Object call(Object thiz, Object... args) {
... do something ...
return null;
}
}
...
void onInitScriptObjects(Bindings scope) {
scope.put("print", new PrintFunction());
}