Using the Java Packager with JDK 11

Update: jpackage is now Production-Ready

This article is based on a very early, pre-release version of what has become jpackage. As of JDK 16, jpackage is now production-ready. For that reason, I’d recommend that you now use jpackage as described here in my new updated article, Installable Java Apps with jpackage, rather than using the technique described in this Medium article. However, I’ll leave this article here, just in case anyone still needs the reference.

Installable Java Apps with jpackage

Introduction

Would you like to package your Java 11 application so that anyone can install it and run it without first having to install Java? Would you like to distribute your work just like any other native application for Mac, Linux and Windows? I’ve done this for my Open Source project and in this article I’ll share how it was done, what problems I encountered and the solutions that I found. I hope that my experience will be a useful guide to anyone else attempting this in their own project.

Santulator: The Application Being Packaged

Santulator in use

Beginning a Journey

Before we get into the detail, I should point out that this post represents the beginning of a journey. As you will see there are some problems to be ironed out in the packaging process and I’m sure lots of things that I will improve in my approach to it over time. It was important to me to release a first working version of Santulator and then to worry about perfecting the way that it is packaged in later releases. If you see any errors or things to be improved, please point them out in the comments. Even better, if you are able to improve something, do create a pull request and link that in your comment so that other people can clearly see how the problem is solved.

What Are We Trying to Achieve?

At this point, it’s worth spelling out exactly what I want to achieve. Here’s a list of the main aims:

  • It should be simple for a non-technical user to install the packaged software.
  • Once installed, the software should run just like any other program on the system.
  • There should be installable bundles for Mac, Linux and Windows.
  • The application should have a launch icon that then shows with the application when it is running, for example in the Dock on the Mac.
  • When the packaged software is running, only the application windows should show. There should be no shell or batch file window left in the background.
  • The installer should register the file extension .santa with the operating system. Session files (.santa files) should then be shown in the operating system file browser with the associated session file icon.
  • Double-clicking a session file (.santa file) should open up the packaged application and show the saved session.
The main application icon and the session file icon

The Tools for the Job

To package up the software we need the right tools for the job. Here is a list of the main software I use in this example:

  • AdoptOpenJDK provide pre-built JDK 11 binaries. These are a great choice for an Open Source project.
  • Key to this is the Java Packager itself. As you can see from the link, this is actually a back-port of software that will be included in a later release of the JDK.
  • JLink is used by the Java Packager to reduce the included parts of the JDK to just those modules that we actually need. Note that this doesn’t need to be dowloaded and installed separately as it comes with the JDK.
  • Santulator has a JavaFX user interface so we need the JavaFX JMOD module files. These are available from Gluon.
  • On Windows we need Inno Setup which is a tool for building installable bundles.
  • It is convenient to include the creation of the installable bundle as part of the standard build process for the software. Santulator is built using Gradle so I have placed the packaging under the control of the Gradle build. Since Santulator uses the Gradle Wrapper, you don’t need to download and install Gradle separately.

Installing the Java Packager

As mentioned in the previous section, the Java Packager needs to be downloaded. For Mac and for Linux the software bundle can be uncompressed into any directory. We need to make a note of this directory as it has to be passed to the build process later for the packaging.

  • jpackager.exe%JAVA_HOME%\bin
  • jdk.packager.jar%JAVA_HOME%\jmods

The Mystery of the Missing Windows DLLs

First I should confess that I’m no expert on Windows so bear with me on this. During my work on Santulator, I discovered a problem using the Java Packager on Windows. You can see the problem clearly in the following screenshots:

Missing MSVCP140.dll
Missing VCRUNTIME140.dll

Windows Inno Setup

To build the installable bundle on Windows, we need the Inno Setup software. This is a great tool for creating installers on Windows. In theory it should be possible to get the Java Packager to run Inno Setup directly, however this didn’t work for me. Instead on Windows I use the Java Packager to create a directory containing the required files that is then passed to Inno Setup. I also generate an .iss file that Inno Setup reads, containing instructions to create the bundle.

Running the Java Packager

The output of the Java Packager depends on the operating system for which we are building the installable bundle. The Java Packager supports various different types of installers but here are the outputs I use for the three target operating systems:

  • On the Mac I create a .pkg installer file. When launched, this guides the user through a wizard for installing the software on their Mac.
  • On Linux I create a .deb bundle. This can then be installed directly on Debian-based systems such as Ubuntu Linux.
  • On Windows I create a directory that is suitable for passing to Inno Setup for building the final installable bundle.
JPackager on the command line

JLink

As of Java 9, the JDK has now been modularised. This is great news for anyone building an installable bundle as it means that you need only include those parts of the JDK that your project requires. Amongst other things this helps to reduce the size of the bundle file created at the end of this process. If you’re interested in seeing an example of how JLink can be used, take a look at this article by Simon Ritter that provides a lot of useful detail.

Wrapping It All up with Gradle

I chose Gradle as the build tool for Santulator. I decided to keep the shell and batch scripts simple and include the real logic in the Gradle script, build.gradle. I have found that it’s sometimes difficult to discover why the Java Packager has failed if, for example, a required file is missing. From this experience, my conclusion has been that the best way to reduce problems like these is to check as many prerequisites as possible in the Gradle script before launching the Java Packager. That way the Gradle script can fail with a useful error message rather than leaving the error handling to the Java Packager.

  • The path to the JavaFX JMOD files.
  • The path to the Java Packager. Actually, you don’t need to pass this on Windows as you are required to install the Java Packager files directly inside directories under JAVA_HOME.
./gradlew clean createBundle \
-PjavafxJmodsPath=/opt/javafx-jmods-11 \
-PjavaPackagerPath=/opt/jpackager-11
  1. Check all the prerequisites. This makes sure, for example, that the JavaFX modules path has been passed as a Gradle property and that it actually contains some module files.
  2. Copy the Java JAR file dependencies into place.
  3. Prepare the file association properties file. This file is later passed to the Java Packager with information about the .santa file extension for Santulator session files and the icon to associate with them.
  4. Launch the Java Packager. This is done by running build-package.sh on Linux and Mac and build-package.bat on Windows.
  5. On Windows, copy the missing DLLs into place (see the section above describing this) along with the icon file for .santa session files.
  6. On Windows, prepare the Inno Setup file.

Running Inno Setup on Windows

In theory, the Java Packager can run Inno Setup automatically and create the Windows setup file. However, I found that this didn’t work for me. Rather than delay the release of Santulator to look for a solution, I decided that it would be better just to use the Java Packager on Windows to create the image directory and then to launch Inno Setup manually. To make this easier, I make use of Gradle to prepare the .iss file that contains the instructions for Inno Setup. You can see the code here in build.gradle that prepares the file.

Inno Setup

Help, My Application Won’t Start!

If you’re anything like me, you won’t get this working the first time around. You’ll find you have an application that doesn’t start up and you’ll be left to debug the problem. So I thought I’d share a couple of tips I learned along the way to help.

./gradlew clean :gui:run
package/build/bundle/Santulator.app/Contents/MacOS/Santulator

The Finished Product

This really does work! Download Santulator to see an example and try it out yourself on your own project. Here’s the installer that I produced running on a Mac:

The Santulator installer on the Mac
The Santulator installer on Windows
The Santulator installer on Linux

Rough Edges: Windows

Out of the three platforms, I had most difficulties with Windows, perhaps due to my lack of familiarity with the platform. The biggest shortcoming of the packaging process I outline in this post as far as Windows is concerned is the need to run Inno Setup manually afterwards. In theory it should be possible to get the Java Packager to do this and thus avoid the extra step. I didn’t have time to find a solution to this and since I had the workaround of running Inno Setup manually, I was able to manage without. As a second best to getting Java Packager to run Inno Setup directly, it should be possible to automate this step with Gradle to avoid the need to run it by hand.

The Windows installer, with a generic icon

Rough Edges: Mac

The Mac bundle comes as a .pkg installer. A full installer seems a little unnecessary for a self-contained application. Arguably it would be better to distribute Santulator as a .dmg file. The Java Packager offers the option to do this but when I tried, I was only able to generate a .dmg file containing a .pkg file within it, which rather defeats the purpose.

The Mac installer, with a generic icon

Rough Edges: Linux

Saved .santa files are correctly associated with Santulator but for some reason the session file icon is not shown in the Ubuntu file browser. Take a look at the following for comparison:

The problem with the session icon on Linux
Linux Installer GUI on Ubuntu 18.04

What the Future Might Hold

Santulator is under active development so this article represents a snapshot in time. Over time the packaging will improve and some of the wrinkles identified here will be ironed out. Similarly, the Java Packager used here was a back port to JDK 11 and in the future it will be improved and will be included in the JDK itself.

JavaFX

Santulator has a JavaFX user interface that works well on Mac, Linux and Windows. For this reason it makes a lot of sense to offer an installable bundle in order to make it as easy to install as it is to use and the Java Packager offers this. However, it should be noted that the Java Packager isn’t just intended for JavaFX-based applications and so it may also be applicable in your JDK 11 software even if you don’t use JavaFX.

What to Do If You Haven’t Upgraded to JDK 11 Yet

If you haven’t upgraded your Java application to JDK 11 yet but would still like to package it, you could well be in luck. Firstly, you might find that after updating all of your dependencies, with a few small changes your application will run as expected on JDK 11. If it’s a JavaFX application you’ll need to do what I describe in this article and make use of the OpenJFX 11 Java modules provided by Gluon. Doing this will get you all of the benefits of the latest JDK, the Java Packager and the chance to reduce the size of the installable bundle thanks to JLink.

Final Thoughts

I hope that this article has inspired you to give the Java Packager a try on JDK 11. Also, as the author of Santulator I’d like to invite you to download the program and try it out. It’s free and Open Source. Feel free to fork the Santulator repository on GitHub and play around with the code to see how it works. To keep up with the latest developments relating to Santulator and VocabHunter, follow @VocabHunterApp on Twitter.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Adam Carroll

Adam Carroll

I’m a Java software developer, based in Barcelona