添加 Java-implemented 函数到 Nashorn 的全局范围
Add Java-implemented function into Nashorn's global scope
我正在尝试 migrate/update 我的项目使用 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 实现独立功能。
您可以轻松实现Java中的脚本功能。您只需实现任何 @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-) 方法。以下示例实现了两个在 Java 代码中实现的此类脚本 'functions'。
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())");
}
}
问完这个问题一段时间后,我再次用谷歌搜索并找到了这个 post:http://mail.openjdk.java.net/pipermail/nashorn-dev/2013-December/002520.html
*) Implement any @FunctionalInterface interface in JDK (or your own
@FunctionalInterface) and pass/put object of the same in a
javax.script.Bindings or even global scope. Script can access these as
though these are functions.
*) Implement jdk.nashorn.api.scripting.JSObject in your class and
implement "call" method on it. Again, nashorn's flexible dynalink based
linker will treat your JSObject impl. as though it is a function. This
can also be used to implement "constructor" (newObject method) in Java
code and so on.
我决定使用 JSObject 实现,与 Sundararajan 的回答中推荐的方法相比,我的代码看起来更像 Rhino,也更接近我的原始代码。不确定它们之间是否有任何性能差异。
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());
}
我正在尝试 migrate/update 我的项目使用 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 实现独立功能。
您可以轻松实现Java中的脚本功能。您只需实现任何 @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-) 方法。以下示例实现了两个在 Java 代码中实现的此类脚本 'functions'。
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())");
}
}
问完这个问题一段时间后,我再次用谷歌搜索并找到了这个 post:http://mail.openjdk.java.net/pipermail/nashorn-dev/2013-December/002520.html
*) Implement any @FunctionalInterface interface in JDK (or your own @FunctionalInterface) and pass/put object of the same in a javax.script.Bindings or even global scope. Script can access these as though these are functions.
*) Implement jdk.nashorn.api.scripting.JSObject in your class and implement "call" method on it. Again, nashorn's flexible dynalink based linker will treat your JSObject impl. as though it is a function. This can also be used to implement "constructor" (newObject method) in Java code and so on.
我决定使用 JSObject 实现,与 Sundararajan 的回答中推荐的方法相比,我的代码看起来更像 Rhino,也更接近我的原始代码。不确定它们之间是否有任何性能差异。
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());
}