I am a beginner for JavaFX. I have a JavaFX & Spring Boot application which runs as a STOMP Websocket client. I did build it as a jar file and it runs well with Java command. My question is how to wrap it in a Windows/Mac/Linux installer (including JRE) so that it can be installed easily on other computers. My pom.xml
<?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>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.1</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.my-group</groupId>
<artifactId>my-app</artifactId>
<version>1.0</version>
<name>my-app</name>
<properties>
<java.version>17</java.version>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
<version>5.2.1</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>19.0.2.1</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-fxml</artifactId>
<version>19.0.2.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
My main class
package com.mygroup.myapp;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import java.awt.*;
@SpringBootApplication
public class MyApplication extends Application {
private ConfigurableApplicationContext applicationContext;
private Parent rootNode;
public static void main(String[] args) {
if (!SystemTray.isSupported()) {
System.setProperty("java.awt.headless", "false");
}
Application.launch(args);
}
@Override
public void init() throws Exception {
applicationContext = SpringApplication.run(MyApplication.class);
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/login.fxml"));
fxmlLoader.setControllerFactory(applicationContext::getBean);
rootNode = fxmlLoader.load();
}
@Override
public void start(Stage primaryStage) {
Platform.setImplicitExit(false);
primaryStage.setResizable(false);
primaryStage.setScene(new Scene(rootNode));
primaryStage.show();
}
@Override
public void stop() {
applicationContext.close();
Platform.exit();
}
}
I have tried this tutorial using JPackage but it does not run after installation.
Background
This example is only for creating a Windows Installer for a JavaFX SpringBoot application, using Maven and
jpackagerunning on Windows, with the assistance of IntelliJ Idea, though the steps will work for any Java application and can performed without Idea, (given some adaption and modification).This is not a guide on how to integrate SpringBoot with JavaFX, but rather how to package and deploy such an application to a Windows machine.
There are a lot of steps here, the reason for that is:
As long as you follow this guide, you should be able to create an installer in a reasonable amount of time and have some chance of troubleshooting the build and installation process when something goes wrong.
Steps
Package your App into an Installer
Install Java
Configure your JAVA_HOME with JDK 21+.
Install the JavaFX SDK 21.0.1+.
Install Wix 3.x.
In Idea 2023.3.2 or later, create a new JavaFX project.
wininstalled.Delete the
module-info.javafile.Upgrade the maven version in the maven wrapper of the generated project.
Edit
<your project home>\.mvn\wrapper\maven-wrapper.propertiesEnsure the version listed in the distributionUrl is at least 3.9.6.
This is because the akman jpackage plugin used here requires at least that version of maven to work.
Replace the generated pom.xml file, with the one below.
Reimport the Maven project into Idea.
Go to the HelloApplication, and try to run it.
Edit the run configuration that your execution attempt generated so that you can set the VM arguments for it.
Set these values (adjust for additional or removed JavaFX modules as needed):
Make sure you set VM arguments NOT program arguments.
Do actually click the link and study the image of how the VM arguments are set, so you don't make a mistake here.
Run the application again, it should run in the IDE.
Copy the icon file for your application from icon archive (Choose
All Download formats | Download ICO) toGo to the Maven panel in the IDE, your project name there should be the name configured in the pom.xml (
wininstalled), underLifecycle, double clickclean, then clickinstall.Your application will be built and packaged.
What the packaging did
target/jpackage-inputdirectory.jpackageusing the akman plugin configuration.jpackagewill create a jlinked image of the java runtime using a default set of modules and the modules listed in the akman configuration (these include both modules from the JDK and modules from JavaFX) and those will be baked into the imagejpackagewill copy the non-modular dependencies from thetarget/jpackage-inputdirectory and configure the application startup executable that it creates to run with the non-modular jars on the classpath.jpackagewill invoke Wix to create an installer for the application.<your project>/target/jpackage/<your project name>.exefile.Install the app
To run the installer, select the Terminal tab in Idea
Execute the installer
jpackageconfiguration assigned Windows to use for the application update and to display when the user queries version information on the installed application in the OS.The installer will execute and install the application onto your machine.
The application is installed under:
A shortcut to the application with the coffee icon you configured will be added to your desktop.
The app is also available from the Windows Start menu,
The app can be removed via the Windows Add or Remove Programs item in the Windows Control Panel.
You can double click your application icon to run your app.
You can run the application from the command line by executing the
.exefile which has been installed (not the installer exe, but the program exe).Updating the App
Troubleshooting
When things go wrong, which is quite likely . . . for instance, maybe you click the icon of the installed application and nothing happens, and then you think you are stuck, but you are not . . .
<user dir>/AppData/Local/<your app name>/<your app name>.exefile from the command line (this is the installed app, not the installer app). If it fails with a stack trace, you will now see the stack trace in the console explaining what went wrong.References
jpackagedocumentation - official documentation from Oracle.Creating installers for non-SpringBoot or non-JavaFX applications
Most of the steps described here are general for packaging any Java program and not specific for SpringBoot or JavaFX. So you can apply these steps for other application types with some modifications.
Even though the target here is SpringBoot, most of the information is generic to deploying a Java application on Windows using a Windows Installer and not that specific for SpringBoot. The only real complication with SpringBoot is that it works best with a non-modular application, but other than that there is nothing special about it in respect to creating installers.
Similarly, for JavaFX it is only supported when used as modules, so that is what is demonstrated here. Note that a non-modular application can still use JDK and JavaFX modules, so having a non-modular application that uses SpringBoot in a non-modular way, but uses a custom modular Java runtime and JavaFX modules is fine.
Creating a cross-platform build
The steps described here are for a Windows-only build.
Steps to create installers for other platforms can be followed and are largely similar to the steps outlined here for Windows. However, they must be run on a machine of the same type as the target platform you are building for, and will create a platform-specific installer for that machine type.
The installers built by
jpackagewill differ, not only by OS, but by architecture type (for instance a Mac Intel installer must be created on a Mac Intel machine, and a Mac M-series processor installer must be created on a Mac M-series machine).The steps for other platforms will differ slightly (e.g. linux builds will use
rpmordebpackaging rather than wix packaging, andmacbuilds will create Mac-type package formats such aspkgordmg). There are different requirements for some things like icon types and formats for different platforms, as well as possibly requirements for signing the app for distribution, which may require paid developer certificates. None of those topics are covered here, but there is information on them in thejpackageresource guide from Oracle.Example pom.xml
Related