Java SE 16: Packaging Tool

Many application require to be installed on the native platform (Linux, Windows, MacOs or etc.)

The  goal of the JEP-392 it to provide a package tool based on the legacy JavaFX javapackager. Such tool fulfills following:

  1. Supports native packaging formats to provide natural installation experience
  2. Allows launch-time arguments specified at packaging time
  3. Available from the programmatically, command-line or ToolProvider API

Java SE 16  provides a final release of the packaging tool that allows to deliver installable package suitable for the native platform. The tool can generate following formats:

Linux: deb, rpm
MacOS: pkg, dmg
Windows: msi, exe

The “jpackage” tool creates an executable platform specific package from a Java Application with all required dependencies.  Java application can be represented as the collection of  modules or ordinary JAR files.

Example usage for the modular application:

Let’s consider a following modularized Java application. The purpose of the “Vehicle Shop Application” is tho show all available vehicles in the store.  The application has following tree structure:

├── out
└── src
    ├── vehicle.api
   │  ├── api
   │   │ ├──
   │   │ └──
   │   └──
   ├── vehicle.factory
   │   ├── factory
   │   │   ├──
   │   │   └──
   │   └──
      └── shop

The purpose of the “VehicleShopMain”  application is to show an available vehicles. The code provides more details: 

package shop;

import java.util.List;
import java.util.ServiceLoader;
import api.CarVehicle;
import api.CarFactory;

import java.awt.FlowLayout;  
import javax.swing.JButton;  
import javax.swing.JFrame;  
import javax.swing.JLabel;  
import javax.swing.JPanel;

public class VehicleShopMain {

    public static void main(String[] args){
        System.out.println("Vehicle Shop Simple App");
        System.out.println("JEP-392: PackagingTool");

        int numberOfCars = 10;
        List<CarVehicle> cars = ServiceLoader.load(CarFactory.class).stream()
                    .map(f -> f.produce(numberOfCars))


    private static void createWindow(List<CarVehicle> cars){
        JFrame frame = new JFrame("Vehicle Shop App");  
        JPanel panel = new JPanel();  
        panel.setLayout(new FlowLayout());  

        String text ="<br>"));
        JLabel label = new JLabel("<html><pre>CARS:<br>" + text + "</pre></html>");  
        frame.setSize(400, 250);  

After compiling all application  modules into the “out” directory by using following command:

$ javac -d ./out/<selected_module> -p out ./src/<selected_module>/ ./src/<selected_module>/**/*.java 

It is possible to run the application from the module path to test whether it works properly before we create a bundle using the packaging tool “jpackage“:

$ java --module-path out --module 

 All works properly it time to pack the application by the following command (MacOS):

$ jpackage --name simple-vehicle-app --module-path out -m 

The application Main-Class has been specified as an argument as a MANIFEST.FM file is not present.  The DMG file has been created for the MacOS platform and it  is possible to add newly created application to the “Application” section by executing the created DMG bundle.


It may come very handy to create a stand-alone application as providing a multiple JAR files is not a suitable option. With JAVA SE 16 is it even more easier.

Happy Coding and Packing!

JEP-392 Packaging Tool
Main: Java tutorials