1

My question is kind of a two parter:

  1. CAN I even include the JavaFX modules in a JPackaged app such that a user doesn't have to go and install a specific version of JavaFX libraries before installing my app?

  2. If #1 is possible, how do I do that and/or what am I doing wrong when I attempt it?

My application was originally Java 8, and I upgraded it to Java 17. Currently:

  • Windows 10
  • Java 17.0.6 LTS
  • JavaFX 19.0.2.1

My app is non-modular and being built with maven and packaged into a monolithic jar with all dependencies (except JavaFX modules) using the Maven Assembly Plugin:

<plugin>
  <artifactId>maven-assembly-plugin</artifactId>
  <configuration>
    <archive>
      <manifest>
        <mainClass>com.github.iguanastin.app.MyAppKt</mainClass>
      </manifest>
    </archive>
    <descriptorRefs>
      <descriptorRef>jar-with-dependencies</descriptorRef>
    </descriptorRefs>
  </configuration>
  <executions>
    <execution>
      <id>make-assembly</id>
      <phase>package</phase>
       <goals>
         <goal>single</goal>
       </goals>
     </execution>
   </executions>
</plugin>

I'm currently using jpackage to package my app into an installable EXE for Windows:

& jpackage.exe
     --input ./input
     --dest ./output
     -n MyApp
     --app-version 1.0.0
     --java-options "--module-path 'C:\Program Files\Java\javafx-sdk-21\lib' --add-modules javafx.controls --add-opens=javafx.graphics/javafx.scene=ALL-UNNAMED"
     --main-jar ./myapp-jar-with-dependencies.jar

Which works fine, as long as the user has manually installed JavaFX in: C:\Program Files\Java\javafx-sdk-21.

As I understand it this isn't the way it SHOULD be packaged, because the --module-path and --add-modules should be passed to Jpackage and not as JVM arguments with the --java-options argument. However, when I try to package it like so:

& jpackage.exe
     --input ./input
     --dest ./output
     -n MyApp
     --app-version 1.0.0
     --module-path 'C:\Program Files\Java\javafx-sdk-21\lib'
     --add-modules javafx.controls
     --java-options '--add-opens=javafx.graphics/javafx.scene=ALL-UNNAMED'
     --main-jar ./myapp-jar-with-dependencies.jar

It creates an EXE with no errors and installs normally, but when I try to run it I get this error:

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 javafx.graphics@21-ea/com.sun.javafx.tk.quantum.QuantumRenderer.getInstance(Unknown Source)        at javafx.graphics@21-ea/com.sun.javafx.tk.quantum.QuantumToolkit.init(Unknown Source)
        at javafx.graphics@21-ea/com.sun.javafx.tk.Toolkit.getToolkit(Unknown Source)
        at javafx.graphics@21-ea/com.sun.javafx.application.PlatformImpl.startup(Unknown Source)
        at javafx.graphics@21-ea/com.sun.javafx.application.PlatformImpl.startup(Unknown Source)
        at javafx.graphics@21-ea/com.sun.javafx.application.LauncherImpl.startToolkit(Unknown Source)
        at javafx.graphics@21-ea/com.sun.javafx.application.LauncherImpl.launchApplication1(Unknown Source)
        at javafx.graphics@21-ea/com.sun.javafx.application.LauncherImpl.lambda$launchApplication$2(Unknown Source)
        at java.base/java.lang.Thread.run(Unknown Source)
Caused by: java.lang.RuntimeException: Error initializing QuantumRenderer: no suitable pipeline found
        at javafx.graphics@21-ea/com.sun.javafx.tk.quantum.QuantumRenderer$PipelineRunnable.init(Unknown Source)
        at javafx.graphics@21-ea/com.sun.javafx.tk.quantum.QuantumRenderer$PipelineRunnable.run(Unknown Source)
        ... 1 more
Exception in thread "main" java.lang.RuntimeException: No toolkit found
        at javafx.graphics@21-ea/com.sun.javafx.tk.Toolkit.getToolkit(Unknown Source)
        at javafx.graphics@21-ea/com.sun.javafx.application.PlatformImpl.startup(Unknown Source)
        at javafx.graphics@21-ea/com.sun.javafx.application.PlatformImpl.startup(Unknown Source)
        at javafx.graphics@21-ea/com.sun.javafx.application.LauncherImpl.startToolkit(Unknown Source)
        at javafx.graphics@21-ea/com.sun.javafx.application.LauncherImpl.launchApplication1(Unknown Source)
        at javafx.graphics@21-ea/com.sun.javafx.application.LauncherImpl.lambda$launchApplication$2(Unknown Source)
        at java.base/java.lang.Thread.run(Unknown Source)
Failed to launch JVM

Which appears to be caused by missing/unlinked JavaFX dlls according to this post. I also found this Github issue which suggests using the JavaFX jmods instead of the SDK, but the result is the same. I forget where, but another post I found suggested adding the sdk /bin folder to the app folder, which also gives the same error at runtime.

After spending hours trying out different combinations of the above solutions with jmods, sdk, etc. I'm still not getting anywhere on this problem.

Iguanastin
  • 11
  • 3
  • The Github issue is correct. `.jmod` files should be used as inputs to jlink since those actually contain the native libraries. If you use the jmods, do you get a `runtime/bin/javafx` folder in the created package? (you can also use `--type app-image` to generate the image directly, instead of an installer) – Jorn Vernee Jan 31 '23 at 03:39
  • @JornVernee That `--type app-image` is incredibly useful, thanks. There is no `runtime/bin/javafx` folder nor any JavaFX dlls in bin when I package with jmods. – Iguanastin Jan 31 '23 at 03:54
  • If I create a jlink runtime image with `jlink --module-path ./jmods --add-modules javafx.controls --output image` where `./jmods` is just a folder with the extracted contents of the jmods download from here: https://download2.gluonhq.com/openjfx/19.0.2.1/openjfx-19.0.2.1_windows-x64_bin-jmods.zip Then I get a `images/bin/javafx` folder. The fact that it doesn't work in your case seems to suggest that maybe another instance of the module is picked up, or maybe jpackage doesn't forward the arguments to jlink correctly. – Jorn Vernee Jan 31 '23 at 03:57
  • I've tried with `jpackage` as well. I can get it to work using the jmods here. i.e. the `runtime/bin/javafx` folder is created and the app launches successfully. – Jorn Vernee Jan 31 '23 at 04:06
  • 1
    Unfortunately I think I figured it out. I somehow ended up with the aarch64 linux jmods instead of the Windows ones, which is embarrassing because I remember reading a comment by someone else who ALSO grabbed the aarch64 jmods. Now I have another error (`java.lang.ClassNotFoundException: java.util.logging.Logger`) but I'm fairly certain that's unrelated. Thanks for your help. – Iguanastin Jan 31 '23 at 04:20
  • A solution could also be to use Liberica FULL JRE/JDK as runtime image, which already includes JavaFX - https://bell-sw.com/pages/downloads/. – Wortig Feb 02 '23 at 16:08

1 Answers1

0

I'm answering my own question because I found the solution. Yes, you can include JavaFX in a jpackage launcher, and my problem was that I had accidentally downloaded the JavaFX jmods for aarch64 linux instead of windows.

Iguanastin
  • 11
  • 3
  • I am wondering why you did not stumble of this tutorial https://github.com/dlemmermann/JPackageScriptFX when you did your research. Everything would have been so much easier. We should work on the page ranking :-) – mipa Jan 31 '23 at 09:41