将命令行开关传递给 Nashorn JavaScript 引擎
Passing command line switch to Nashorn JavaScript engine
我正在尝试使用 nashorn 在 Java 环境中 运行 以下代码。Code Doc
load("fx:base.js");
load("fx:controls.js");
load("fx:graphics.js");
var material = new PhongMaterial();
material.diffuseColor = Color.LIGHTGREEN;
material.specularColor = Color.rgb(30, 30, 30);
var meshView = Java.to([
new Box(200, 200, 200),
new Sphere(100),
new Cylinder(100, 200)
], "javafx.scene.shape.Shape3D[]");
for (var i = 0; i != 3; i++) {
meshView[i].material = material;
meshView[i].translateX = (i + 1) * 220;
meshView[i].translateY = 200;
meshView[i].translateZ = 20;
meshView[i].drawMode = DrawMode.FILL;
meshView[i].cullFace = CullFace.BACK;
};
var pointLight = new PointLight(Color.WHITE);
pointLight.translateX = 800;
pointLight.translateY = -200;
pointLight.translateZ = -1000;
var root = new Group(meshView);
root.children.add(pointLight);
var scene = new Scene(root, 800, 400, true);
scene.fill = Color.rgb(127, 127, 127);
scene.camera = new PerspectiveCamera(false);
$STAGE.scene = scene;
$STAGE.show();
它使用 JavaScript API 来创建 JavaFx 场景。
如果您将 jjs
命令行实用程序与 -fx
开关一起使用,它会按预期工作,但是如果您通过 Java 代码使用 nashorn 脚本引擎执行相同的文件,它会抛出以下异常
Exception in thread "main" java.lang.ExceptionInInitializerError
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:348)
at jdk.nashorn.internal.runtime.Context.findClass(Context.java:983)
at jdk.nashorn.internal.objects.NativeJava.simpleType(NativeJava.java:489)
at jdk.nashorn.internal.objects.NativeJava.type(NativeJava.java:320)
at jdk.nashorn.internal.objects.NativeJava.type(NativeJava.java:312)
at jdk.nashorn.internal.objects.NativeJava.type(NativeJava.java:308)
at jdk.nashorn.internal.scripts.Script$Recompilation0A$\=fx\!base.LOAD_FX_CLASSES(fx:base.js:38)
at jdk.nashorn.internal.scripts.Script$\=fx\!controls.:program(fx:controls.js:30)
at jdk.nashorn.internal.runtime.ScriptFunctionData.invoke(ScriptFunctionData.java:636)
at jdk.nashorn.internal.runtime.ScriptFunction.invoke(ScriptFunction.java:229)
at jdk.nashorn.internal.runtime.ScriptRuntime.apply(ScriptRuntime.java:387)
at jdk.nashorn.internal.runtime.Context.evaluateSource(Context.java:1150)
at jdk.nashorn.internal.runtime.Context.load(Context.java:799)
at jdk.nashorn.internal.objects.Global.load(Global.java:995)
at jdk.nashorn.internal.scripts.Script$\^eval\_.:program(<eval>:2)
at jdk.nashorn.internal.runtime.ScriptFunctionData.invoke(ScriptFunctionData.java:636)
at jdk.nashorn.internal.runtime.ScriptFunction.invoke(ScriptFunction.java:229)
at jdk.nashorn.internal.runtime.ScriptRuntime.apply(ScriptRuntime.java:387)
at jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl(NashornScriptEngine.java:437)
at jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl(NashornScriptEngine.java:401)
at jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl(NashornScriptEngine.java:397)
at jdk.nashorn.api.scripting.NashornScriptEngine.eval(NashornScriptEngine.java:147)
at javax.script.AbstractScriptEngine.eval(AbstractScriptEngine.java:212)
at com.metalop.nashorn.javafx.GettingStarted.main(GettingStarted.java:23)
Caused by: java.lang.IllegalStateException: Toolkit not initialized
at com.sun.javafx.application.PlatformImpl.runLater(PlatformImpl.java:273)
at com.sun.javafx.application.PlatformImpl.runLater(PlatformImpl.java:268)
at com.sun.javafx.application.PlatformImpl.setPlatformUserAgentStylesheet(PlatformImpl.java:550)
at com.sun.javafx.application.PlatformImpl.setDefaultPlatformUserAgentStylesheet(PlatformImpl.java:512)
at javafx.scene.control.Control.<clinit>(Control.java:87)
... 25 more
那么如何在 nashorn 的 java 代码中传递 -fx
开关或初始化 javafx?
使用 jdk.nashorn.api.scripting.NashornScriptEngineFactory
实例化您的 Nashorn 引擎。它有 getScriptEngine
的重载,它接受一个字符串数组——这些是命令行参数。
很遗憾,您不能通过 javax.script
界面执行此操作,但 jdk.nashorn.api.scripting
也是一个 public 并支持 API。
正如阿提拉所说,无法通过 javax.script 传递参数。您有两个选择:
(1) 使用 Nashorn 特定 API -> https://docs.oracle.com/javase/8/docs/jdk/api/nashorn/jdk/nashorn/api/scripting/NashornScriptEngineFactory.html
(或)
(2) 在 java 命令行中定义 "nashorn.args" 系统 属性。
另请参阅:https://wiki.openjdk.java.net/display/Nashorn/Nashorn+jsr223+engine+notes
在任何一种情况下,我都不确定“-fx”的特定选项是否有效。这是因为 FX 代码具有特定的初始化要求,这些要求由 "jjs" 工具处理。不确定这是否适用于脚本引擎
嵌入模式。
为了让 JavaScript 正常工作,我做了几件事,因为传递 -fx
nashorn arg 对我不起作用。
正如 Nikos 在评论中提到的那样,class 必须从 javafx.application.Application
扩展,然后主函数应该调用具有代码的 launch()
Nashorn初始化和JS脚本执行。
启动方法有 start(Stage primaryStage)
签名。 Stage
对象在计算时必须绑定到 JavaScript。
以下代码是我如何实现它的示例。
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.SimpleBindings;
import javafx.application.Application;
import javafx.stage.Stage;
public class GettingStarted extends Application {
public static void main(String args[]) {
launch(args);
}
@Override
public void start(Stage primaryStage) throws Exception {
ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
try (InputStream is = GettingStarted.class.getResourceAsStream("getting-started.js")) {
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
SimpleBindings bindings = new SimpleBindings();
bindings.put("$STAGE", primaryStage);
engine.eval(reader, bindings);
} catch (Exception e) {
e.printStackTrace();
}
}
}
我正在尝试使用 nashorn 在 Java 环境中 运行 以下代码。Code Doc
load("fx:base.js");
load("fx:controls.js");
load("fx:graphics.js");
var material = new PhongMaterial();
material.diffuseColor = Color.LIGHTGREEN;
material.specularColor = Color.rgb(30, 30, 30);
var meshView = Java.to([
new Box(200, 200, 200),
new Sphere(100),
new Cylinder(100, 200)
], "javafx.scene.shape.Shape3D[]");
for (var i = 0; i != 3; i++) {
meshView[i].material = material;
meshView[i].translateX = (i + 1) * 220;
meshView[i].translateY = 200;
meshView[i].translateZ = 20;
meshView[i].drawMode = DrawMode.FILL;
meshView[i].cullFace = CullFace.BACK;
};
var pointLight = new PointLight(Color.WHITE);
pointLight.translateX = 800;
pointLight.translateY = -200;
pointLight.translateZ = -1000;
var root = new Group(meshView);
root.children.add(pointLight);
var scene = new Scene(root, 800, 400, true);
scene.fill = Color.rgb(127, 127, 127);
scene.camera = new PerspectiveCamera(false);
$STAGE.scene = scene;
$STAGE.show();
它使用 JavaScript API 来创建 JavaFx 场景。
如果您将 jjs
命令行实用程序与 -fx
开关一起使用,它会按预期工作,但是如果您通过 Java 代码使用 nashorn 脚本引擎执行相同的文件,它会抛出以下异常
Exception in thread "main" java.lang.ExceptionInInitializerError
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:348)
at jdk.nashorn.internal.runtime.Context.findClass(Context.java:983)
at jdk.nashorn.internal.objects.NativeJava.simpleType(NativeJava.java:489)
at jdk.nashorn.internal.objects.NativeJava.type(NativeJava.java:320)
at jdk.nashorn.internal.objects.NativeJava.type(NativeJava.java:312)
at jdk.nashorn.internal.objects.NativeJava.type(NativeJava.java:308)
at jdk.nashorn.internal.scripts.Script$Recompilation0A$\=fx\!base.LOAD_FX_CLASSES(fx:base.js:38)
at jdk.nashorn.internal.scripts.Script$\=fx\!controls.:program(fx:controls.js:30)
at jdk.nashorn.internal.runtime.ScriptFunctionData.invoke(ScriptFunctionData.java:636)
at jdk.nashorn.internal.runtime.ScriptFunction.invoke(ScriptFunction.java:229)
at jdk.nashorn.internal.runtime.ScriptRuntime.apply(ScriptRuntime.java:387)
at jdk.nashorn.internal.runtime.Context.evaluateSource(Context.java:1150)
at jdk.nashorn.internal.runtime.Context.load(Context.java:799)
at jdk.nashorn.internal.objects.Global.load(Global.java:995)
at jdk.nashorn.internal.scripts.Script$\^eval\_.:program(<eval>:2)
at jdk.nashorn.internal.runtime.ScriptFunctionData.invoke(ScriptFunctionData.java:636)
at jdk.nashorn.internal.runtime.ScriptFunction.invoke(ScriptFunction.java:229)
at jdk.nashorn.internal.runtime.ScriptRuntime.apply(ScriptRuntime.java:387)
at jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl(NashornScriptEngine.java:437)
at jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl(NashornScriptEngine.java:401)
at jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl(NashornScriptEngine.java:397)
at jdk.nashorn.api.scripting.NashornScriptEngine.eval(NashornScriptEngine.java:147)
at javax.script.AbstractScriptEngine.eval(AbstractScriptEngine.java:212)
at com.metalop.nashorn.javafx.GettingStarted.main(GettingStarted.java:23)
Caused by: java.lang.IllegalStateException: Toolkit not initialized
at com.sun.javafx.application.PlatformImpl.runLater(PlatformImpl.java:273)
at com.sun.javafx.application.PlatformImpl.runLater(PlatformImpl.java:268)
at com.sun.javafx.application.PlatformImpl.setPlatformUserAgentStylesheet(PlatformImpl.java:550)
at com.sun.javafx.application.PlatformImpl.setDefaultPlatformUserAgentStylesheet(PlatformImpl.java:512)
at javafx.scene.control.Control.<clinit>(Control.java:87)
... 25 more
那么如何在 nashorn 的 java 代码中传递 -fx
开关或初始化 javafx?
使用 jdk.nashorn.api.scripting.NashornScriptEngineFactory
实例化您的 Nashorn 引擎。它有 getScriptEngine
的重载,它接受一个字符串数组——这些是命令行参数。
很遗憾,您不能通过 javax.script
界面执行此操作,但 jdk.nashorn.api.scripting
也是一个 public 并支持 API。
正如阿提拉所说,无法通过 javax.script 传递参数。您有两个选择:
(1) 使用 Nashorn 特定 API -> https://docs.oracle.com/javase/8/docs/jdk/api/nashorn/jdk/nashorn/api/scripting/NashornScriptEngineFactory.html
(或)
(2) 在 java 命令行中定义 "nashorn.args" 系统 属性。
另请参阅:https://wiki.openjdk.java.net/display/Nashorn/Nashorn+jsr223+engine+notes
在任何一种情况下,我都不确定“-fx”的特定选项是否有效。这是因为 FX 代码具有特定的初始化要求,这些要求由 "jjs" 工具处理。不确定这是否适用于脚本引擎 嵌入模式。
为了让 JavaScript 正常工作,我做了几件事,因为传递 -fx
nashorn arg 对我不起作用。
正如 Nikos 在评论中提到的那样,class 必须从
javafx.application.Application
扩展,然后主函数应该调用具有代码的launch()
Nashorn初始化和JS脚本执行。启动方法有
start(Stage primaryStage)
签名。Stage
对象在计算时必须绑定到 JavaScript。
以下代码是我如何实现它的示例。
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.SimpleBindings;
import javafx.application.Application;
import javafx.stage.Stage;
public class GettingStarted extends Application {
public static void main(String args[]) {
launch(args);
}
@Override
public void start(Stage primaryStage) throws Exception {
ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
try (InputStream is = GettingStarted.class.getResourceAsStream("getting-started.js")) {
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
SimpleBindings bindings = new SimpleBindings();
bindings.put("$STAGE", primaryStage);
engine.eval(reader, bindings);
} catch (Exception e) {
e.printStackTrace();
}
}
}