IntelliJ 无法使用 OpenJDK 11 识别 JavaFX 11

IT小君   2021-09-09T02:01:56

我无法让 IntellJ 识别 JavaFX 包。使用新的 JavaFX 项目,使用 OpenJDK 11,尝试构建项目时,IntelliJ 无法识别 JavaFX 包。

我是openjfx:javafx-base-11从 Maven 仓库导入的。

我查看了其他问题,解决方案似乎包括检查字节码是否处于正确级别(我的是),以及项目语言是否正确(我的是)。

谁有想法?

图1

图2

图3

编辑:

错误:

在此处输入图片说明

评论(5)
IT小君

正如评论中提到的,入门指南是从 Java 11 和 JavaFX 11 开始的地方。

像在 Java 11 之前一样工作的关键是要了解:

  • JavaFX 11 不再是 JDK 的一部分
  • 您可以以不同的形式获取它,作为 SDK 或常规依赖项(maven/gradle)。
  • 即使您的项目不是模块化的,您也需要将其包含在项目的模块路径中。

JavaFX 项目

如果您在 IntelliJ(没有 Maven 或 Gradle)中创建一个常规的 JavaFX 默认项目,我建议您从这里下载 SDK 请注意,也有 jmods,但对于非模块化项目,首选 SDK。

这些是运行默认项目的简单步骤:

  1. 创建 JavaFX 项目
  2. 设置 JDK 11(指向您本地的 Java 11 版本)
  3. 添加 JavaFX 11 SDK 作为库。URL 可能类似于/Users/<user>/Downloads/javafx-sdk-11/lib/. 执行此操作后,您会注意到现在可以在编辑器中识别 JavaFX 类。

JavaFX 11 项目

  1. 在运行默认项目之前,您只需要将这些添加到 VM 选项中:

    --module-path /Users/<user>/Downloads/javafx-sdk-11/lib --add-modules=javafx.controls,javafx.fxml

马文

如果您使用 Maven 构建您的项目,请按照以下步骤操作:

  1. 使用 JavaFX 原型创建 Maven 项目
  2. 设置 JDK 11(指向您本地的 Java 11 版本)
  3. 添加 JavaFX 11 依赖项。

    <dependencies>
        <dependency>
            <groupId>org.openjfx</groupId>
            <artifactId>javafx-controls</artifactId>
            <version>11</version>
        </dependency>
        <dependency>
            <groupId>org.openjfx</groupId>
            <artifactId>javafx-fxml</artifactId>
            <version>11</version>
        </dependency>
    </dependencies>
    

执行此操作后,您会注意到现在可以在编辑器中识别 JavaFX 类。

JavaFX 11 Maven 项目

您会注意到 Maven 为您管理所需的依赖项:它将为 javafx.controls 添加 javafx.base 和 javafx.graphics,但最重要的是,它将根据您的平台添加所需的分类器就我而言,Mac。

这就是为什么你的 jarsorg.openjfx:javafx-controls:11空的,因为有三种可能的分类器(windows、linux 和 mac 平台),它们包含所有类和本机实现。

如果您仍想转到 .m2 存储库并手动从那里获取依赖项,请确保选择正确的(例如.m2/repository/org/openjfx/javafx-controls/11/javafx-controls-11-mac.jar

  1. 这里的插件替换默认的 maven 插件

  2. 运行mvn compile javafx:run,它应该可以工作。

类似的工作也适用于 Gradle 项目,详细解释见此处

编辑

提到的入门指南包含IntelliJ 的更新文档和示例项目:

2021-09-09T02:01:56   回复
IT小君

JavaFX 不再是 JDK 11 的一部分的问题。以下解决方案适用于 IntelliJ(尚未使用 NetBeans 尝试过):

  1. 添加 JavaFX 全局库作为依赖项:

    设置 -> 项目结构 -> 模块。在模块中,转到依赖项选项卡,然后单击添加“+”号 -> 库 -> Java-> 从列表中选择 JavaFX,然后单击添加所选,然后应用设置。

  2. 右键单击 JavaFX 项目中的源文件 (src),然后创建一个新的 module-info.java 文件在文件中写入以下代码:

    module YourProjectName { 
        requires javafx.fxml;
        requires javafx.controls;
        requires javafx.graphics;
        opens sample;
    }
    

    我向您保证,这两个步骤将解决您使用 JavaFX 的所有问题。

参考:The Learn Programming 频道有一个 You Tube 教程,将在短短 5 分钟内解释上述所有细节。我还建议观看它以解决您的问题:https : //www.youtube.com/watch?v=WtOgoomDewo

2021-09-09T02:01:56   回复
IT小君

以上都不适合我。我花了太多时间来清除出现的其他错误。我发现这是最简单和最好的方法。

这也适用于在 Jdk 11、12 和 OpenJdk12 上获取 JavaFx!

  • 该视频向您展示了 JavaFx Sdk 下载
  • 如何将其设置为全局库
  • 设置module-info.java(我更喜欢底部的)

module thisIsTheNameOfYourProject {
    requires javafx.fxml;
    requires javafx.controls;
    requires javafx.graphics;
    opens sample;
}

整个过程只花了我 5 分钟!!!

2021-09-09T02:01:57   回复
IT小君

快速总结,您可以执行以下任一操作:

  1. 在 José 的回答中包含 JavaFX 模块 via--module-path--add-moduleslike。

或者

  1. 将 JavaFX 库添加到项目后(手动或通过 maven/gradle 导入),添加module-info.java与此答案中指定文件类似文件。(请注意,此解决方案使您的应用程序模块化,因此如果您使用其他库,您还需要添加语句以在module-info.java文件中要求它们的模块)。

这个答案是对何塞答案的补充。

情况是这样的:

  1. 您使用的是最新的 Java 版本,例如 13。
  2. 您有一个 JavaFX 应用程序作为 Maven 项目。
  3. 在您的 Maven 项目中,您已按照 Jose 的回答配置了 JavaFX 插件并设置了 JavaFX 依赖项。
  4. 您转到扩展 Application 的主类的源代码,右键单击它并尝试运行它。
  5. IllegalAccessError尝试启动应用程序时,您会遇到一个“未命名的模块”。

IllegalAccessError尝试从 Intellij Idea 运行 JavaFX 应用程序时生成的堆栈跟踪摘录

Exception in Application start method
java.lang.reflect.InvocationTargetException
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:567)
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:464)
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:363)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:567)
    at java.base/sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:1051)
Caused by: java.lang.RuntimeException: Exception in Application start method
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:900)
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication$2(LauncherImpl.java:195)
    at java.base/java.lang.Thread.run(Thread.java:830)
Caused by: java.lang.IllegalAccessError: class com.sun.javafx.fxml.FXMLLoaderHelper (in unnamed module @0x45069d0e) cannot access class com.sun.javafx.util.Utils (in module javafx.graphics) because module javafx.graphics does not export com.sun.javafx.util to unnamed module @0x45069d0e
    at com.sun.javafx.fxml.FXMLLoaderHelper.<clinit>(FXMLLoaderHelper.java:38)
    at javafx.fxml.FXMLLoader.<clinit>(FXMLLoader.java:2056)
    at org.jewelsea.demo.javafx.springboot.Main.start(Main.java:13)
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$9(LauncherImpl.java:846)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runAndWait$12(PlatformImpl.java:455)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:428)
    at java.base/java.security.AccessController.doPrivileged(AccessController.java:391)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:427)
    at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
Exception running application org.jewelsea.demo.javafx.springboot.Main

好的,现在你有点卡住了,不知道发生了什么。

实际发生的事情是这样的:

  1. Maven 已成功为您的应用程序下载了 JavaFX 依赖项,因此您无需单独下载依赖项或安装 JavaFX SDK 或模块分发或类似的东西。
  2. Idea 已成功将模块作为依赖项导入到您的项目中,因此一切编译正常,所有代码完成,一切正常。

所以看起来一切都应该没问题。但是,当您运行应用程序时,JavaFX 模块中的代码在尝试使用反射来实例化应用程序类(调用启动时)和 FXML 控制器类(加载 FXML 时)的实例时失败。如果没有一些帮助,这种反射的使用在某些情况下可能会失败,产生晦涩的IllegalAccessError. 这是由于 Java 模块系统安全功能不允许来自其他模块的代码在您的类上使用反射,除非您明确允许它(JavaFX 应用程序启动器和 FXMLLoader 都需要在其当前实现中进行反射才能使其正常工作)正确)。

这是该问题的其他一些答案(参考module-info.java)出现的地方。

因此,让我们参加 Java 模块速成课程:

关键部分是这样的:

4.9. 打开

如果我们需要允许反射私有类型,但又不想暴露所有代码,我们可以使用 opens 指令来暴露特定的包。

但请记住,这将向全世界打开包裹,因此请确保这是您想要的:

module my.module { opens com.my.package; }

所以,也许你不想向全世界开放你的包裹,那么你可以这样做:

4.10. 打开……到

好的,所以反射有时很棒,但我们仍然希望从封装中获得尽可能多的安全性。我们可以有选择地将我们的包打开到预先批准的模块列表中,在这种情况下,使用 opens...to 指令:

module my.module { 打开 com.my.package 到 moduleOne、moduleTwo 等;}

所以,你最终创建了一个 src/main/java/module-info.java 类,它看起来像这样:

module org.jewelsea.demo.javafx.springboot {
    requires javafx.fxml;
    requires javafx.controls;
    requires javafx.graphics;
    opens org.jewelsea.demo.javafx.springboot to javafx.graphics,javafx.fxml;
}

org.jewelsea.demo.javafx.springboot包含 JavaFX 应用程序类和 JavaFX 控制器类的包的名称在哪里(将其替换为应用程序的适当包名称)。这告诉Java运行时,它是类的OK javafx.graphics,并javafx.fxml就在你的类调用反射org.jewelsea.demo.javafx.springboot包。完成此操作后,应用程序被编译并重新运行,一切都会正常运行IllegalAccessError,JavaFX 使用反射生成的问题将不再发生。

但是如果你不想创建一个 module-info.java 文件怎么办

如果不是使用 IDE 顶部工具栏中的运行按钮直接运行应用程序类,而是:

  1. 转到IDE一侧的Maven窗口。
  2. 选择 JavaFX maven 插件目标javafx.run
  3. 右键单击它并选择Run Maven BuildDebug...

然后应用程序将在没有module-info.java文件的情况下运行我猜这是因为 maven 插件足够智能,可以动态包含某种设置,即使没有module-info.java文件,JavaFX 类也可以反映应用程序,尽管我不知道这是如何实现的。

要将该设置传输到顶部工具栏中的“运行”按钮,请右键单击javafx.runMaven 目标并Create Run/Debug Configuration为目标选择选项然后您可以从顶部工具栏中选择 Run 来执行 Maven 目标。

2021-09-09T02:01:57   回复
IT小君

一个很好的解释可以在

https://edencoding.com/runtime-components-error/

包含

  1. 提供对模块的反射访问

  2. 授予其他人访问您的模块的权限

总而言之,我们需要添加到上述答案中,将导出添加到您的模块定义中

module my.project {
    requires javafx.fxml;
    requires javafx.controls;
    opens my.project to javafx.graphics;
    exports my.project;
}
2021-09-09T02:01:57   回复