I am trying to run the the following code in Java environment using the nashorn.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();
It uses JavaScript APIs to create a JavaFx scene.
If you use the jjs
command line utility with -fx
switch it works as expected, but if you execute the same file with nashorn script engine via Java code, it throws the following exception
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$Recompilation$3$500A$\=fx\!base.LOAD_FX_CLASSES(fx:base.js:38)
at jdk.nashorn.internal.scripts.Script$4$\=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
So how do I pass the -fx
switch or initilize javafx within java code for nashorn?
There are couple of things that I did to get the JavaScript working as passing the -fx
nashorn arg didn't work for me.
As mentioned in the comment by Nikos the class has to extend from javafx.application.Application
and the main function should then call the launch()
which has the code for Nashorn initialization and JS script execution.
The start method has start(Stage primaryStage)
signature. The Stage
object had to be bound to the JavaScript while evaluating.
The following code is a sample how I was able to achieve it.
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();
}
}
}