Creating an MSI installer from a JavaFX 11 modular desktop application

This is a follow-on article for building Java desktop applications using OpenJDK11 and OpenJFX 11. See

In this article, we are, like the previous articles, going to build the whole application using the command line.

The software tools we will use in this article are:

  • OpenJDK 11
  • OpenJFX 11
  • OpenJFX 11 modules
  • JPackager
  • Wix Toolset 3.11

See the earlier article Making a Windows MSI from a Java 11 and JavaFX 11 Desktop application for more information about these tools

What is different here is firstly the application is going to take advantage of the modular system introduced in Java 9. Secondly, we are going to build a Java Runtime Environment that includes the JavaFX modules our application requires. We will then package up the Java application with the JRE however, this will leave us with a JRE for any other Java applications providing the modules they need are included in the JRE.

Creating the JAR file

To start with we need to create a directory to use as our base. I will call mine “c:\temp\sunlounger” as this is the project I am going to build.

Next copy the source code for the application in this directory. My source code folder is called “scr” and under this folder contains all the packages, source code, and application resources.

We are now going to use the command line to build up the application. Open up a command prompt and navigate to the base directory we created earlier.

Learning from experience, some people may have more than one version of Java on their machine. To avoid using the wrong version of Java we are going to set a variable that points to our JDK, OpenJDK 11 in our case.

set JAVA="C:\Program Files\java\jdk-11.0.2\bin"

We will also set a variable to point to the libraries for our JavaFX

set PATH_TO_FX="C:\Program Files\java\openjfx-11.0.2_windows-x64_bin-sdk\javafx-sdk-11.0.2\lib"

We are going to take the source code and compile it so we have byte code (dot class files). To make this easy for projects with multiple source files we will create a source file list we can pass into the compiler and call this list “sources.txt”.

dir /s /b src\*.java > sources.txt

To compile the source code we run the Java compiler. We need to pass the path to any modules that our code requires. In this case, we are building a JavaFX application so we will make use of a number of modules from JavaFX. You can look in your module-info.java file to get a list of the modules you need to add. We also need to specify the location to put our compiled code which I’m using “jarclasses”. Finally, we pass in the list of source files to use and for this, we use the file we made in the previous step, “sources.txt”.

%JAVA%\javac --module-path %PATH_TO_FX% --add-modules=javafx.controls,javafx.fxml,javafx.graphics,java.desktop,javafx.base -d jarclasses @sources.txt

Note: If your application makes use of external Jars files you will need to add these into the Java compile command. If for example, I wanted to use “calendar.jar” then I would create a folder in my base directory called “libs” and place the jar file in there. Then I would include the path to that folder in the module path and finally, I would add the modules required. Something like this:

set PATH_TO_LIBS =" C:\Temp\sun2\libs"
%JAVA%\javac --module-path %PATH_TO_FX%;%PATH_TO_LIBS% --add-modules=javafx.controls,javafx.fxml,javafx.graphics,java.desktop,javafx.base,calendar.appointments -d jarclasses @sources.txt

A lot of applications make use of none code files, resources such as images, cascading style sheets, or configuration files. These need to be carried across to our completed application. We do this by wrapping them up into our application Jar file.

To achieve this we will copy all the files from the “src” folder that do not have the file extension “.java” and place them in the same folder as our compiled code, the “jarclasses” folder. We need to maintain the folder structure as part of the copy.

First, we create a small text file that contains the values we want to exclude when we copy the files. The file, excl.txt, will just contain “.java” and the only contents.

echo .java > excl.txt

Using the file, we copy all the files from the “src” folder to the “jarclasses” folder, maintaining the folder structure, where any part of the file name does not match what is in the “excl.txt” file.

xcopy src\*.* jarclasses /S /I /E /Y /EXCLUDE:C:\Temp\SunLounger\excl.txt

We now have everything in place to build our application Jar file. To build the Jar file we call the jar command, pass the name of the jar file to create, the main class to launch when starting, where to find the class files, and include all the files found in the folder and all its subfolders.

mkdir app
%JAVA%\jar --create --file=app/sunlounger.jar --main-class=application.Launcher -C jarclasses .

Creating the JRE with JavaFX

We will use a JDK tool call JLink. This allows us to build a Java Runtime Environment using the modules specified in the build command.

We will call JLink passing it the module path, much like we did when compiling the source code. We also specify the modules to include in the build, again like we did when compiling the application.

For this build, we will need access to the Java and JavaFX modules. To make it easy to reference these we will define variables to point to these locations.

set JAVA_MODS="C:\Program Files\java\jdk-11.0.2\jmods"
set FX_MODS="C:\Program Files\java\javafx-jmods-11.0.2"

Note: The JavaFX modules are provided as a separate download so may not be with the OpenJFX Software Development Kit.

With these values set we can now call the JLink tool to build the JRE.

%JAVA%\jlink --module-path %JAVA_MODS%;%FX_MODS% --add-modules=javafx.controls,javafx.fxml,javafx.graphics,java.desktop,javafx.base --output fxjre

With both the Jar and JRE build we can test our components by typing this at the command prompt

C:\Temp\sun2\fxjre\bin\java -jar app\sunlounger.jar

And the application should launch.

Packaging up the application

To package up the application we will make use of the JPackager tool.

Note: Please read the article Making a Windows MSI from a Java 11 and JavaFX 11 Desktop application for information about JPackager and where to obtain this tool as it is not part of OpenJDK 11.

We will create an install package, on a Windows machine this will be an MSI file. The MSI file will be written into the “build” subfolder and the file name will be “SunLounger”. The MSI file will launch Java using the sunlounger.jar runnable jar file. We can package up any Java Runtime Environment into the MSI; we will use the environment we just created. Finally, we will give our application a version number, set the icon to use on the MSI file, and specify the vendor name.

%JAVA%\jpackager create-installer --output build --input app --name SunLounger --main-jar sunlounger.jar --runtime-image "C:\Temp\sun2\fxjre" --version 1.0 --icon sunbed.ico --vendor softwarepulse

What we end up with is an MSI file located in the build subfolder. Double-clicking this file launches the installer which installs the application on the Window operating system. We can then find our application under the Start button under the “softwarepulse”, the vendor name.

Leave a Reply

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

This site uses Akismet to reduce spam. Learn how your comment data is processed.