5

I am trying to adapt my program to run with Java 12. It currently runs with Java 8 and has some JavaFX components (a few dialogs). It's not modular. My IDE is Eclipse, and the JavaFX jar files are included in the build path as a User Library. I'd like to generate a runnable jar and either bundle the javafx files inside or add them to the custom JRE, so that I can distribute it without requiring the end user to have Java12 or JavaFX installed separately.

To start, I thought I'd experiment with a simple HelloFX program modified to more closely resemble my program.

public class HelloFX2 {

    public HelloFX2() {
        startToolkit();

        // have to wait a second for the JavaFX thread to actually start, or else the Platform.runLater throws an exception
        try
        {
            Thread.sleep(1000);
        }
        catch(InterruptedException ex)
        {
            Thread.currentThread().interrupt();
        }

        // create the scene and display
        Platform.runLater(() -> {
            Scene theScene = createTheScene();
            final Stage stage = new Stage();
            stage.setScene(theScene);
            stage.show();
        });

    }

    public Scene createTheScene() {
        String javaVersion = System.getProperty("java.version");
        String javafxVersion = System.getProperty("javafx.version");
        Label l = new Label("Hello, JavaFX " + javafxVersion + ", running on Java " + javaVersion + ".");
        Scene scene = new Scene(new StackPane(l), 640, 480);
        return scene;
    }

    public void startToolkit () {
        // we can only create a Scene in a JavaFX thread
        SwingUtilities.invokeLater(() -> {

            // Initialize FX Toolkit, so that we can use the Java FX objects
            new JFXPanel();
        });
    }

}

I also used a Main class to run, as per this suggestion. I don't think I need it in my case because HelloFX2 doesn't extend Application, but again this is closer to what my actual program looks like.

public class Main2 {
    public static void main(String[] args) {
        HelloFX2 theApp = new HelloFX2();
    }
}

The program runs fine in Eclipse. I export as a runnable JAR file with the 'Extract Libraries' option, and then use the jdeps and jlink to create a custom JRE:

D:\Work\Java12>"C:\Program Files\Java\jdk-12.0.1\bin\jdeps" --ignore-missing-deps --print-module-deps HelloFX2.jar
java.base,java.desktop

D:\Work\Java12>"C:\Program Files\Java\jdk-12.0.1\bin\jlink" --no-header-files --no-man-pages  --add-modules java.base,java.desktop --output java-runtime

But when I try to run it, I get this error:

D:\Work\Java12>"java-runtime\bin\java" -jar HelloFX2.jar
Graphics Device initialization failed for :  d3d, sw
Error initializing QuantumRenderer: no suitable pipeline found
java.lang.RuntimeException: java.lang.RuntimeException: Error initializing QuantumRenderer: no suitable pipeline found
        at com.sun.javafx.tk.quantum.QuantumRenderer.getInstance(QuantumRenderer.java:280)
        at com.sun.javafx.tk.quantum.QuantumToolkit.init(QuantumToolkit.java:243)
        at com.sun.javafx.tk.Toolkit.getToolkit(Toolkit.java:260)
        at com.sun.javafx.application.PlatformImpl.startup(PlatformImpl.java:267)
        at com.sun.javafx.application.PlatformImpl.startup(PlatformImpl.java:158)
        at javafx.embed.swing.JFXPanel.lambda$initFx$1(JFXPanel.java:224)
        at java.base/java.lang.Thread.run(Thread.java:835)
Caused by: java.lang.RuntimeException: Error initializing QuantumRenderer: no suitable pipeline found
        at com.sun.javafx.tk.quantum.QuantumRenderer$PipelineRunnable.init(QuantumRenderer.java:94)
        at com.sun.javafx.tk.quantum.QuantumRenderer$PipelineRunnable.run(QuantumRenderer.java:124)
        ... 1 more
Exception in thread "AWT-EventQueue-0" java.lang.RuntimeException: No toolkit found
        at com.sun.javafx.tk.Toolkit.getToolkit(Toolkit.java:272)
        at com.sun.javafx.application.PlatformImpl.startup(PlatformImpl.java:267)
        at com.sun.javafx.application.PlatformImpl.startup(PlatformImpl.java:158)
        at javafx.embed.swing.JFXPanel.lambda$initFx$1(JFXPanel.java:224)
        at java.base/java.lang.Thread.run(Thread.java:835)

This is the same error that occurs with the original HelloFX program when you don't add the --module-path switch to the command line, but I shouldn't need that because I don't extend Application.

Is JavaFX not being found? The JavaFX class files are all included in the jar, but I'm not sure how to point to them.

José Pereda
  • 44,311
  • 7
  • 104
  • 132
Michael
  • 141
  • 2
  • 12
  • It looks like your fat jar only contains the JavaFX classes, but not the native libraries that are part of the JavaFX SDK. – José Pereda Jun 26 '19 at 12:36
  • That did it! I copied all the dll files to a lib64 folder, and used `"java-runtime6\bin\java" -Djava.library.path=lib64 -jar HelloFX2.jar` to run. If you post this as a solution I can mark it as solved – Michael Jun 26 '19 at 12:51
  • Done, posted the answer. – José Pereda Jun 26 '19 at 13:18
  • Texts and docs not worked for me! I read the sample code and got it .. this is the [link](https://github.com/openjfx/samples) – Davide Jan 14 '20 at 11:21

1 Answers1

5

Using the JavaFX SDK, there is a lib folder with the jars like javafx.base.jar, or javafx.controls.jar, but also there are native libraries like libglass.so (Linux), libglass.dylib(Mac). On Windows, the native dlls, like glass.dllare in the bin folder.

When packaging those classes into a fat jar, you must take into account the required native libraries too.

This means that you have to pack the native libraries for javafx.graphics, but you don't need to include the webkit library (that adds around 80 MB) if you don't use the javafx.web module.

Note also that these libraries are platform specific (and even the jars). In case you want to distribute your jar to other platforms, you can also pack the classes and native libraries from those platforms, simply by downloading the SDK for them.

All of this is explained in detail in https://openjfx.io/openjfx-docs/#modular, section Non-modular project - Command Line.

For modular projects, jlink is the recommended tool. In both cases, also using build tools (Gradle/Maven) really helps dealing with the JavaFX dependencies: you won't need the JavaFX SDK, as you will retrieve the dependencies from Maven Central, and these already bundle the native libraries with them. Again, worth reading the whole https://openjfx.io/openjfx-docs/#modular document.

José Pereda
  • 44,311
  • 7
  • 104
  • 132
  • simply by downloading the SDK for them, what do you mean? – Paul Kocian Apr 23 '22 at 18:21
  • 1
    If you work with the JavaFX SDK, you have to get it from here: https://gluonhq.com/products/javafx/, choosing OS, version and architecture. I meant that you have to download different SDKs for different platforms. – José Pereda Apr 23 '22 at 18:28