JavaRush /Java Blog /Random EN /Coffee break #148. How to turn any Java program into a st...

Coffee break #148. How to turn any Java program into a standalone EXE file

Published in the Random EN group
Source: Mccue.dev Today you will learn how to create an executable EXE file from a Java program to run on the Windows operating system. Coffee break #148.  How to turn any Java program into a standalone EXE file - 1Double-clicking to launch is one of the easiest ways to open a program. If the person you want to show your application to already has the correct version of Java installed, they can double-click the jar file to run it. If it doesn't have Java installed, there are ways to create an executable installer, such as jpackage . After that, to run the code you just need to click on this installer. You can also use Native Image to turn the code into an executable file that does not require any additional installation. In this article, we'll focus on a fairly simple approach that works for any application, no matter what dependencies you include or what JVM features you use. The code that will be discussed today can be found in the GitHub repository , and the executable files with the program are posted here .

Stack used

Java 9+

java --version jlink --version

Maven

mvn --version

NodeJS

npx --version

Step 1: Compile and package your code into a jar

This basic program will create a simple window with text that you can change by clicking on one of the buttons in the interface.
package example;

import org.apache.commons.text.WordUtils;

import javax.swing.*;
import java.awt.*;

public class Main {
    public static void main(String[] args) {
        var label = new JLabel("Hello, World!");
        label.setFont(new Font("Serif", Font.PLAIN, 72));

        var uppercaseButton = new JButton("Uppercase");
        uppercaseButton.addActionListener(e ->
            label.setText(WordUtils.capitalize(label.getText()))
        );

        var lowercaseButton = new JButton("lowercase");
        lowercaseButton.addActionListener(e ->
            label.setText(WordUtils.uncapitalize(label.getText()))
        );

        var panel = new JPanel();
        panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
        panel.add(label);
        panel.add(uppercaseButton);
        panel.add(lowercaseButton);

        var frame = new JFrame("Basic Program");
        frame.add(panel);
        frame.pack();
        frame.setVisible(true);
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    }
}
Coffee break #148.  How to turn any Java program into a standalone EXE file - 2Our goal now is to package the code along with its dependencies into a jar. JAR files are regular ZIP archives with little extra structure. For a Maven project the configuration will look like this.
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3 .org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>example</groupId> <artifactId>javaexe</artifactId> <version>1.0</version> <properties> <project.build.sourceEncoding>UTF-8</project .build.sourceEncoding> <maven.compiler.source>18</maven.compiler.source> <maven.compiler.target>18</maven.compiler.target> </properties> <dependencies> <dependency> <groupId> org.apache.commons</groupId> <artifactId>commons-text</artifactId> <version>1.9</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache .maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>2.4.3</version> <executions> <execution> <phase>package</phase> <goals> <goal> shade</goal> </goals> <configuration> <transformers> <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <manifestEntries> <Main-Class>example.Main</Main- Class> <Build-Number>1.0</Build-Number> </manifestEntries> </transformer> </transformers> </configuration> </execution> </executions> </plugin> </plugins> </build> </project>
Here the “shade” plugin will handle including code from all your dependencies into the jar. In this case, the only external dependency is org.apache.commons/commons-text .
mvn clean package
We will then move this jar file to a new target/ directory where it will be separated from other files.
mkdir build mv target/javaexe-1.0.jar build

Step 2: Create a Java Runtime Environment (JRE)

To run the jar file we've already created, we need to link it to the Java runtime environment. For this we will use jlink . Since the Java ecosystem doesn't use modules, you probably haven't heard of them or used jlink. In short, jlink can create “custom executable images”. For example, you are making a web server. You don't need AWT or Swing, so including them in your code will be redundant. With jlink you can create a JRE that doesn't include the java.desktop module at all . This system works best if your application and all its dependencies include compiled module-info.java files , which tell jlink exactly what modules you want to include. You can also manually define the list of required modules using jdeps . And even without a modular project, we can effectively clone our Java installation into a directory using jlink.
jlink --add-modules ALL-MODULE-PATH --output build/runtime
Including each module individually ensures that libraries such as org.apache.commons/commons-text will work as intended. We just need to figure out which modules we need.

Step 3: Combine Jar and JRE into an executable

Having a jar file containing the code and all its dependencies, as well as the JRE, all that remains is to combine them. To do this we need to do the following:
  1. Zip the directory containing the JRE and jar of your application.
  2. Attach a stub script to the top of this zip file, which will extract the data into a temporary directory and run the code.
There is a JavaScript library for this called caxa . Its purpose is to turn NodeJS projects into executables, and it can also bundle any NodeJS installations on the system. Luckily, you can skip this step by specifying the --no-include-node flag .
npx caxa \ --input build \ --output application \ --no-include-node \ -- ​​"{{caxa}}/runtime/bin/java" "-jar" "{{caxa}}/javaexe-1.0 .jar"
This will create an executable file named “application”. If you are creating it for Windows, then you need to specify “application.exe”. When the executable runs, {{caxa}} will be replaced with the temporary directory where the zip file was deployed. Please note that when creating executable files, mechanisms such as code signing and automatic updates are also used. However, these things require deeper study, which is difficult to fit into one publication.
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION