Packaging: jlink and jpackage
The notebook's user has no JDK, no Maven and no JavaFX libraries. They need a folder with the program or an installer. The JDK has two tools for this. jlink builds a trimmed Java runtime: only the modules the application needs, together with the application itself. jpackage wraps such a runtime in a familiar form: a program with an .exe file or an .msi, .dmg or .deb installer.
Why modules matter
jlink works only with named modules: every library must have its own module-info. JavaFX 25 and Jackson 3 have one, so our project builds without changes. From the requires lines in module-info.java jlink finds everything it needs and takes nothing extra.
Configuring the plugin
javafx-maven-plugin can call jlink. Add the parameters to its configuration:
<!-- pom.xml — the javafx-maven-plugin plugin -->
<plugin>
<groupId>org.openjfx</groupId>
<artifactId>javafx-maven-plugin</artifactId>
<version>0.0.8</version>
<configuration>
<mainClass>com.example.notes/com.example.notes.App</mainClass>
<options>
<option>--enable-native-access=javafx.graphics</option>
</options>
<launcher>notes</launcher>
<jlinkImageName>notes</jlinkImageName>
<jlinkZipName>notes</jlinkZipName>
<stripDebug>true</stripDebug>
<noHeaderFiles>true</noHeaderFiles>
<noManPages>true</noManPages>
</configuration>
</plugin>| Parameter | What it does |
|---|---|
launcher | The name of the launch script in the bin folder |
jlinkImageName | The name of the image folder in target |
jlinkZipName | Also pack the image into a zip archive |
stripDebug, noHeaderFiles, noManPages | Drop debug information, C header files and man pages |
Building the image
mvn clean javafx:jlinkMaven compiles the project and runs jlink. At the end you see Building zip: ...\target\notes.zip and BUILD SUCCESS. The warning The 0 argument for --compress is deprecated comes from jlink itself in response to an option the plugin passes; it does not affect the result. target now holds a notes folder of about 100 MB and a notes.zip archive of about 32 MB. Inside target/notes/bin are Java, the needed libraries and the notes and notes.bat launch scripts:
target/notes/bin/notesOn Windows run target\notes\bin\notes.bat. The same window opens as with mvn javafx:run. The folder or the archive can be copied to another computer with the same operating system; it does not need Java.
A program and an installer
jpackage is part of the JDK. It takes the ready image and turns it into an ordinary program:
jpackage --type app-image --name Notes --runtime-image target/notes --module com.example.notes/com.example.notes.App --java-options --enable-native-access=javafx.graphics --dest target/disttarget/dist/Notes now contains Notes.exe (Notes.app on macOS), which opens the window without a console. The app-image type is just a folder. For an installer, change --type:
| System | Types | What else you need |
|---|---|---|
| Windows | exe, msi | WiX Toolset |
| macOS | dmg, pkg | Xcode command line tools |
| Linux | deb, rpm | dpkg or rpm-build |
jpackage builds a package only for the system it runs on: a Windows installer is made on Windows, a macOS one on a Mac. Use --icon for an icon and --app-version for the version.
Common mistake
If even one library is not modular, jlink stops: Error: automatic module cannot be used with jlink: jsr305 from file:///.../jsr305-3.0.2.jar. Such a library is replaced with a modular version or an alternative. If there is no replacement, you are left with an ordinary launch through java: the whole application goes on the classpath, and JavaFX is added as modules with the --module-path and --add-modules options.