首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >了解主类如何影响JPMS

了解主类如何影响JPMS
EN

Stack Overflow用户
提问于 2019-02-18 22:15:19
回答 1查看 276关注 0票数 7

我有一个非常基本的JavaFX应用程序,如果应用程序类是而不是主类,它就能完美地工作:

代码语言:javascript
复制
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.stage.Stage;

public class Main {

    public static void main(String[] args) {
        Application.launch(App.class, args);
    }

}

public class App extends Application {

    @Override
    public void start(Stage primaryStage) {
        FXMLLoader loader = new FXMLLoader(); // works
    }

}

但是,当我将这两者合并在一起(这是大多数教程(包括OpenJFX的官方文档)中推荐的方法)时,模块系统抛出一个IllegalAccessError (至少在OpenJDK 11.0.2上是这样):

代码语言:javascript
复制
public class MainApp extends Application {

    @Override
    public void start(Stage primaryStage) {
        FXMLLoader loader = new FXMLLoader(); // throws IllegalAccessError
    }

    public static void main(String[] args) {
        launch(MainApp.class, args);
    }

}

例外是:

java.lang.IllegalAccessError:类com.sun.javafx.fxml.FXMLLoaderHelper (在未命名的模块@0x642c1a1b中)无法访问类com.sun.javafx.util.Utils (在模块javafx.graphics中),因为模块javafx.graphics不将com.sun.javafx.util导出到未命名的模块@0x642c1a1b

奇怪的是,我没有积极地使用模块系统。我没有在我的项目中添加module-info.java。所以我假设所有东西都应该导出到任何未命名的模块中?但这根本不是重点。

主要问题是:如果跨两个类分发相同的代码,为什么相同的代码行为不同?在这两种情况下,FXMLLoader都使用com.sun.javafx.fxml.FXMLLoaderHelper,而后者又使用com.sun.javafx.util.Utils。所以,无论是在这两种情况下,我都应该得到例外,或者没有例外。有什么关系?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-02-19 00:14:28

有几个答案已经张贴,可以部分适用于您的问题,但它可能是方便收集在这里,并提出他们在一个完整的答案。

应用程序类

在对缺少Maven Shade JavaFX运行时组件的回答中,我解释了为什么当您使用Application类作为您的主类时,您需要使用模块系统。

总结如下:

正如您所读到的这里: 此错误来自于sun.launcher.LauncherHelper中的java.base模块(链接)。 如果主应用程序扩展了Application并具有main方法,则LauncherHelper将检查javafx.graphics模块是否以命名模块的形式出现:

代码语言:javascript
复制
Optional<Module> om = ModuleLayer.boot().findModule(JAVAFX_GRAPHICS_MODULE_NAME);
if (!om.isPresent()) {
    abort(null, "java.launcher.cls.error5");
}

如果该模块不存在,则中止启动。

每个JavaFX 11 jar都有一个module-info.class文件,因此根据定义,这些文件将被添加到模块路径中。

但是,如果不通过Application类运行,则不会完成检查。

主类

Maven和Eclipse启动JavaFX 11应用程序的不同行为的另一个答案解释了为什么当您在Maven exec:java插件中使用Launcher类(一个主类而不是扩展应用程序)时,它没有模块化的系统。

总结如下:

  • 为了克服上述的sun.launcher.LauncherHelper问题,需要使用启动程序。
  • 就像maven插件在类路径中运行一样,将所有依赖项加载到一个独立的线程中,本例中的IntelliJ也是如此。

如果在运行Main.main()时检查命令行

代码语言:javascript
复制
/path/to/jdk-11.0.2.jdk/Contents/Home/bin/java \
    "-javaagent:/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar=60556:/Applications/IntelliJ IDEA.app/Contents/bin"  \
    -Dfile.encoding=UTF-8  \
    -classpath /path/to/so-question-54756176-master/target/classes:/path/to/.m2/repository/org/openjfx/javafx-base/11.0.2/javafx-base-11.0.2.jar:.../path/to/.m2/repository/org/openjfx/javafx-fxml/11.0.2/javafx-fxml-11.0.2-mac.jar  \
    Main

来自JavaFX SDK的所有JavaFX jars都被添加到类路径中,并且您正在运行经典的java -cp ... Main

javafx.fxml失踪

错误:缺少IntelliJ运行时组件,运行此应用程序需要JavaFX运行时组件的其他答案解释了在模块系统上运行时所遇到的错误,但是您没有将javafx.fxml添加到--add-modules选项中。

代码语言:javascript
复制
Caused by: java.lang.IllegalAccessError: class com.sun.javafx.fxml.FXMLLoaderHelper (in unnamed module @0x5fce9dc5) 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 @0x5fce9dc5
    at com.sun.javafx.fxml.FXMLLoaderHelper.<clinit>(FXMLLoaderHelper.java:38)
    at javafx.fxml.FXMLLoader.<clinit>(FXMLLoader.java:2056)

您的错误说您使用的是FXML,但是它不能在模块路径中被解析,所以它试图通过反射访问,这失败了,因为您没有将该javafx.graphics打开到您的未命名模块。

所以现在你会问:我一开始就没有设置javafx.graphics

嗯,你没有,但IntelliJ为你做的!

运行MainApp.main()时检查命令行

代码语言:javascript
复制
/path/to/jdk-11.0.2.jdk/Contents/Home/bin/java \
    --add-modules javafx.base,javafx.graphics \
    --add-reads javafx.base=ALL-UNNAMED \
    --add-reads javafx.graphics=ALL-UNNAMED \
    "-javaagent:/Applications/IntelliJ IDEA.app/Contents/lib/idea_rt.jar=60430:/Applications/IntelliJ IDEA.app/Contents/bin" \
    -Dfile.encoding=UTF-8 \
    -classpath /path/to/so-question-54756176-master/target/classes:/path/to/.m2/repository/org/openjfx/javafx-base/11.0.2/javafx-base-11.0.2.jar:.../.m2/repository/org/openjfx/javafx-graphics/11.0.2/javafx-graphics-11.0.2-mac.jar \
    MainApp

您可以看到,默认情况下,IntelliJ添加了javafx.basejavafx.graphics。因此,只缺少javafx.fxml (当然,您应该添加模块路径)。

正如您所指出的,建议的解决方案在文档中。

在命令行中,使用--module-path包含指向JavaFX库文件夹的路径,在本例中使用--add-modules包含javafx.fxml (在这里没有控件)。

或者使用Maven插件。在某个时候,您将不得不离开您的IDE,因此您需要使用插件来运行应用程序。

Maven exec

关于Maven exec插件的最后一个注意事项是,如果您使用它的话:

更重要的是,推荐的Maven解决方案,直到为模块化系统修复了插件exec:java (好消息是,正如我们所说的是完成 ),将使用exec:exec,正如在这个问题中所解释的那样,因此您可以指定两个vm参数。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/54756176

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档