Передача переключателя командной строки в движок Nashorn JavaScript

Я пытаюсь запустить следующий код в среде Java с помощью nashorn.Документ с кодом

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();

Он использует API-интерфейсы JavaScript для создания сцены JavaFx.

Если вы используете утилиту командной строки jjs с переключателем -fx, она работает должным образом, но если вы выполняете тот же файл с помощью механизма сценариев nashorn через код Java, он выдает следующее исключение

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

Итак, как передать переключатель -fx или инициализировать javafx в коде java для nashorn?


person Shiva    schedule 12.08.2016    source источник
comment
Я считаю, что критической частью является исключение root IllegalStateException: Toolkit not initialized. Это означает, что вы запускаете код JavaFX, не запустив JavaFX (что делает javafx.application.Application). Таким образом, одно из решений должно состоять в том, чтобы запустить ваше Java-приложение с классом javafx.application.Application, а не просто с любым классом Main.   -  person Nikos Paraskevopoulos    schedule 12.08.2016
comment
@NikosParaskevopoulos: расширение класса из приложения загрузило зависимости и решило проблему. Спасибо за комментарий...!   -  person Shiva    schedule 16.08.2016


Ответы (3)


Создайте свой двигатель Nashorn с помощью jdk.nashorn.api.scripting.NashornScriptEngineFactory. У него есть перегрузки getScriptEngine, которые принимают массив строк — это аргументы командной строки.

К сожалению, вы не можете сделать это через интерфейс javax.script, но jdk.nashorn.api.scripting также является общедоступным и поддерживаемым API.

person Attila Szegedi    schedule 12.08.2016
comment
Я попытался использовать NashornScriptEngineFactory и передать параметр -fx, но это не сработало. Ваши указатели были полезны и информативны, спасибо! - person Shiva; 16.08.2016

Как упоминал Аттила, невозможно передать аргументы через javax.script. У вас есть два варианта:

(1) Используйте специальный API Nashorn -> https://docs.oracle.com/javase/8/docs/jdk/api/nashorn/jdk/nashorn/api/scripting/NashornScriptEngineFactory.html

(or)

(2) Определите системное свойство «nashorn.args» в командной строке Java.

См. также: https://wiki.openjdk.java.net/display/Nashorn/Nashorn/Nashorn+jsr223+engine+notes

В любом случае, я не уверен, что конкретный вариант в случае "-fx" будет работать. Это связано с тем, что код FX имеет особые требования к инициализации, которые позаботятся о инструменте «jjs». Не уверен, что это будет работать в режиме встраивания скриптового движка.

person A. Sundararajan    schedule 13.08.2016
comment
Спасибо за ответ, я быстро попробовал, но -fx arg здесь не сработал. - person Shiva; 16.08.2016

Есть несколько вещей, которые я сделал, чтобы заставить JavaScript работать, так как передача аргумента -fx nashorn у меня не сработала.

  1. Как упоминалось в комментарии Nikos, класс должен расширяться от javafx.application.‌​Application, а затем основная функция должна вызывать launch(), который имеет код для инициализации Nashorn и выполнения сценария JS.

  2. Метод start имеет сигнатуру 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();
        }

    }

}
person Shiva    schedule 16.08.2016