Back to /

Java desktop applications in 2025

Nowadays Java is used for building server applications and the Spring Framework is probably one of the most popular tools for creating microservices. However, Java is a 32-year-old programming language and for most of the time it was used for building UI applications - either as Java Applets or standalone desktop applications. And many of them have stayed with us until these days - for example IntelliJ IDE that is based on the Java Swing framework.

Of course it’s easy to say that in 2025 the state of Java UI frameworks, such as Swing, JavaFX or SWT is unclear:

I will focus on the Swing framework because in my opinion it is still the safest option for building desktop applications in Java. And new features that were added to JDK some time ago make this choice more compelling. From Java 16, developers can use the jpackage tool to build a distribution package that will contain a Java runtime image with necessary libraries, an application and a launcher. To run such an application, users don’t need to download and install the Java JRE because runtime is part of the package. Furthermore we can adjust runtime shape with jlink and include only those modules that are required in our application. For example, we can create runtime with java.base and java.desktop modules that should be enough for running a basic desktop application.

A distribution package can be prepared with three Maven plugins:

1. Building Uber Jar

<plugin>
    <artifactId>maven-shade-plugin</artifactId>
    <version>3.5.1</version>
    <executions>
        <execution>
            <id>exec-jar</id>
            <goals>
                <goal>shade</goal>
            </goals>
            <phase>package</phase>
        </execution>
    </executions>
    <configuration>
        <finalName>my-app</finalName>
        <outputDirectory>${project.build.directory}/exec</outputDirectory>
        <createDependencyReducedPom>false</createDependencyReducedPom>
        <transformers>
            <transformer
				implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                <mainClass>com.milosz.apps.MyApp</mainClass>
            </transformer>
        </transformers>
    </configuration>
</plugin>

2. Building minimal JRE image

Assembles JRE image with modules java.base and java.desktop. All files are saved in directory linkimage.

<plugin>
	<artifactId>maven-antrun-plugin</artifactId>
	<version>3.1.0</version>
	<executions>
    	<execution>
        	<phase> package </phase>
        	<configuration>
            	<target>
                	<link modules="java.base,java.desktop
	destDir="target/linkimage" modulepath="${java.home}/jmods"
	includeHeaders="false"
	includeManPages="false" debug="false">
                	</link>
            	</target>
        	</configuration>
        	<goals>
            	<goal>run</goal>
        	</goals>
    	</execution>
	</executions>
</plugin>

3. Building distribution package

Plugins takes Uber Jar exec/my-app.jar (Step 1) and JRE runtime from linkimage directory and compiles distribution in directory jpackage/my-app.

<plugin>
	<groupId>com.github.akman</groupId>
	<artifactId>jpackage-maven-plugin</artifactId>
	<version>0.1.5</version>
	<executions>
    	<execution>
        	<id>native-package</id>
        	<phase>package</phase>
        	<goals>
            	<goal>jpackage</goal>
        	</goals>
    	</execution>
	</executions>
	<configuration>
    	<name>my-app</name>
    	<mainjar>my-app.jar</mainjar>
    	<input>${project.build.directory}/exec</input>
    	<appversion>${project.version}</appversion>
    	<type>IMAGE</type>
    	<runtimeimage>${project.build.directory}/linkimage</runtimeimage>
	</configuration>
</plugin>

Look and feel

Default Swing's "Metal" L&F doesn't look good on HiDPI devices. The good alternative are themes from FlatLaf. To use it, Maven dependency must be present and L&F loade before UI is displayed with code UIManager.setLookAndFeel("com.formdev.flatlaf.FlatIntelliJLaf");