How to Package Java Swing Apps into Standalone Executables Without a JRE

This guide compares five Java Swing packaging approaches, evaluates their pros and cons, and demonstrates a custom WinForm tool that bundles a Swing app with a minimal JRE into a standalone executable, complete with example Maven configuration and source code.

Code Ape Tech Column
Code Ape Tech Column
Code Ape Tech Column
How to Package Java Swing Apps into Standalone Executables Without a JRE

Java Swing desktop applications require a JRE to run, which limits distribution. This article lists five common packaging methods: GraalVM native image, JLink custom runtime, Exe4J launcher, batch script with self‑extracting archive, and plain JAR distribution requiring a JRE.

Each method’s advantages and disadvantages are compared: GraalVM offers performance and security but has long build time and limited reflection support; JLink produces lightweight binaries yet builds are complex and output size can be large; Exe4J lowers the entry barrier and improves user experience but still needs a JRE and results in larger files; batch scripts are flexible and easy to update but also require a JRE and produce large packages; plain JARs are small and easy to update but cannot run on machines without a JRE.

To balance these trade‑offs, the author created a WinForm‑based packaging tool that converts a Java program into a native executable. The tool’s UI is shown below.

Usage steps: start with a Swing project (example pom.xml and HelloSwing.java shown), build a fat JAR, export a minimal JRE, then use the packaging tool to bundle the JAR and JRE into an EXE that can be launched by double‑click.

<?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>
          <!-- 获取所有项目依赖项 -->
          <descriptorRefs>
            <descriptorRef>jar-with-dependencies</descriptorRef>
          </descriptorRefs>
          <!--  去除jar-with-dependencies后缀  -->
          <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 {
        // 初始化皮肤
        FlatLightLaf.install();
        UIManager.setLookAndFeel(new FlatDarkLaf());
        // 初始化窗口
        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);
    }
}

This record documents the entire packaging process.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaPackagingGraalVMSwingExecutableJLink
Code Ape Tech Column
Written by

Code Ape Tech Column

Former Ant Group P8 engineer, pure technologist, sharing full‑stack Java, job interview and career advice through a column. Site: java-family.cn

0 followers
Reader feedback

How this landed with the community

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.