1

I'm developing an app using JavaFX, but I've encountered a problem creating a build and converting it into an executable app. Several years ago, I created a small app using this technology, and I remember that Intellij IDEA allowed me to create a native executable for almost any desktop operating system (Windows, Mac, or Linux). However, that strategy didn't work for me in this project. According to what I've been reading online, the JavaFX project was natively separated from the Oracle JDK, so it needs to be run independently.

I'm developing this new project with Oracle OpenJDK 23 and intending to use it only in Windows environments. I've been researching how to create an executable build of this app using Maven plugins (I've already tried some variants) and nothing has worked. I managed to get the resulting .jar file to be of shade type and contain all the libraries used by the project. I've attached my pom.xml file.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
 <modelVersion>4.0.0</modelVersion>
 <groupId>cu.nerzur</groupId>
 <artifactId>WallpaperEngine</artifactId>
 <version>0.2.2</version>
 <name>WallpaperEngine</name>
 <description>WallpaperEngine</description>
 <properties>
 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
 <junit.version>5.10.2</junit.version>
 <java.version>23</java.version>
 </properties>
 <dependencies>
 <!-- reduce boiler plate -->
 <dependency>
 <groupId>com.sangupta</groupId>
 <artifactId>jerry-core</artifactId>
 <version>3.0.1</version>
 </dependency>
 <!-- for making HTTP calls -->
 <dependency>
 <groupId>com.sangupta</groupId>
 <artifactId>jerry-http</artifactId>
 <version>2.0.0</version>
 </dependency>
 <dependency>
 <groupId>org.projectlombok</groupId>
 <artifactId>lombok</artifactId>
 <version>1.18.38</version>
 <optional>true</optional>
 <scope>provided</scope>
 </dependency>
 <dependency>
 <groupId>net.java.dev.jna</groupId>
 <artifactId>jna</artifactId>
 <version>5.13.0</version>
 </dependency>
 <dependency>
 <groupId>net.java.dev.jna</groupId>
 <artifactId>jna-platform</artifactId>
 <version>5.13.0</version>
 </dependency>
 <!-- https://mvnrepository.com/artifact/org.openjfx/javafx-controls -->
 <dependency>
 <groupId>org.openjfx</groupId>
 <artifactId>javafx-controls</artifactId>
 <version>26-ea+3</version>
 </dependency>
 <!-- https://mvnrepository.com/artifact/org.openjfx/javafx-fxml -->
 <dependency>
 <groupId>org.openjfx</groupId>
 <artifactId>javafx-fxml</artifactId>
 <version>26-ea+3</version>
 </dependency>
 <dependency>
 <groupId>org.openjfx</groupId>
 <artifactId>javafx-swing</artifactId>
 <version>26-ea+3</version>
 </dependency>
 <dependency>
 <groupId>org.junit.jupiter</groupId>
 <artifactId>junit-jupiter-api</artifactId>
 <version>${junit.version}</version>
 <scope>test</scope>
 </dependency>
 <dependency>
 <groupId>org.junit.jupiter</groupId>
 <artifactId>junit-jupiter-engine</artifactId>
 <version>${junit.version}</version>
 <scope>test</scope>
 </dependency>
 <!-- for JSON parsing -->
 <dependency>
 <groupId>com.google.code.gson</groupId>
 <artifactId>gson</artifactId>
 <version>2.13.1</version>
 </dependency>
 </dependencies>
 <build>
 <plugins>
 <plugin>
 <groupId>org.apache.maven.plugins</groupId>
 <artifactId>maven-compiler-plugin</artifactId>
 <version>3.14.0</version>
 <configuration>
 <release>23</release>
 <annotationProcessorPaths>
 <path>
 <groupId>org.projectlombok</groupId>
 <artifactId>lombok</artifactId>
 <version>1.18.38</version>
 </path>
 </annotationProcessorPaths>
 <compilerArgs>
 <arg>-Xlint:all</arg>
 </compilerArgs>
 </configuration>
 </plugin>
 <plugin>
 <groupId>org.apache.maven.plugins</groupId>
 <artifactId>maven-shade-plugin</artifactId>
 <version>3.6.0</version>
 <executions>
 <execution>
 <phase>package</phase>
 <goals>
 <goal>shade</goal>
 </goals>
 <configuration>
 <transformers>
 <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
 <mainClass>com.nerzur.wallpaperengine.Init</mainClass>
 </transformer>
 </transformers>
 <filters>
 <filter>
 <artifact>*:*</artifact>
 <excludes>
 <exclude>META-INF/*.SF</exclude>
 <exclude>META-INF/*.DSA</exclude>
 <exclude>META-INF/*.RSA</exclude>
 </excludes>
 </filter>
 </filters>
 </configuration>
 </execution>
 </executions>
 </plugin>
 <plugin>
 <groupId>org.openjfx</groupId>
 <artifactId>javafx-maven-plugin</artifactId>
 <version>0.0.8</version>
 <executions>
 <execution>
 <id>default-cli</id>
 <configuration>
 <mainClass>com.nerzur.wallpaperengine.Init</mainClass>
 <launcher>app</launcher>
 <jlinkZipName>app</jlinkZipName>
 <jlinkImageName>app</jlinkImageName>
 <noManPages>true</noManPages>
 <stripDebug>true</stripDebug>
 <noHeaderFiles>true</noHeaderFiles>
 </configuration>
 </execution>
 </executions>
 </plugin>
 </plugins>
 </build>
</project>

But I still can't get the Java FX runtimes to be included, and I get an error message when running the jar with the command java -jar app.jar.

PS D:\Development\SpringBoot\WallpaperEngine\target> java -jar .\WallpaperEngine-0.2.2.jar
Error: JavaFX runtime components are missing, and are required to run this application
PS D:\Development\SpringBoot\WallpaperEngine\target>

Some solutions mention using a module-info.java file to create a Java module that includes JavaFX dependencies. However, when creating this file, errors start to appear because I'm using dependencies that aren't backed by modules, or so it seems. I'm not currently using this file, but when I had it integrated into the project, it looked something like this.

module com.nerzur.WallpaperEngine {
 requires javafx.controls;
 requires javafx.fxml;
 requires javafx.graphics;
 requires java.desktop;
 requires transitive static lombok;
 requires transitive slf4j.api;
 requires transitive jerry.http;
 requires transitive jerry.core;
 requires transitive java.net.http;
 requires transitive com.google.gson;
 requires transitive com.sun.jna;
 requires transitive com.sun.jna.platform;
 
 opens com.nerzur.wallpaperengine to javafx.fxml;
 opens com.nerzur.wallpaperengine.controller to javafx.fxml;
 
 exports com.nerzur.wallpaperengine;
 exports com.nerzur.wallpaperengine.controller;
 exports com.nerzur.wallpaperengine.service;
 exports com.nerzur.wallpaperengine.scheduledTask;
 exports com.nerzur.wallpaperengine.util;
}

The only solution I've found to make this project compilable is to use Launch4j (an external app) using the current pom.xml and deleting the module-info.java file. Then, pass a fixed path for the JRE and another path with the JVM execution options as parameters with the following command: --module-path "C:\WallpaperEngine\libs\javafx-sdk-24.0.2\lib" --add-modules javafx.controls,javafx.fxml,javafx.swing" which indicates the absolute path of the JavaFX SDK. This forces me to copy the app to an absolute path on the PC and include both SDKs in the compiled APK (which doesn't seem optimal to me).

Is there any other way to create an executable for this type of application that doesn't involve such drastic methods?

Mark Rotteveel
110k237 gold badges158 silver badges229 bronze badges
asked Sep 1 at 13:16
8
  • 3
    "I get an error message" you have to add the complete error to the question so people can help you to solve it. Commented Sep 1 at 14:03
  • For Launch4j, suppose your app directory is C:\WallpaperEngine. Then the parameter should be adjusted to use a relative directory: .\libs\javafx-sdk-24.0.2\lib --> --module-path ".\libs\javafx-sdk-24.0.2\lib" Commented Sep 1 at 14:40
  • @life888888 thanks, applying the idea you mentioned about using relative paths I was able to run the app in any directory using launch4j, the --module-path command changed to this: --module-path "%EXEDIR%\libs\javafx-sdk-24.0.2\lib" --add-modules javafx.controls,javafx.fxml,javafx.swing Commented Sep 1 at 15:58
  • 2
    The JDK comes with a tool that does this. I don't usually build with Maven, but I assume this plugin is the one you would want to use. Commented Sep 1 at 17:03
  • Example of using Maven and jpackage to package a JavaFX application. You are using JNA, indicating custom native components, so the solution to your issue would be more complicated. You want to create an APK for Android, so it is probably best to use a technology targeted at that (e.g. Gluon Mobile). Commented Sep 2 at 17:31

0

Know someone who can answer? Share a link to this question via email, Twitter, or Facebook.

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.