Friends of OpenJDK Today

Creating Executables For JavaFX Applications

December 08, 2023

Author(s)

  • Avatar photo
    Heshan Thenura Kariyawasam

    Heshan Thenura Kariyawasam, a self-taught programmer from Sri Lanka, specializing in Java, JavaFX, and Spring Boot. Dedicated to mastering these technologies since 2013 to create efficient and scalable applications.

Here on Foojay, you can already find some great articles on how to create native executables from your JavaFX code:

Let's take a look in this article at the current state of what can be done with jpackage and GitHub Actions.

All the sources and workflow files used here can be found in the JavaPackageDemo repository.

General Configuration

JavaFX Launch File

A Launcher.java file is needed as an entry point to your JavaFX application.

A dedicated launcher file, such as Launcher.java, serves as the entry point for a Java application, handling essential setup tasks before starting the main program. This separation streamlines code management, keeping initialization logic distinct and making the application easier to maintain and expand.

For instance, if your main JavaFX application class is named MainApplication, create another Java file named Launcher.java and include the following code:

public class Launcher {
    public static void main(String[] args) {
        MainApplication.main(args);
    }
}

Prerequisites

The process that is used here, is based on Gradle. Include the following code snippet in your build.gradle file to generate a standalone FatJar for your project.

A FatJAR is essential because it bundles an entire Java application with all its dependencies into a single file. This eliminates the hassle of managing external libraries separately, ensuring easy deployment and portability across various systems. It simplifies distribution, maintains version consistency, and allows the application to run independently without relying on external dependencies, making it an efficient and self-contained package for seamless execution.

task customFatJar(type: Jar) {
    manifest {
        attributes 'Main-Class': 'YOUR.PACKAGE.Launcher'
    }
    archiveBaseName = 'PackageDemoJAR'
    duplicatesStrategy = DuplicatesStrategy.EXCLUDE
    from { configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } }
    with jar
}
  • task customFatJar(type: Jar): Defines a new task named customFatJar of type Jar, indicating that this task will generate a JAR file.
  • manifest {...}: Sets the Main-Class attribute in the JAR's manifest file to point to the Launcher class, which serves as the entry point of your application.
  • archiveBaseName = '...': Specifies the base name for the generated JAR file.
  • duplicatesStrategy = DuplicatesStrategy.EXCLUDE: Handles duplicate files encountered during the JAR creation process by excluding them.
  • from {...}: Collects all dependencies from the runtime classpath and includes them in the JAR. configurations.runtimeClasspath gathers the project's runtime dependencies, and zipTree adds each dependency to the JAR.
  • with jar: Includes the existing JAR file (if any) generated by the default jar task along with the assembled JAR containing dependencies.

This customFatJar task amalgamates your project's code and its dependencies into a single JAR file. Upon execution, the generated JAR file will be located in the following path: build/libs

To validate the functionality of your JAR file, execute it using the command: java -jar <path to your JAR file>. This command verifies the proper execution of your Java application encapsulated within the JAR.

Building Executables with jpackage

jpackage is generally included as part of the JDK starting from Java 14. However, in certain cases or older versions where it might not be bundled or available by default, you can manually download the JDK that includes jpackage from the official Oracle or OpenJDK website. Ensure you download a JDK version that explicitly mentions support for jpackage. After downloading and installing the JDK, you should have access to the jpackage tool in the JDK's bin directory

To confirm whether jpackage is installed on your system, run the command jpackage --help on CMD or Terminal. If installed, this command will display the help information for the jpackage utility, confirming its presence and functionality.

$ jpackage --help
Usage: jpackage <options>

Sample usages:
--------------
    Generate an application package suitable for the host system:
        For a modular application:
            jpackage -n name -p modulePath -m moduleName/className
        For a non-modular application:
            jpackage -i inputDir -n name \
                --main-class className --main-jar myJar.jar
        From a pre-built application image:
            jpackage -n name --app-image appImageDir
...

Creating a native executable application requires performing the build on the target platform. For each platform, the required additional steps and the jpackage command are explained.

GitHub Workflows

By using GitHub Actions, we can remove the need to have different platforms available to build native applications. Within the repository of the example project, workflows are provided for each platform which can be used as a guideline if you want to run the same process on your own machine.

Windows

Installing the WiX Toolset, version 3.0 or later for Windows is necessary. After completing the prerequisites, execute the following command:

jpackage --input <direcory of jar file> --name <name> --main-jar <main jar file > --main-class <main class> --type <type> --win-dir-chooser

Example:

jpackage --input build/ --name PackageDemo --main-jar <mPackageDemoJAR.jar > --main-class <com.heshanthenura.packagedemo.Launcher> --type msi --win-dir-chooser

Linux

For Linux, it's required to install fakeroot. Run the following command to install fake root: apt-get install fakeroot -y.

For Red Hat Linux, it's necessary to install rpm-build package. Run the following command to install rpm-build package: apt-get install fakeroot -y. When using yum (older versions of RHEL or CentOS): sudo yum install rpm-build.

After completing the prerequisites, execute the following command:

jpackage --input <direcory of jar file> --name <name> --main-jar <main jar file> --main-class <main class> --type <type>

MacOS

For macOS, no additional installations are needed and you can immediately execute the following example command:

jpackage --input build/libs/ --name PackageDemo --main-jar PackageDemoJAR-1.0-SNAPSHOT.jar --main-class com.heshanthenura.packagedemo.Launcher --type dmg --dest build/macos/ --app-version 1.0 --vendor "Heshan Thenura"

Conclusion

Creating a native executable with JavaFX and jpackage for Windows, macOS, and Linux streamlines deployment across multiple operating systems.

Following a structured set of steps, developers can package Java applications into platform-specific native executables.

This process involves leveraging jpackage, which allows bundling the application, its dependencies, and a JRE into a standalone package, ensuring ease of installation and execution on various platforms.

Ultimately, this approach simplifies distribution, enhances user accessibility, and provides a consistent user experience across different operating systems for JavaFX applications.

Topics:

Related Articles

View All

Author(s)

  • Avatar photo
    Heshan Thenura Kariyawasam

    Heshan Thenura Kariyawasam, a self-taught programmer from Sri Lanka, specializing in Java, JavaFX, and Spring Boot. Dedicated to mastering these technologies since 2013 to create efficient and scalable applications.

Comments (0)

Your email address will not be published. Required fields are marked *

Highlight your code snippets using [code lang="language name"] shortcode. Just insert your code between opening and closing tag: [code lang="java"] code [/code]. Or specify another language.

Save my name, email, and website in this browser for the next time I comment.

Subscribe to foojay updates:

https://foojay.io/feed/
Copied to the clipboard