Java Artifacts Just Got Better: jpackage is Production Ready in Java 16

jpackage is Production Ready in Java 16

JDK (Java Development Kit) 14 added an incubating feature to the Java toolkit – the ability to pack a self-contained Java application. The newly released Java 16 takes it to production, and you are going to learn all about it.

If you shudder thinking about compilation for different platforms, I know the feeling. One of the Java promises, the WORA (Write Once, Run Anywhere) principle, while revolutionizing platform independence, it stopped short of one more step – to be able to deploy anywhere. Personally, I think that WORADA sounds awesome, but I guess before Docker it didn’t occur to people that eliminating “works on my machine” is as simple as shipping your machine.

So you wrote a class, you’ve built a jar file and then you needed the right JVM (or JDK) and all the right dependencies, organized in a very particular way in order to make it work. What are the chances this knowledge will be consistently transferred intact from the Dev silo to the Ops silo?

The “Ship Your Machine” Container Revolution

Everything changed with containers. While in years past the complaint “I have a very hard time deploying Java applications” was met with “Well, at least it runs on every platform, everything else doesn’t even do that,” the rise of Docker and containers blew the “At least it’s multiplatform” argument out of the water. Suddenly, multi-platform support is much less important (since you ship the target platform) but having a package, which will contain the entire application emerged as a winner. 

Meet jpackage, the Native Java App Installer Generator

Only 4 years after the first release of Docker JEP 311: Java Packager API & CLI saw the light of day. The idea was to take the old and abandoned javapackager tool (whose goal was “to be used as an alternative to an Ant task” — it’s a quote from the Oracle official documentation, I kid you not!) clean it up, document it, provide a proper API and allow Java developers to create proper installers. It was replaced with JEPs 343 and 392: Packaging Tool in the release of Java 16, which is a clean rewrite, and it is awesome. Here we go:

$ jpackage create-installer --runtime-installer \
    --name  --output outputdir

Boom, you’ve just created an installer (.msi/.exe1, .dmg, or .deb/.rpm) that includes EVERYTHING (your app, your dependencies, the entire JRE, and the kitchen sink). 

Empower your maven builds with JFrog's Artifactory DevOps tool

EVERYTHING? That Sounds Like A Lot!

It actually is! But you don’t really have to pack everything. Run something like the following to create an executable with only your application:

$ jpackage --name myapp --input lib --main-jar main.jar \
    --main-class myapp.Main

The package will include a launcher for the application, also called myapp. To start the application, the launcher will place every JAR file that was copied from the input directory on the classpath of the JVM.

Hey, Where Did my JRE Go?!

But.. But.. didn’t we just defeat the entire purpose by excluding the JRE? Yes we did. Let’s find a middle way by including the JRE, but not all of it. You can use the jlink command to create a subset of the JRE, including only the modules you really need:

$ jlink --add-modules java.base,java.sql --output smalljre

Now you have a custom (and tiny) JRE called smalljre. Let’s create an installer with it, instead of the entire beast:

$ jpackage --name myapp --input lib --main-jar main.jar \
    --runtime-image smalljre

Isn’t jpackage cool? It is! Does it replace Docker? Not really. Was it really meant to replace Docker? No. So, what gives? Well, now we have a standalone Java application, we can just Run Anywhere. 

Getting Your Java Package Anywhere

Great, we created an awesome package. Now what? Well, it depends on what this package is. Here are a couple of options:

  • It’s a downloadable desktop application. In that case, you need a cloud distribution service. JFrog Platform offers a free cloud account that does exactly that. You can deploy your Java package to a generic repo and let people download it to their devices. 
    • JFrog Platform also serves as Debian and rpm package repository types so you can host and serve your Debian and rpm Java packages natively!
    • If you want to improve the distribution experience even further, other JFrog Platform subscription levels include CDN (Content Delivery Network) support which provides better download speeds anywhere in the world. 
  • It’s a part of a Docker image. In that case, grab a free JFrog Container Registry for self-hosting or open a free cloud account on a JFrog Platform. In both cases, you get a free Docker registry for your Docker images, and a generic repository for the contents of those images, i.e. our Java package. Next, a simple ADD instruction will copy a single file – the Java package to your image, keeping your Dockerfile clean, simple and tidy.

Java 16 – Applications Simplified

Grab all your jars, add any JRE, pack them all together with a simple command, and suddenly the question of every Java newbie “How the heck do I make an application out of this mess” is a reality thanks to jpackage. Make it accessible to any target or end-user using the JFrog Platform and you have a winning combination!

Read more about Java 16 release and how it affects the Java community in this blog post:
Java 16 Commits to Git and GitHub: A Personal Reflection


Java® is a registered trademark of Oracle and/or its affiliates.