JavaFX 警告:不支持的 JavaFX 配置:类是从“未命名模块 @...”加载的背景警告溶液

2022-09-03 05:26:40

我刚刚下载了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>

运行时,所有内容都会编译,窗口会弹出,但我收到标题中所述的警告。

我以前从未使用过JavaFX,所以我不确定在哪里可以找到这个模块。


答案 1

TL;DR:

确保 JavaFX 已解析为命名模块

  • 非模块化应用:

    java --module-path <path-to-fx> --add-modules <fx-modules> ...
    
  • 模块化应用:

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

    其中包括您的模块以及JavaFX。<path>

  • 使用包含 JavaFX 的 JDK 发行版(有关详细信息,请参阅下面的答案)。可能仍需要使用 。--add-modules


背景

此警告与 Java 9 中引入的 Java 平台模块系统 (JPMS) 有关。如果您不熟悉模块,那么我建议您阅读了解 Java 9 模块以获取简要概述。

JPMS 带来了模块路径,它现在与类路径一起存在。当从类路径加载类时,它们将成为所谓的未命名模块的一部分。而模块路径上的类包含在模块中,因此被加载到“命名模块中”。命名模块可能是自动的,也可能不是自动的,这取决于它是否具有描述符。module-info


警告

JavaFX 仅支持作为命名模块加载。换句话说,JavaFX 仅支持从模块路径加载,而不支持从类路径加载。自版本9以来,当框架被模块化时,这一直是隐含的。但是现在,从版本16开始,如果JavaFX检测到它是从类路径加载的(即在未命名的模块中),则会发出警告。请参见 JDK-8256362


溶液

解决方案是确保从模块路径加载 JavaFX 并将其解析为命名模块。注意 JavaFX 由七个模块组成,从其文档中可以看出。

您如何确保将JavaFX解析为命名模块可能取决于您的环境(例如,非模块化与模块化应用程序,外部JavaFX SDK等)。下面的示例都使用命令行来演示如何设置所需的参数。但是,如果您使用的是 IDE(例如 NetBeans、IntelliJ、Eclipse)和/或构建工具(例如 Maven、Gradle),并且不确定在何处设置这些参数,请查看 JavaFX 11+ 入门

请注意,Gradle和Maven都有插件,可以更轻松地使用JavaFX(即它们为您处理所有配置)。

非模块化应用

如果你的代码是非模块化的,那么你没有描述符。这意味着将JavaFX添加到模块路径是不够的;您还必须强制Java解析JavaFX模块。这可以通过参数来完成。module-info--add-modules

例如:

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

请注意,我只在参数中包含模块。这是因为它需要 和 模块,这意味着它们将被隐式拉入。javafx.controls--add-modulesjavafx.basejavafx.graphics

如果您需要其他模块,那么还需要将它们包含在参数中,并用逗号分隔。--add-modules

另外,请注意,在这种情况下,可以将代码和其他非模块化依赖项放在类路径上。重要的部分是 JavaFX 是从模块路径加载的。

模块化应用

如果你的代码是模块化的,那么你有一个描述符。此描述符将具有必要的指令。在这种情况下,您不再需要使用 ,但您需要确保通过 将应用程序作为模块启动。module-inforequires--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 发行版

从Java 11开始,JavaFX不再包含在Oracle提供的JDK中。但Oracle并不是唯一一家基于OpenJDK的Java供应商。有一些供应商提供JDK发行版,其中包括JavaFX。其中至少有两个是:

当JavaFX包含在JDK中时,它现在就像所有其他Java模块(例如)一样是运行时映像的一部分。这意味着它将自动作为命名模块加载,您不再需要手动将JavaFX放在模块路径上。但是,如果您的应用程序是非模块化的,那么您可能仍然需要使用(不确定)。java.base--add-modules

部署

当您去部署 JavaFX 应用程序时,在运行时映像中包含 JavaFX 可能是最简单的方法。您可以使用 / 工具执行此操作。这可以通过包含JavaFX的JDK或外部JavaFX SDK来完成。但是,如果使用后者,请确保在创建自定义运行时映像时使用 JMOD 文件(或使用 Maven Central 中的 JavaFX JAR,它嵌入了所需的本机代码)。jlinkjpackage

如果您的代码是非模块化的,那么您将创建一个包含 JavaFX(以及应用程序所需的所有其他非自动命名模块)的自定义运行时映像,然后进行配置以将代码(以及所有非模块化依赖项)放在类路径上。jpackage

忽略警告

据我所知,如果从类路径加载 JavaFX,则当前不会中断任何内容。这意味着另一种选择,至少现在是这样,就是忽略警告。但是,我建议至少将JavaFX放在模块路径上,如果您可以毫不费力地这样做的话。


答案 2

推荐