JavaFX WARNING: Unsupported JavaFX configuration: classes were loaded from ‘unnamed module @…’

TL;DR:

Make sure JavaFX is resolved as named modules.

  • Non-modular application:

    java --module-path <path-to-fx> --add-modules <fx-modules> ...
    
  • Modular application:

    java --module-path <path> --module <main-module>/<main-class> [args...]
    

    Where <path> includes your module as well as JavaFX.

  • Use JDK distribution which includes JavaFX (see answer below for more information). May still need to use --add-modules.


Background

This warning is related to the Java Platform Module System (JPMS) introduced in Java 9. If you’re not familiar with modules, then I recommend reading Understanding Java 9 Modules for a brief overview.

With JPMS came the module-path, which now exists alongside the class-path. When classes are loaded from the class-path they become a part of the so-called unnamed module. Whereas classes on the module-path are contained within modules, and are thus loaded “into” named modules. A named module may or may not be automatic, depending on if it has a module-info descriptor or not, respectively.


The Warning

JavaFX only supports being loaded as named modules. In other words, JavaFX only supports being loaded from the module-path, not the class-path. This has been implicitly true since version 9, back when the framework was modularized. But now, as of version 16, a warning is emitted if JavaFX detects it was loaded from the class-path (i.e. is in the unnamed module). See JDK-8256362.


Solution

The solution is to make sure JavaFX is loaded from the module-path and resolved as named modules. Note JavaFX is made up of seven modules, as can be seen by its documentation.

How exactly you ensure JavaFX is resolved as named modules may depend on your environment (e.g. non-modular vs modular application, external JavaFX SDK, etc.). The examples below all use the command-line to show how to set the needed arguments. However, if you’re using an IDE (e.g. NetBeans, IntelliJ, Eclipse) and/or a build tool (e.g. Maven, Gradle) and are unsure of where to set these arguments, then check out Getting Started with JavaFX 11+.

Note that both Gradle and Maven have plugins that make it easier to work with JavaFX (i.e. they handle all the configuration for you).

Non-modular Application

If your code is non-modular then you do not have a module-info descriptor. This means adding JavaFX to the module-path is not enough; you also have to force Java to resolve the JavaFX modules. That can be done via the --add-modules argument.

For example:

java --module-path <path-to-fx> --add-modules javafx.controls ...

Notice I only include the javafx.controls module in the --add-modules argument. This is because it requires the javafx.base and javafx.graphics modules, which means they will be implicitly pulled in.

If you need other modules then you need to include them in the --add-modules argument as well, separated by a comma.

Also, note it’s okay, in this case, to have your code and other non-modular dependencies on the class-path. The important part is that JavaFX is loaded from the module-path.

Modular Application

If your code is modular then you will have a module-info descriptor. This descriptor will have the necessary requires directives. In this case, you no longer need to use --add-modules, but you do need to make sure to launch your application as a module via --module.

For example:

module app {
  // transitively requires javafx.base and javafx.graphics
  requires javafx.controls;

  // export javafx.application.Application implementation's package
  // to at least javafx.graphics
  exports com.example.app to javafx.graphics;
}
java --module-path <path> --module app/com.example.app.Main [args...]

Note for this you need to not only put JavaFX on the module-path, but also your own module.

Use a JDK Distribution that Includes JavaFX

Since Java 11, JavaFX is no longer included in the JDK provided by Oracle. But Oracle is not the only vendor for Java based on OpenJDK. There are vendors out there that provide JDK distributions which include JavaFX. At least two of them are:

  • BellSoft Liberica JDK (make sure to choose the “Full JDK” option).
  • Azul Zulu JDK (make sure to choose the “JDK FX” package).

Also note that you can use jilnk to create a Java runtime that includes the JavaFX modules.

When JavaFX is included in the JDK, it’s now part of the run-time image like all the other Java modules (e.g. java.base). This means it will automatically be loaded as named modules and you no longer have to manually put JavaFX on the module-path. However, if your application is non-modular then you may still need to use --add-modules (not sure).

Deployment

When you go to deploy a JavaFX application, including JavaFX in the run-time image is likely the easiest approach. You can do this with the jlink / jpackage tools. And this can be done with either a JDK that includes JavaFX or an external JavaFX SDK. However, if you use the latter then make sure to use the JMOD files when making the custom run-time image (or use the JavaFX JARs from Maven Central, which embed the needed native code).

If your code is non-modular, then you’d create a custom run-time image that includes JavaFX (and all the other non-automatic named modules needed by your application), and then configure jpackage to place your code (and all non-modular dependencies) on the class-path.

Ignore the Warning

As far as I can tell, nothing currently breaks if JavaFX is loaded from the class-path. This means another option, at least for now, is to just ignore the warning. However, I recommend putting at least JavaFX on the module-path if you can do so without too much trouble.

Leave a Comment

tech