Issue
I just downloaded JavaFX and set it up, I have done nothing else. I ran the sample code and this was the warning that popped up, although everything compiled. I'm using IntelliJ.
This is in Main.java:
package sample;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Main extends Application {
@Override
public void start(Stage primaryStage) throws Exception{
Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
primaryStage.setTitle("Hello World");
primaryStage.setScene(new Scene(root, 300, 275));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
This is in sample.fxml:
<?import javafx.geometry.Insets?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<GridPane fx:controller="sample.Controller"
xmlns:fx="http://javafx.com/fxml" alignment="center" hgap="10" vgap="10">
</GridPane>
When running, everything compiles, the window pops up, but I get the warning as stated in the title.
I never used JavaFX before so I'm unsure of where to locate this module.
Solution
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).
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.
Answered By - Slaw
Answer Checked By - Candace Johnson (JavaFixing Volunteer)