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:
- Supports native packaging formats to provide natural installation experience
- Allows launch-time arguments specified at packaging time
- 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
│ │ ├── CarFactory.java
│ │ └── CarVehicle.java
│ └── module-info.java
├── vehicle.factory
│ ├── factory
│ │ ├── SimpleCar.java
│ │ └── SimpleCarFactory.java
│ └── module-info.java
└── vehicle.shop
├── module-info.java
└── shop
└── VehicleShopMain.java
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 java.util.stream.Collectors;
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(ServiceLoader.Provider::get)
.map(f -> f.produce(numberOfCars))
.flatMap(List::stream)
.collect(Collectors.toList());
createWindow(cars);
}
private static void createWindow(List<CarVehicle> cars){
JFrame frame = new JFrame("Vehicle Shop App");
JPanel panel = new JPanel();
panel.setLayout(new FlowLayout());
String text = cars.stream().map(CarVehicle::toString).collect(Collectors.joining("<br>"));
JLabel label = new JLabel("<html><pre>CARS:<br>" + text + "</pre></html>");
panel.add(label);
frame.add(panel);
frame.setSize(400, 250);
frame.setLocationRelativeTo(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
After compiling all application modules into the “out” directory by using following command:
$ javac -d ./out/<selected_module> -p out ./src/<selected_module>/module-info.java ./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 vehicle.shop/shop.VehicleShopMain
All works properly it time to pack the application by the following command (MacOS):
$ jpackage --name simple-vehicle-app --module-path out -m vehicle.shop/shop.VehicleShopMain
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.
Conclusion
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!
Main: Java tutorials