Currently, we have Java 12 without any build-in packaging tool. But there is hope! JPackage is the new tool for packaging self-contained Java applications.

Now, what is JPackage? JPackage is a command line tool. It takes an application and a JVM image and creates platform specific bundles from then. It creates exe and msi files on Windows for example, and deb and rpms for Linux. The problem is: it is currently only available as an early-access build for Java 14! What to do now? Must be build our application with this early access thing? It turns out: no!

As mentioned, JPackage takes an application and an jvm image as inputs. We can use the early access JPackage binary and use it to create a native bundle from an application and an Java 12 runtime image! Pretty cool, right?

To create an installer for an application, we have to

Download OpenJDK 12

Download JPackage

Point JAVA_HOME to the OpenJDK 12 installation

Point JPACKAGE_HOME to the JPackage installation

Install fakeroot and rpm packages if we are on Linux

Install Inno Setup and Wix Toolset if we are on Windows

Now we can invoke the JPackage tool in a very general way:

package.sh $JPACKAGE_HOME/bin/jpackage (1) --package-type rpm --runtime-image $JAVA_HOME (2) ..rest of required arguments

1 Invoking the jpackage binary 2 Passing in the OpenJDK 12 installation as runtime image

I’ve left out all other required command line arguments for clarification. Please take a look at the JEP documentation or just checkout FXDesktopSearch, which includes a working Maven pom to see the whole packaging process in action. The tricky part are the cross platform builds. We have to invoke JPackage for Windows builds in a different way than Linux builds. This is encapsulated in my example by Maven Profiles.

There are other subtle issues around. JPackage does not support cross platform builds. We have to invoke the tool on a Windows box to get Windows binaries, on a Linux box to get Linux binaries and so on. If we have a Windows 10 64bit machine, there is a neat trick available. Say hello to the Microsoft Windows Subsystem for Linux!

The Windows Subsystem for Linux is a cool thing. It is basically a running Linux shell (Ubuntu for instance) on our Windows desktop. We can do all the cool Linux stuff, and use all the Linux tools, but on a running Windows machine, without installing VirtualBox or VMWare. We can also access the whole Windows file systems from Linux shell side by using special mount points.

This introduces a pretty cool way to create true cross platform builds without having multiple build servers! We can create the Windows binaries by invoking JPackage on Windows, then switch to the Windows Linux Subsystem and invoke it to create the Linux binaries! Now, how long does my FXDesktopSearch example build take on Windows? Well…​

windowsbuild [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 02:45 min [INFO] Finished at: 2019-04-23T13:34:18+02:00 [INFO] Final Memory: 59M/207M [INFO] ------------------------------------------------------------------------

linuxbuild [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 02:35 min [INFO] Finished at: 2019-04-23T11:39:17Z [INFO] ------------------------------------------------------------------------

The Subsystem for Linux needs some configuration to make it work properly with JPackage. First, JPackage relies on fakeroot. Fakeroot does not work property, we have to use fakeroot-tcp. This can be easily configured by:

configurefakeroot.sh sudo update-alternatives --set fakeroot /usr/bin/fakeroot-tcp

Then we have to configure file permissions. Add the following configuration section to the wsl.conf inside of the Linux shell:

/etc/wsl.conf [automount] enabled = true root = /mnt/ options = "metadata,umask=22,fmask=11"

and we have to set the right umask:

~/.bashrc umask 0022

Oh, and by the way: to launch graphical user interfaces from the Linux subsystem, we have to install an X11 server on our Windows machine and set the DISPLAY variable on Linux side accordingly:

~/.bashrc export DISPLAY=:0

We now have a working cross platform build environment. The last open point is software package distribution. App stores are very popular today. So why not distribute our Java applications using an App Store?

We already have platform specific packages available. How would be publish a Windows build into the Microsoft Office Store? It turns out, this is pretty straightforward. We just have to convert the msi files to msix files by using the MSIX Packaging Tool, which can also be downloaded from the Microsoft App Store. The result of the conversion can then be published.