posts

How to create JavaFX native images

figure
Aug 24, 2022
Peter Zhelezniakov

In our recent guide to JavaFX, we summarized the key features of this platform and compared it to the most prominent competitors. If you are still wondering whether JavaFX is worth learning, refer to the guide. For those of you who have already mastered the software, we suggest going a step further and integrate it with native image technology. So let’s get our hands dirty and turn a JavaFX application into a native executable using Liberica Native Image Kit!

  1. What is Liberica Native Image Kit?
  2. Turn a JavaFX app into a native image!
    1. Enable native compilation
    2. Compile the application
    3. Speed and memory comparison
    4. Limitations
  3. Conclusion
  4. Further reading

What is Liberica Native Image Kit?

Liberica Native Image Kit (NIK) is a utility based on the GraalVM Community Edition. It helps to convert JVM-based applications into native executables. Liberica NIK enhances the experience of writing desktop applications as the native image takes up less disc space and starts up almost instantly.

The benefits of using Liberica NIK in your enterprise development:

  • Supports a wide variety of platforms, features, and languages. We support Windows, Linux, and MacOS, including ARM-based Macs. Starting with version 21.3, Liberica NIK works with AWT/Swing and OpenJFX
  • Always on the latest versions of GraalVM CE and Liberica JDK with eliminated CVEs and bug fixes
  • Receives support from the engineers who develop the product

Turn a JavaFX app into a native image!

Enable native compilation

First, you need to download and install Liberica NIK. Go to the Liberica NIK Download Center and choose NIK version 22 for Java 11 or 17. You need the Full version as it includes LibericaFX, an instance of OpenJFX.

Download the package and follow the instructions to install the utility on your platform. macOS users should get the .dmg package to avoid any issues with running Liberica NIK.

You are now ready to compile Java applications natively. You have several options:

  • Manual invocation. From your NIK installation, run \ native-image <args class="bs-link" target="_blank"> -jar <your application jar>
  • Configure Maven build as described here
  • Configure Gradle build as described here

In all three cases, arguments you pass to the native-image invocation should include:

  • --add-modules javafx.controls,javafx.fxml,javafx.swing to include JavaFX modules (may change with the next release)
  • Your application is likely to use resources such as icons or images. These resources must be made known to native-image so that it includes them in the resulting executable. There are two options to include and exclude resource identifiers, and you can use wildcards there: \ -H:IncludeResources='com.fxapp.resources.images.*' \ -H:ExcludeResources='com.fxapp.resources.unused.*'

Alternatively, resources can be configured using JSON files. Many applications make use of dynamic language features such as reflective or JNI access. In this case, the feature being used, such as the name of the method called, is not known at image build time, so NIK cannot figure out exactly which method is called. These dynamic feature usages must be configured beforehand using JSON files as described here.

You can create JSON files using the native image agent. Run your application with the agent enabled, probably several times to exercise different code paths. The agent captures dynamic feature accesses and creates configuration files automatically. These files can be passed to native-image without further editing.

Compile the application

Let us now compile a JavaFX app natively. We will use the BrickBreaker game as an example. You can utilize your own app or select a JavaFX demo on GitHub. BrickBreaker requires no dynamic feature configuration. At the same time, it uses lots of images that need to be included in the resulting executable. In this example, image names are passed using -H:IncludeResources with a regular expression:

$ native-image --add-modules javafx.controls,javafx.fxml,javafx.swing -H:IncludeResources='ensemble.samples.shared-resources.brickImages.*' -jar BrickBreaker.jar

After the compilation has finished, run

$ ls -lh BrickBreaker

and then

$ ./BrickBreaker

Natively compiled BrickBreaker demo

Speed and memory comparison

The figures below were obtained on an Intel Core i7 laptop running Ubuntu Linux.

Liberica JRE 17.0.4.1 Native Image made with Liberica NIK 22.2.0-JDK17
Startup time 710ms 366ms
Maximum RSS 176M 133M
Executable size 276M (JRE+jar) 36M

Limitations

Modules javafx.media and javafx.web are currently not supported for native compilation. The javafx.media module is responsible for adding the playback of media and audio content. The javafx.web module defines the WebView functionality.

Conclusion

In this step-by-step tutorial, we learned how to generate JavaFX native images. Liberica NIK can also be used to create tiny containers saving precious cloud resources. Give it a try!

Further reading

Refer to our series of articles that explain how to use Liberica NIK with popular Java frameworks:

Generate a native executable with Spring Native — a version of Spring framework with built-in support for native images compilation

Create a microservice with Micronaut framework, designed especially for facilitating microservices development

Build a native image with Quarkus framework that natively supports GraalVM and MicroProfile APIs