Catherine Edelveis, Author at foojay https://foojay.io/today/author/catherine-edelveis/ a place for friends of OpenJDK Mon, 20 Apr 2026 06:37:53 +0000 en-US hourly 1 https://wordpress.org/?v=6.9.4 https://foojay.io/wp-content/uploads/2020/04/Favicon-3-2-150x150.png Catherine Edelveis, Author at foojay https://foojay.io/today/author/catherine-edelveis/ 32 32 Which Java Runtime Should You Use in Production? Comparing OpenJDK Distributions https://foojay.io/today/which-java-runtime-should-you-use-in-production-comparing-openjdk-distributions/ https://foojay.io/today/which-java-runtime-should-you-use-in-production-comparing-openjdk-distributions/#respond Sat, 18 Apr 2026 15:01:39 +0000 https://foojay.io/?p=123468 Table of Contents TLDRIntroOpenJDKEclipse TemurinLiberica JDKAzul ZuluAmazon CorrettoIBM Semeru RuntimesRed Hat OpenJDKSapMachineMicrosoft Build of OpenJDKMaking the Call TLDR Intro Picking a Java runtime is like picking any commodity infrastructure, isn’t it? You simply find the version you need and grab ...

The post Which Java Runtime Should You Use in Production? Comparing OpenJDK Distributions appeared first on foojay.

]]>
Table of Contents
TLDRIntroOpenJDKEclipse TemurinLiberica JDKAzul ZuluAmazon CorrettoIBM Semeru RuntimesRed Hat OpenJDKSapMachineMicrosoft Build of OpenJDKMaking the Call

TLDR

  • All eight distributions on this list start from the same OpenJDK codebase. The version number is the thing they have most in common. However, support ownership, vendor accountability, and additional tooling variety are where they go separate ways.
  • BellSoft and Azul are the two vendors for whom Java is the primary business rather than a portfolio item. The difference is in support window length and toolchain depth.
  • If your infrastructure already standardizes on AWS, Azure, RHEL, SAP, or IBM platforms, the aligned distribution answers itself. The real decision is for teams without that constraint.

Intro

Picking a Java runtime is like picking any commodity infrastructure, isn’t it? You simply find the version you need and grab a build.

Spoiler alert: it isn't.

The distributions in this comparison are united by two acts. First, they stem from the same OpenJDK source code. Second, most are TCK-verified, which means they've passed the Java SE Technology Compatibility Kit confirming the runtime behaves as specified. It means that they can run the same Java applications without modification.

Where they diverge is how they deal with situations when something goes wrong: who's accountable, how long they'll maintain the build, and whether the vendor's portfolio lines up with the infrastructure you're already running.

This article offers a neutral comparison of the leading OpenJDK distributions and features teams should pay attention to.

OpenJDK

Raw OpenJDK is the upstream development project. It is the community baseline, with maximum freedom and no vendor coupling. The project exists to develop the next Java version; there's no support, no lifecycle guarantees, and older builds don't include current security patches.

Consequently, upstream OpenJDK is not designed to behave like a long-term, maintained enterprise runtime. Never use upstream OpenJDK in production!

Eclipse Temurin

Temurin is the Eclipse Foundation's TCK-verified build of OpenJDK, produced by the Adoptium project. It's free, broadly supported across platforms, distributed via Docker containers and package managers, and carries a published LTS roadmap covering at least four years. Quarterly updates align with the OpenJDK release cycle. Compared to raw upstream OpenJDK, it's the first distribution on this list that can actually be deployed.

The gap is support ownership. Adoptium doesn't sell commercial support, it lists third-party providers. For organizations with a procurement requirement of "single vendor for both binaries and support," Temurin doesn't qualify. For teams where community governance and third-party support options are acceptable, it's the natural baseline.

Liberica JDK

BellSoft's Liberica JDK is TCK-certified and free for production use. Paketo buildpacks ship it by default. VMware recommends it for use with Spring Framework. LTS and non-LTS builds cover a wide range of platforms, with commercial support for LTS running 8.5 years. For teams still running Java 6 or 7, BellSoft offers commercial support for those versions as well. Quarterly updates ship in two tracks: CPU builds for security patches only, and PSU builds that include patches plus non-critical fixes.

BellSoft is a Java-centric vendor. Its portfolio extends beyond the JDK itself into additional Java deployment tools and covers JavaFX builds, OpenWebStart support, Mission Control, a GraalVM-based Liberica Native Image Kit, a container-optimized Linux distribution Alpaquita Linux, lightweight container images, hardened container images, and a product discovery API. That can be useful for teams that want one vendor for runtime, Java-focused Linux, and containerization assets.

Azul Zulu

Azul Zulu developed by Azul is free, TCK-verified, with LTS and non-LTS builds across a wide range of platforms. LTS releases get 8 years of support, with commercial support available for Java 6 and 7. Quarterly updates include both CPU and PSU tracks.

Azul is one of the Java-focused vendors. It provides not only Zulu binaries, but also additional Java products such as Azul Mission Control, and JVM inventory/discovery tooling. Extras include OpenJFX builds, IcedTea-Web for Java Web Start use cases, a documented metadata/discovery API, and commercial support for Applets.

Separately from Zulu, Azul offers Platform Prime: a JVM alternative to OpenJDK HotSpot with additional features optimizing performance: C4 (a pauseless GC), a ReadyNow! warmup accelerator, the Falcon JIT compiler, and a Cloud Native Compiler that offloads JIT compilation off the running instance.

Amazon Corretto

Amazon Corretto is a TCK-verified distribution maintained by AWS, available for Linux, Windows, and macOS, with regular updates for LTS versions and Docker images included.

The AWS-specific additions benefit teams already in that environment: the Amazon Corretto Crypto Provider (ACCP) is optimized for AWS services, and SnapStart cuts cold start latency for Java-based Lambda functions by up to 10x.

Commercial support isn't a separate Corretto product — it runs through AWS Support Plans. For teams already on AWS with an active support plan, the JDK support comes with the relationship they already have. Outside that context, the commercial support picture is thin.

IBM Semeru Runtimes

IBM Semeru is built around OpenJ9, an alternative JVM implementation that replaces HotSpot. It's available in an Open Edition (GPLv2 + Classpath Exception) and a Certified Edition under an IBM license, with IBM Runtimes for Business as the commercial support offering. Quarterly updates cover LTS versions and the current release.

The second argument for Semeru is platform coverage: it supports IBM Z, Power, AIX, and z/OS-related environments. For organizations on those platforms, Semeru is the natural fit. For everyone else considering Semeru, the main draw is OpenJ9 itself — the JVM optimizations are what make it distinct. But it also means it is not the most vanilla choice on the list as it might be hard to migrate to another JVM implementation in the future.

Red Hat OpenJDK

Red Hat's OpenJDK build is designed for the Red Hat stack: RHEL, OpenShift, and supported middleware environments. It ships with a RHEL subscription, covers all LTS versions, and runs on Windows and RHEL only — no macOS, no other Linux distributions.

JDK support lifecycle depends on RHEL: if a RHEL version reaches end of support before the JDK version it ships with, JDK support ends with RHEL.

As for the TCK verification, Red Hat's own policy states that OpenJDK 8 builds delivered after July 1, 2025 are not TCK-certified. Later versions remain TCK-tested.

For teams standardized on RHEL and OpenShift, the JDK support follows the same lifecycle as the rest of the stack. The platform constraints make it a non-starter outside that environment.

SapMachine

SapMachine is SAP's free, TCK-verified distribution and the default runtime for many SAP applications and SAP Business Technology Platform services, available for Linux, Windows, and macOS. It covers all LTS versions except Java 8, plus the current release, with at least four years of documented LTS support. Quarterly updates align with OpenJDK.

Commercial support from SAP is available only for SAP customers using SapMachine in the context of SAP-supported products.

Important note: SAP applies patches that don't always make it upstream. Vendor-specific fixes that remain in SapMachine only can surface as compatibility issues when moving to a different distribution. Organizations deep in the SAP stack should default to SapMachine. For non-SAP workloads, the support scope narrows and the migration risk is real.

Microsoft Build of OpenJDK

Microsoft's OpenJDK distribution is no-cost and open-source, covering LTS versions except Java 8 and the current release, available for Linux, macOS, and Windows with Alpine-compatible binaries for some releases. Platform-specific installers and package manager installation methods are available alongside quarterly updates.

The same patch caveat as SapMachine applies: Microsoft may include fixes not yet backported upstream, with no guarantee they'll make it into the main OpenJDK project. Commercial support requires active Azure Support Plans and covers only workloads on Azure-related services.

Making the Call

If procurement requires a single vendor for both binaries and support, upstream OpenJDK and Temurin are both off the table. Platform-aligned teams are sorted more quickly: AWS has Corretto, RHEL and OpenShift shops are covered by their Red Hat subscription, SAP landscapes use SapMachine, IBM enterprise platforms go to Semeru, and Azure workloads have Microsoft's distribution.

For teams without strong platform alignment, the remaining question is vendor focus. BellSoft and Azul have Java as their primary business. That shows in support window length, legacy version coverage, and toolchain depth. Both companies offer a variety of additional features, tools, and optimizations that can provide tangible business value for organizations running predominantly Java-based workloads.

Temurin is still the possible call where community governance and third-party support options work. Outside those constraints, the decision mostly reduces to which vendor's stack already maps to the infrastructure the team maintains.

The post Which Java Runtime Should You Use in Production? Comparing OpenJDK Distributions appeared first on foojay.

]]>
https://foojay.io/today/which-java-runtime-should-you-use-in-production-comparing-openjdk-distributions/feed/ 0
A Guide to Creating JavaFX Native Images https://foojay.io/today/a-guide-to-creating-javafx-native-images/ https://foojay.io/today/a-guide-to-creating-javafx-native-images/#respond Tue, 15 Apr 2025 09:57:48 +0000 https://foojay.io/?p=115904 Table of Contents Table of ContentsSet Up GraalVM for JavaFX Native CompilationCollect Metadata Using GraalVM Tracing AgentBuild a JavaFX Native Image with GraalVMUse GitHub Actions to Automate JavaFX ReleasesConclusion Combining JavaFX-based applications with GraalVM Native Image will enable you to ...

The post A Guide to Creating JavaFX Native Images appeared first on foojay.

]]>
Table of Contents
Table of ContentsSet Up GraalVM for JavaFX Native CompilationCollect Metadata Using GraalVM Tracing AgentBuild a JavaFX Native Image with GraalVMUse GitHub Actions to Automate JavaFX ReleasesConclusion

Combining JavaFX-based applications with GraalVM Native Image will enable you to create platform-specific executables that don’t require the JVM to run.

In this article, we will look into two ways of turning JavaFX applications into native images: manually and with the Maven plugin. We will also learn to integrate this process into the CI/CD pipeline with GitHub Actions.

This article was originally published here.

The code for the project I use in this article is available on GitHub. It was built using Liberica JDK Full that includes an OpenJFX bundle. It facilitates developing and building JavaFX applications as there’s no need to add separate dependencies for JavaFX.

Table of Contents

  1. Set Up GraalVM for JavaFX Native Compilation
  2. Collect Metadata Using GraalVM Tracing Agent
  3. Build a JavaFX Native Image with GraalVM
  4. Use GitHub Actions to Automate JavaFX Releases
  5. Conclusion

Set Up GraalVM for JavaFX Native Compilation

IMPORTANT NOTE: you will need to provide the executable JAR of your application to the Native Image, so make sure that you create one before proceeding.

Regardless of whether you plan to use a build system plugin or manual compilation, you need to install a GraalVM distribution that supports JavaFX such as Liberica Native Image Kit (NIK).

Download Liberica NIK Full with OpenJFX for LTS JDK 17 or 21. You can also use package managers such as SDKMAN!

Install Liberica NIK. You can set $JAVA_HOME or create a &NIK_HOME environmental variable to store the path to the installed package.

If you want to build native images using Maven, you need to add the plugin to your pom.xml file. It would be more convenient to add it to profiles:

   <profiles>
        <profile>
            <id>native</id>
            <build>
                <plugins>
                    <plugin>
                        <groupId>org.graalvm.buildtools</groupId>
                        <artifactId>native-maven-plugin</artifactId>
                        <version>0.10.5</version>
                        <extensions>true</extensions>
                        <executions>
                            <execution>
                                <id>build-native</id>
                                <goals>
                                    <goal>compile-no-fork</goal>
                                </goals>
                                <phase>package</phase>
                            </execution>
                        </executions>
                        <configuration>
                            <mainClass>com.java.MyApp</mainClass>
                        </configuration>
                    </plugin>
                </plugins>
            </build>
        </profile>
    </profiles>

We’re all set up, let’s move on! 

Collect Metadata Using GraalVM Tracing Agent

Java dynamic features and resources such as images or icons require special treatment when working with GraalVM Native Image. This is because the native-image compiler includes only those elements into the executable that are reachable at build time.

Luckily, there are several ways of overcoming this obstacle:

  • If your JavaFX doesn’t use any dynamic features, you can use the -H:IncludeResources='com.fxapp.resources.images.*' flag to make the compiler include resources into the executable.
  • You can specify metadata manually in a JSON file.
  • You can useTracing Agent to collect metadata automatically.

I would recommend using Tracing Agent because you cannot be 100% certain that your application doesn’t use or won’t use dynamic features. In addition, if you use FXML files to separate UI code from the business logic, simply adding these files to the native executable won’t help. For Native Image, FXML files are just resources. The compiler doesn’t know that they contain method calls.

Let’s run the application with the agent to collect metadata.

Enable the Tracing Agent on the command line with the -agentlib:native-image-agent flag, specifying the output directory for JSON files with metadata:

$NIK_HOME/bin/java -agentlib:native-image-agent=config-output-dir=./agent-data -jar app.jar

The application will start, and you will need to run it through all execution paths so that the agent collects all required data. When the application exits, the JSON files will be automatically generated in the specified directory.

You can also use the config-merge-dir option instead of config-output-dir if you need to run the application several times to gather metadata. This option is also useful if you don’t want to collect metadata from scratch every time you update the project.

$NIK_HOME/bin/java -agentlib:native-image-agent=config-merge-dir=./agent-data -jar app.jar

It is possible to enable the agent in the pom.xml. Follow the instructions described here.

Build a JavaFX Native Image with GraalVM

Now that we have all necessary metadata on our hands, it’s time to generate a native image.

If you do it manually, run the following command with a -H:ConfigurationFileDirectories flag specifying the path to the directory with metadata:

$NIK_HOME/bin/native-image -H:ConfigurationFileDirectories=./tracing-agent-data -jar target/lottery-1.0-SNAPSHOT.jar

After the compilation has finished, you will find the native executable in the /target directory. You can run it with

./target/myApp

If you use the plugin, add the block to the plugin configuration and specify the -H:ConfigurationFileDirectories flag with the path to metadata:

<configuration>
    <imageName>myApp</imageName>
    <outputDirectory>target/native</outputDirectory>
    <mainClass>com.java.MyApp</mainClass>
    <buildArgs>
         <buildArg>-H:ConfigurationFileDirectories=./agent-data</buildArg>
    </buildArgs>
</configuration>

By default, Maven places the native executable into the /target directory. But you can specify another directory under ``.

After that, run

./mvn -Pnative package

The native executable will be created in the /target/native directory.

You can now run your executable with:

./target/native/myApp

Note that the native executable doesn’t need JVM to run because it already contains all necessary Java classes.

Use GitHub Actions to Automate JavaFX Releases

In contrast to the JAR files that can be run on any platform where Java is installed, native images are built for a specific architecture. So, if you have built a native image on Linux x66, it will run on Linux x64 only.

But what if we want to build an image for another platform? Or what if we release the application for several platforms? In this case, we can use GitHub Actions to build and release the images right from the GitHub.

When writing a workflow file for building JavaFX native images, there are several things to consider:

  • You need to specify all operation systems and architectures, for which you want to build native images;
  • Building native images for Linux requires installing additional packages: libasound2-dev, libavcodec-dev, libavformat-dev, libavutil-dev, libgl-dev, libgtk-3-dev, libpango1.0-dev, libxtst-dev;
  • To build native images, you need to use a GraalVM distribution that supports JavaFX.

Let’s look at the workflow file that takes all these factors into consideration (you can find this file under native-image.yml in the repository):

name: Native Image

on:
  workflow_dispatch:
  push:
    branches:
      - main

jobs:
  build_non_win_images:
    name: 'Build Native Image ${{ matrix.platform }}'
    strategy:
      matrix:
        os: [ macos-latest, windows-latest, ubuntu-latest ]
        include:
          - os: 'ubuntu-latest'
            platform: 'linux-amd64'
          - os: 'macos-latest'
            platform: 'darwin-arm64'
          - os: 'macos-13'
            platform: 'darwin-amd64'
          - os: 'windows-latest'
            platform: 'win-amd64'
    runs-on: ${{matrix.os}}
    permissions:
      contents: write
    steps:
      - name: linux packages
        if: ${{ matrix.os == 'ubuntu-latest' }}
        run: sudo apt install libasound2-dev libavcodec-dev libavformat-dev libavutil-dev libgl-dev libgtk-3-dev libpango1.0-dev libxtst-dev

      - name: Checkout the repository
        uses: actions/checkout@v4

      - uses: graalvm/setup-graalvm@v1
        with:
          distribution: 'liberica'
          java-version: '21'
          java-package: 'jdk+fx'
          github-token: ${{ secrets.GITHUB_TOKEN }}
          cache: maven

      - name: Build
        shell: bash
        run: |
          ./mvnw -Pnative package

      - name: Archive Release
        uses: thedoctor0/zip-release@0.7.5
        with:
          type: 'zip'
          filename: "raffle-${{ matrix.platform }}.zip"
          directory: target/native

      - name: Upload binaries to release
        uses: svenstaro/upload-release-action@v2
        with:
          repo_token: ${{ secrets.GITHUB_TOKEN }}
          tag: ${{ github.ref }}
          release_name: native-image
          file: "target/native/raffle-${{ matrix. platform }}.zip"
          overwrite: true
          make_latest: true

What do we have here?

First of all, at the Build Native Image stage, we specify the OSs and platforms, for which to build a native image.

Then, we add an additional step ‘linux packages’ with an if statement to install required packages for Linux.

At this stage, we also specify a GraalVM distribution to compile the images. In our case, it is Liberica NIK for Java 21 that supports JavaFX.

At the Build stage, we run ./mvnw -Pnative package to build the native images.

At the Archive Release stage, we archive the native image specifying the platform in the file name. Here, we also specify the directory where the native image was created. Note that if the image will be generated by default in the target directory, the whole directory will be packaged into the ZIP file. So, that’s why we specified a separate directory for the native image in the pom.xml in the section above (target/native).

At the Upload binaries to release stage, we take the archived native image and load it into the release.

That’s it! Make sure that you created a release on GitHub and commit the changes: the workflow will be triggered automatically.

After the workflow completes successfully, you will find the binaries for all platforms under Releases.

Conclusion

Creating JavaFX Native Images using GraalVM helps to improve the performance and portability of Java desktop applications by eliminating the need for a JVM at runtime.

In this guide, we explored the entire process, from setting up GraalVM and configuring the necessary metadata to compiling the native executable and automating builds with GitHub Actions.

If you want to explore JavaFX and native compilation further, check out the official GraalVM and Liberica Native Image Kit documentation for further optimizations.

Also, subscribe to our letter for more content on JavaFX, native images, and all things Java!

The post A Guide to Creating JavaFX Native Images appeared first on foojay.

]]>
https://foojay.io/today/a-guide-to-creating-javafx-native-images/feed/ 0