Week 79 — Which options are there for packaging Java applications as native executables?

Question of the Week #79
Which options are there for packaging Java applications as native executables?
3 Replies
Eric McIntyre
Eric McIntyre6mo ago
Before creating a native executable, one should have a JAR file with the application to package. Assume a simple main class in a file SimpleMain.java:
public class SimpleMain{
public static void main(String[] args){
System.out.println("Hello World");
}
}
public class SimpleMain{
public static void main(String[] args){
System.out.println("Hello World");
}
}
It is possible to compile that class and create a runnable JAR file as follows:
javac SimpleMain.java
jar cfe jarDir/SimpleApplication.jar SimpleMain SimpleMain.class
javac SimpleMain.java
jar cfe jarDir/SimpleApplication.jar SimpleMain SimpleMain.class
This should create a JAR file SimpleApplication.jar in the directory jarDir containing SimpleMain.class that runs the SimpleMain class when being used with java -jar. Running java -jar jarDir/SimpleApplication.jar should print Hello World. Once a JAR with the application is obtained, it is possible to create an installer that installs a JRE with the JAR using jpackage. The --input argument specifies a directory that should be included in the installation, --main-jar refers to the JAR with the main class (which should be located in the input directory) and --main-class refers to the fully-qualified name of the main class. It is also possible to specify a name using --name or use other options for configuring various things about the application.
jpackage --name MyApp --main-jar SimpleApplication.jar --input jarDir --main-class SimpleMain
jpackage --name MyApp --main-jar SimpleApplication.jar --input jarDir --main-class SimpleMain
By default, the jpackage command creates an installer for the current platform (like msi, dmg or deb). After installing, the application should be available on the system. As most applications don't need all JDK modules, it's possible to explicitly specify the modules to include in the installer using --add-modules:
jpackage --name MyApp --main-jar SimpleApplication.jar --input jarDir --main-class SimpleMain --add-modules java.base,jdk.zipfs
jpackage --name MyApp --main-jar SimpleApplication.jar --input jarDir --main-class SimpleMain --add-modules java.base,jdk.zipfs
The module java.base is required for all applications and jdk.zipfs is necessary for handling JAR files. The modules required by an application can be looked up using the jdeps command:
jdeps --print-module-deps jarDir/SimpleApplication.jar
jdeps --print-module-deps jarDir/SimpleApplication.jar
If the application is has a module-info.java, it is also possible to create the installer from the modulepath:
jpackage --name MyApp --input bin -p MODULE_PATH -m MODULE_NAME/fully.qualified.MainClass
jpackage --name MyApp --input bin -p MODULE_PATH -m MODULE_NAME/fully.qualified.MainClass
where MODULE_PATH refers to the modulepath (either with JARs or with directories containing the class files) and MODULE_NAME should be replaced with the name of the module.
Eric McIntyre
Eric McIntyre6mo ago
Another option to package a Java application is using the native-image tool provided by GraalVM. Instead of creating an installer, this will create a native executable with the application compiled for a specific platform. Once the JAR is created, a native executable of it can be created using the command
native-image jarDir/SimpleApplication.jar
native-image jarDir/SimpleApplication.jar
where jarDir/SimpleApplication.jar is the JAR containing the application. Alternatively, it is also possible to from a directory with the .class files or multiple JAR files by specifying the class path:
native-image -cp CLASS_PATH fully.qualified.MainClass
native-image -cp CLASS_PATH fully.qualified.MainClass
or by specifying the modulepath if the application is modular:
native-image -p MODULE_PATH -m MODULE_NAME/fully.qualified.MainClass
native-image -p MODULE_PATH -m MODULE_NAME/fully.qualified.MainClass
If reflection, JNI, resources, proxy classes or similar things are used, these need to be specified as arguments to native-image. See also https://discord.com/channels/648956210850299986/1099004918007865404 for more information on that.
📖 Sample answer from dan1st
Eric McIntyre
Eric McIntyre6mo ago
there is GraalVM Native Image, Excelsior JET, Launch4jJWrapper, Packr, Install4j
Submission from chandrashekhar_
Want results from more Discord servers?
Add your server