Build Native Images for a Java Application

Having a hard time distributing Java Applications to your users? Are you using any paid tools for the same? What if I say, there is an Open-Source tool that will help you solve all the challenges you have faced?

Introducing you to GraalVM - A tool that helps to build native images for a Java Application.

GraalVM for Java Application

GraalVM can be used to build native images that will have almost zero dependency requirements, have faster startup time and comparatively less memory usage.

Let's see how we can build native images for a simple Hello World program. I shall use IntelliJ Idea as my IDE and Maven as the build automation tool. You need to download GraalVM JDK from their official downloads page.

I quickly created a simple Hello World program in IntelliJ Idea as you can see below ๐Ÿ‘‡

Hello World program running via Java

The pom.xml file generated by IntelliJ Idea is a very simple pom file and looks like this ๐Ÿ‘‡

Initial pom.xml file as generated by IntelliJ Idea

I will add the GraalVM maven build plugin configuration to the pom and finally, it is ๐Ÿ‘‡

<?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.example</groupId>
    <artifactId>HelloWorld</artifactId>
    <version>1.0-SNAPSHOT</version>
    <properties>
        <maven.compiler.source>20</maven.compiler.source>
        <maven.compiler.target>20</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <build>
        <plugins>
            <plugin>
                <groupId>org.graalvm.buildtools</groupId>
                <artifactId>native-maven-plugin</artifactId>
                <version>0.9.27</version>
                <extensions>true</extensions>
                <configuration>
                    <imageName>HelloWorld</imageName>
                    <mainClass>HelloWorld</mainClass>
                    <outputDirectory>target/</outputDirectory>
                    <buildArgs>
                        <buildArg>--no-fallback</buildArg>
                        <buildArg>-H:+ReportExceptionStackTraces</buildArg>
                        <buildArg>--verbose</buildArg>
                    </buildArgs>
                </configuration>
                <executions>
                    <execution>
                        <id>build</id>
                        <goals>
                            <goal>build</goal>
                        </goals>
                        <phase>package</phase>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

GraalVM maven plugin requires three environment variables to be defined in the terminal session before generating native images. You can set those three environment variables by running these three commands ๐Ÿ‘‡

export JAVA_HOME=~/Downloads/graalvm
export GRAALVM_HOME=~/Downloads/graalvm
export PATH=~/Downloads/graalvm/bin:$PATH

I have previously downloaded GraalVM JDK in my Downloads folder. You will replace Downloads with the name of the folder in which graalvm is downloaded. You should rename the graalvm directory to only graalvm i.e. you should remove any version text from the directory name, for simplicity.

At last comes the time to build the native executable for our Hello World program. You should run this ๐Ÿ‘‡ command to build the native executable.

mvn clean package

This command does two things :

  • Deletes the previously created target directory (if it exists)

  • Runs the package goal of the Maven lifecycle which includes the package goal of GraalVM build plugin

The output of the above command is ๐Ÿ‘‡

Native image generation by GraalVM

It builds the executable with the name HelloWorld in the target directory.

When we run the HelloWorld native image directly from the terminal, it runs without any Java Runtime ๐ŸŽ‰!

Running the image

As you can see, the native application starts up in milliseconds which is very fast. This is how a simple Java app can be distributed as a native image. You can also build these images for MacOS, Windows and Linux on the respective systems by leveraging CI/CD pipelines' capabilities. I recommend GitHub Actions to build these native images and store them as artifacts for each run. You can check this GitHub Actions workflow file that I have created for a complex Java project - Drifty which is an Open-Source Interactive File Downloader System.

Drifty uses Java and JavaFX for its CLI and GUI counterparts. So, I had to use GluonFX Maven Plugin to build native images for the JavaFX application.

So, that is how you can build native images for any Java project. GraalVM also supports building the same for Micronaut, Helidon, Quarkus and Spring Boot applications.


Connect with me

12
Subscribe to my newsletter

Read articles from Saptarshi Sarkar directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Saptarshi Sarkar
Saptarshi Sarkar

Saptarshi Sarkar is a software developer and an open-source enthusiast. He is familiar with technologies like Java and is currently learning DevOps. He loves contributing to Open-Source projects and also enjoys maintaining them.