Skip to Content
Course content

315: Packaging a JavaFX Application for Distribution

Click on the "Edit" button in the top corner of the screen to edit your slide content.

You've spent weeks polishing your Library Catalog Manager. The UI is snappy, the database integration is solid, and it works perfectly in your IDE. Now comes the part where most developers start sweating: distribution. You want to send this to a client or a friend, but you're about to hit the "it works on my machine" wall if you aren't careful.

The "Just Send the JAR" Trap

The most intuitive move—and the one I see juniors do constantly—is to build a "fat JAR." You use a plugin like Maven Shade or Gradle Shadow to cram every single dependency into one giant ZIP file and tell your user, "Just make sure you have Java 17 installed and run java -jar library-manager.jar."

In the old days of Java 8, this was mostly fine. But since Java 11, JavaFX is no longer bundled with the JDK. If you go the fat JAR route, your user doesn't just need a JRE; they need the specific JavaFX modules installed and configured on their system path. I can guarantee you that your user will not do this. They'll send you a screenshot of a ClassNotFoundException: javafx.application.Application and a very frustrated email. Even if they do install the right JDK, you're still relying on the user to manage their environment variables. That's a losing game. We want the user to double-click an icon, not open a terminal.

Bundling the World with jpackage

The professional way to handle this is to stop thinking of your app as a "Java program" and start thinking of it as a "native application." We do this using jlink and jpackage. Instead of asking the user to provide the runtime, we bundle a stripped-down version of the Java Runtime Environment (JRE) directly with the app.

First, jlink allows us to create a custom runtime image. If your Library Catalog Manager only uses java.base, java.sql, and the JavaFX modules, jlink throws away the rest of the JDK (like the compiler and unused standard libraries). This keeps the footprint smaller. Then, jpackage takes that custom runtime and your code and wraps them in a platform-specific installer—an .msi for Windows, a .dmg for macOS, or a .deb for Linux.

# A simplified look at what the jpackage command is actually doing under the hood
jpackage --name "LibraryManager" \
         --input lib/ \
         --main-jar library-manager.jar \
         --main-class com.catalog.Main \
         --type exe \
         --win-shortcut \
         --win-menu

Now, when the user runs that installer, they get a real executable. They don't even need to know Java is running the show. It just works.

Trading Disk Space for Sanity

There is a trade-off here, and it's purely about file size. A fat JAR might be 5MB. A jpackage distribution will be 40MB to 100MB because it includes the runtime. To some, that feels wasteful. To me, that's a tiny price to pay for eliminating 100% of the "Java not found" support tickets.

One detail I've learned the hard way: jpackage is platform-specific. You cannot build a Windows .exe from a Mac. You have to run the packaging command on the OS you are targeting. I usually handle this by setting up a simple GitHub Action or a Jenkins pipeline that triggers builds on different OS runners, so I don't have to keep three different laptops on my desk just to ship a release.




📋 Practical Task

Packaging the Library Catalog Manager for Windows/macOS

Using the Library Catalog Manager project you've been developing, move beyond the JAR file and create a native system installer. Follow these requirements:

  • Use jlink to create a minimized runtime image containing only the necessary modules (java.base, java.sql, and the required javafx.* modules).
  • Run the jpackage tool to bundle your JARs and the custom runtime into a native installer (.msi or .dmg).
  • Configure the packaging tool to create a desktop shortcut and an application icon.
  • Verify the distribution by moving the resulting installer to a different directory (or a different machine) that does not have a JDK installed, and ensure the application launches successfully.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.