Operations 8 min read

Packaging Java Swing Applications into Executable Binaries: Options and Comparison

This article reviews several methods for distributing Java Swing applications as standalone executables—including GraalVM native images, JLink, Exe4J, batch scripts, and plain JAR distribution—compares their advantages and drawbacks, and demonstrates a custom WinForm packaging tool with example Maven and source code.

Architecture Digest
Architecture Digest
Architecture Digest
Packaging Java Swing Applications into Executable Binaries: Options and Comparison

I primarily develop with Java and enjoy creating small utilities using the Swing GUI library, but Swing applications require a JRE to run, which limits their distribution to users who already have Java installed.

Current Java program packaging options include:

Compiling the JAR to a native binary with GraalVM.

Using JLink to create a custom runtime image and package it as a binary.

Generating a launcher with Exe4J and wrapping it in a self‑extracting archive.

Writing a batch script and packaging it as a self‑extracting archive.

Distributing the plain JAR and requiring users to install a JRE and launch it manually.

The following table summarizes the pros and cons of each approach:

技术方案

优点

缺点

GraalVM

性能提升,减少资源损耗,安全性高

构建耗时,调试困难,不好支持反射

Jlink

二进制文件,比携带环境更轻量级

构建复杂,调试困难,体积大

Exe4J

降低使用门槛,有更好的体验,便于调试

体积大,需要 JRE 运行,不适合做小工具

批处理

降低使用门槛,配置灵活,易于更新,便于调试

体积大,需要 JRE 运行,不适合做小工具

仅 Jar 包

分发文件小,容易更新

没有 JRE 的电脑上不能运行,需要命令启动,使用门槛高,体验不好

Because binary distribution makes debugging harder while plain JAR distribution hurts user experience, I created a WinForm‑based packaging tool that converts a Java program into a binary executable. The tool’s UI is shown in the attached screenshot.

Below are the Maven pom.xml and the sample Swing source file HelloSwing.java used with the tool.

<?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>
        <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>
                    <descriptorRefs>
                        <descriptorRef>jar-with-dependencies</descriptorRef>
                    </descriptorRefs>
                    <appendAssemblyId>false</appendAssemblyId>
                    <archive>
                        <manifest>
                            <mainClass>org.hellloswing.HelloSwing</mainClass>
                        </manifest>
                    </archive>
                </configuration>
                <executions>
                    <execution>
                        <id>make-assembly</id>
                        <phase>package</phase>
                        <goals>
                            <goal>single</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>
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());
        // Create window
        JFrame jFrame = new JFrame("Hello Swing!");
        jFrame.setSize(500, 500);
        jFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        jFrame.setLocationRelativeTo(null);
        JPanel jPanel = new JPanel(new BorderLayout());
        jPanel.add(new JLabel("Hello Swing!", JLabel.CENTER), BorderLayout.CENTER);
        jFrame.getContentPane().add(jPanel);
        jFrame.setVisible(true);
    }
}

After building a fat JAR, I export a minimal JRE, then feed both the JAR and the JRE into the custom packaging tool, which produces an .exe that can be launched with a double‑click.

This post serves as a record of the process.

JavaMavenpackagingGraalVMSwingExecutableJLink
Architecture Digest
Written by

Architecture Digest

Focusing on Java backend development, covering application architecture from top-tier internet companies (high availability, high performance, high stability), big data, machine learning, Java architecture, and other popular fields.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.