JavaFX 警告:不支持的 JavaFX 配置:类 是从 'unnamed module @...' 加载的
JavaFX WARNING: Unsupported JavaFX configuration: classes were loaded from 'unnamed module @...'
我只是下载了 JavaFX 并进行了设置,我没有做任何其他事情。我 运行 示例代码,这是弹出的警告,尽管所有内容都已编译。我正在使用 IntelliJ。
这是在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);
}
}
这在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>
当运行,一切都编译时,弹出window,但我收到标题中所述的警告。
我以前从未使用过 JavaFX,所以我不确定在哪里可以找到这个模块。
TL;DR:
确保 JavaFX 被解析为 命名模块。
非模块化应用程序:
java --module-path <path-to-fx> --add-modules <fx-modules> ...
模块化应用:
java --module-path <path> --module <main-module>/<main-class> [args...]
其中 <path>
包括您的模块以及 JavaFX。
使用 JDK 发行版,其中包括 JavaFX(有关更多信息,请参阅下面的答案)。可能还需要用--add-modules
.
背景
此警告与 Java 平台模块系统 (JPMS) 有关 Java 9. 如果您不熟悉模块,那么我建议阅读 Understanding Java 9 Modules 以获得简要概述。
JPMS 带来了模块路径,它现在与 class 路径并存。当从 class 路径加载 classes 时,它们成为所谓的 未命名模块 的一部分。而模块路径上的 classes 包含在模块中,因此被加载“到” 命名模块 。命名模块可能会或可能不会 自动 ,分别取决于它是否具有 module-info
描述符。
警告
JavaFX 仅支持加载为命名模块。换句话说,JavaFX 只支持从模块路径加载,而不支持从 class 路径加载。从版本 9 开始,当框架被模块化时,这是隐式的。但是现在,从版本 16 开始,如果 JavaFX 检测到它是从 class 路径加载的(即在 未命名模块 中),则会发出警告.参见 JDK-8256362。
解决方案
解决方案是确保 JavaFX 从模块路径加载并解析为 命名模块 。注意JavaFX是由七个模块组成的,its documentation.
可以看出
如何确保 JavaFX 被解析为命名模块可能取决于您的环境(例如,非模块化与模块化应用程序、外部 JavaFX SDK 等)。下面的示例都使用命令行来说明如何设置所需的参数。但是,如果您正在使用 IDE(例如 NetBeans、IntelliJ、Eclipse)and/or 构建工具(例如 Maven、Gradle)并且不确定在哪里设置这些参数,那么查看 Getting Started with JavaFX 11+.
请注意,Gradle 和 Maven 都有插件,可以更轻松地使用 JavaFX(即它们会为您处理所有配置)。
非模块化应用程序
如果您的代码是非模块化的,那么您就没有 module-info
描述符。这意味着将 JavaFX 添加到模块路径是不够的;您还必须强制 Java 解析 JavaFX 模块。这可以通过 --add-modules
参数来完成。
例如:
java --module-path <path-to-fx> --add-modules javafx.controls ...
注意我只在 --add-modules
参数中包含了 javafx.controls
模块。这是因为它需要 javafx.base
和 javafx.graphics
模块,这意味着它们将被隐式引入。
如果您需要其他模块,那么您也需要将它们包含在 --add-modules
参数中,以逗号分隔。
另外,请注意,在这种情况下,将您的代码和其他非模块化依赖项放在 class 路径上是可以的。重要的部分是 JavaFX 是从模块路径加载的。
模块化应用程序
如果您的代码是模块化的,那么您将 有一个module-info
描述符。该描述符将具有必要的 requires
指令。在这种情况下,您不再需要使用 --add-modules
,但您需要确保通过 --module
.
将您的应用程序作为模块启动
例如:
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...]
请注意,您不仅需要将 JavaFX 放在模块路径中,还需要您自己的模块。
使用包含 JavaFX
的 JDK 分配
从Java11开始,JavaFX不再包含在Oracle提供的JDK中。但是 Oracle 并不是基于 OpenJDK 的 Java 的唯一供应商。有些供应商提供 JDK 发行版,其中包括 JavaFX。其中至少有两个是:
- BellSoft Liberica JDK(确保选择“完整 JDK”选项)。
- Azul Zulu JDK(确保选择“JDK FX”包)。
当 JavaFX 包含在 JDK 中时,它现在是 运行 时间图像的一部分,就像所有其他 Java 模块一样(例如 java.base
).这意味着它将自动加载为 命名模块 ,您不再需要手动将 JavaFX 放在模块路径上。但是,如果您的应用程序是非模块化的,那么您可能仍需要使用 --add-modules
(不确定)。
部署
当你去部署一个 JavaFX 应用程序时,在 运行 时间映像中包含 JavaFX 可能是最简单的方法。您可以使用 jlink
/ jpackage
工具执行此操作。这可以通过包含 JavaFX 的 JDK 或外部 JavaFX SDK 来完成。但是,如果您使用后者,请确保在制作自定义 运行-time 图像时使用 JMOD 文件(或使用来自 Maven Central 的 JavaFX JAR,它嵌入了所需的本机代码)。
如果您的代码是非模块化的,那么您将创建一个包含 JavaFX(以及您的应用程序所需的所有其他非自动命名模块)的自定义 运行 时间图像),然后配置 jpackage
以将您的代码(以及所有非模块化依赖项)放在 class 路径上。
忽略警告
据我所知,如果从 class 路径加载 JavaFX,目前 不会中断。这意味着另一种选择,至少现在是忽略警告。但是,我建议至少将 JavaFX 放在模块路径上,如果这样做不会太麻烦的话。
我只是下载了 JavaFX 并进行了设置,我没有做任何其他事情。我 运行 示例代码,这是弹出的警告,尽管所有内容都已编译。我正在使用 IntelliJ。
这是在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);
}
}
这在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>
当运行,一切都编译时,弹出window,但我收到标题中所述的警告。
我以前从未使用过 JavaFX,所以我不确定在哪里可以找到这个模块。
TL;DR:
确保 JavaFX 被解析为 命名模块。
非模块化应用程序:
java --module-path <path-to-fx> --add-modules <fx-modules> ...
模块化应用:
java --module-path <path> --module <main-module>/<main-class> [args...]
其中
<path>
包括您的模块以及 JavaFX。使用 JDK 发行版,其中包括 JavaFX(有关更多信息,请参阅下面的答案)。可能还需要用
--add-modules
.
背景
此警告与 Java 平台模块系统 (JPMS) 有关 Java 9. 如果您不熟悉模块,那么我建议阅读 Understanding Java 9 Modules 以获得简要概述。
JPMS 带来了模块路径,它现在与 class 路径并存。当从 class 路径加载 classes 时,它们成为所谓的 未命名模块 的一部分。而模块路径上的 classes 包含在模块中,因此被加载“到” 命名模块 。命名模块可能会或可能不会 自动 ,分别取决于它是否具有 module-info
描述符。
警告
JavaFX 仅支持加载为命名模块。换句话说,JavaFX 只支持从模块路径加载,而不支持从 class 路径加载。从版本 9 开始,当框架被模块化时,这是隐式的。但是现在,从版本 16 开始,如果 JavaFX 检测到它是从 class 路径加载的(即在 未命名模块 中),则会发出警告.参见 JDK-8256362。
解决方案
解决方案是确保 JavaFX 从模块路径加载并解析为 命名模块 。注意JavaFX是由七个模块组成的,its documentation.
可以看出如何确保 JavaFX 被解析为命名模块可能取决于您的环境(例如,非模块化与模块化应用程序、外部 JavaFX SDK 等)。下面的示例都使用命令行来说明如何设置所需的参数。但是,如果您正在使用 IDE(例如 NetBeans、IntelliJ、Eclipse)and/or 构建工具(例如 Maven、Gradle)并且不确定在哪里设置这些参数,那么查看 Getting Started with JavaFX 11+.
请注意,Gradle 和 Maven 都有插件,可以更轻松地使用 JavaFX(即它们会为您处理所有配置)。
非模块化应用程序
如果您的代码是非模块化的,那么您就没有 module-info
描述符。这意味着将 JavaFX 添加到模块路径是不够的;您还必须强制 Java 解析 JavaFX 模块。这可以通过 --add-modules
参数来完成。
例如:
java --module-path <path-to-fx> --add-modules javafx.controls ...
注意我只在 --add-modules
参数中包含了 javafx.controls
模块。这是因为它需要 javafx.base
和 javafx.graphics
模块,这意味着它们将被隐式引入。
如果您需要其他模块,那么您也需要将它们包含在 --add-modules
参数中,以逗号分隔。
另外,请注意,在这种情况下,将您的代码和其他非模块化依赖项放在 class 路径上是可以的。重要的部分是 JavaFX 是从模块路径加载的。
模块化应用程序
如果您的代码是模块化的,那么您将 有一个module-info
描述符。该描述符将具有必要的 requires
指令。在这种情况下,您不再需要使用 --add-modules
,但您需要确保通过 --module
.
例如:
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...]
请注意,您不仅需要将 JavaFX 放在模块路径中,还需要您自己的模块。
使用包含 JavaFX
的 JDK 分配从Java11开始,JavaFX不再包含在Oracle提供的JDK中。但是 Oracle 并不是基于 OpenJDK 的 Java 的唯一供应商。有些供应商提供 JDK 发行版,其中包括 JavaFX。其中至少有两个是:
- BellSoft Liberica JDK(确保选择“完整 JDK”选项)。
- Azul Zulu JDK(确保选择“JDK FX”包)。
当 JavaFX 包含在 JDK 中时,它现在是 运行 时间图像的一部分,就像所有其他 Java 模块一样(例如 java.base
).这意味着它将自动加载为 命名模块 ,您不再需要手动将 JavaFX 放在模块路径上。但是,如果您的应用程序是非模块化的,那么您可能仍需要使用 --add-modules
(不确定)。
部署
当你去部署一个 JavaFX 应用程序时,在 运行 时间映像中包含 JavaFX 可能是最简单的方法。您可以使用 jlink
/ jpackage
工具执行此操作。这可以通过包含 JavaFX 的 JDK 或外部 JavaFX SDK 来完成。但是,如果您使用后者,请确保在制作自定义 运行-time 图像时使用 JMOD 文件(或使用来自 Maven Central 的 JavaFX JAR,它嵌入了所需的本机代码)。
如果您的代码是非模块化的,那么您将创建一个包含 JavaFX(以及您的应用程序所需的所有其他非自动命名模块)的自定义 运行 时间图像),然后配置 jpackage
以将您的代码(以及所有非模块化依赖项)放在 class 路径上。
忽略警告
据我所知,如果从 class 路径加载 JavaFX,目前 不会中断。这意味着另一种选择,至少现在是忽略警告。但是,我建议至少将 JavaFX 放在模块路径上,如果这样做不会太麻烦的话。