How to Turn Your Java Swing App into a Standalone Executable (No JRE Needed)
This article compares five Java packaging methods—GraalVM, JLink, Exe4J, batch scripts, and plain JAR—detailing their pros and cons, then introduces a custom WinForm tool that bundles Swing applications into self‑contained executable files, complete with code examples and deployment steps.
I mainly develop with Java and enjoy creating small Swing utilities, but Swing apps require a JRE to run, which limits distribution.
Current Java program packaging options include:
Use the popular GraalVM to compile a JAR into a native executable.
Use JLink to package the JAR into a native executable.
Generate a launcher with Exe4J and create a self‑extracting archive.
Create a batch script and wrap it in a self‑extracting archive.
Distribute only the JAR, requiring users to install a JRE and launch via command line.
The above options have different advantages and disadvantages:
Technology
Advantages
Disadvantages
GraalVM
Performance boost, lower resource consumption, high security
Long build time, difficult debugging, limited reflection support
JLink
Binary file, lighter than bundling full environment
Complex build, difficult debugging, large size
Exe4J
Lower entry barrier, better user experience, easier debugging
Large size, requires JRE at runtime, not suitable for small tools
Batch script
Lower entry barrier, flexible configuration, easy updates, easy debugging
Large size, requires JRE, not suitable for small tools
Plain JAR
Small distribution, easy updates
Cannot run on machines without JRE, requires command‑line launch, high entry barrier, poor user experience
Because binary distribution is hard to debug and JAR distribution harms user experience, I combined these approaches and built a WinForm packaging tool to convert Java programs into native executables. The tool UI is shown below:
Software usage:
This may be a useful open‑source project , the mall project is a SpringBoot3 + Vue e‑commerce system (60K stars on GitHub) with a micro‑service architecture, Docker and K8s deployment, covering front‑end store, back‑end admin, and full order workflow.
Boot project: https://github.com/macrozheng/mall
Cloud project: https://github.com/macrozheng/mall-swarm
Tutorial site: https://www.macrozheng.com
Project demo:
Below is a sample Swing program.
pom.xml file:
<code><?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>org.helloswing</groupId>
<artifactId>HelloSwing</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<!-- https://mvnrepository.com/artifact/com.formdev/flatlaf -->
<dependency>
<groupId>com.formdev</groupId>
<artifactId>flatlaf</artifactId>
<version>3.5.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.7.1</version>
<configuration>
<!-- Get all project dependencies -->
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<!-- Remove jar-with-dependencies suffix -->
<appendAssemblyId>false</appendAssemblyId>
<!-- Specify main class -->
<archive>
<manifest>
<mainClass>org.hellloswing.HelloSwing</mainClass>
</manifest>
</archive>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<!-- Bind to package phase -->
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
</code>HelloSwing.java file:
<code>package org.hellloswing;
import com.formdev.flatlaf.FlatDarkLaf;
import com.formdev.flatlaf.FlatLightLaf;
import javax.swing.*;
import java.awt.*;
public class HelloSwing {
public static void main(String[] args) throws UnsupportedLookAndFeelException {
// Initialize look and feel
FlatLightLaf.install();
UIManager.setLookAndFeel(new FlatDarkLaf());
// Initialize window
JFrame jFrame = new JFrame("Hello Swing!");
// Set size
jFrame.setSize(500, 500);
// Close operation
jFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
// Center window
jFrame.setLocationRelativeTo(null);
// Set components
JPanel jPanel = new JPanel(new BorderLayout());
jPanel.add(new JLabel("Hello Swing!", JLabel.CENTER), BorderLayout.CENTER);
jFrame.getContentPane().add(jPanel);
// Show window
jFrame.setVisible(true);
}
}
</code>After building a fat JAR, export a trimmed JRE, then use the packaging tool to bundle the JAR and JRE into an EXE file, which can be run by double‑clicking.
macrozheng
Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.