无法启动使用 Apache POI 的 JavaFX 应用程序

Jos*_*ang 4 java javafx apache-poi javafx-17

我有一个按预期工作的 JavaFX 应用程序。我需要使用 Apache POI 来读取和写入 excel 文件。以下是我已采取的步骤:

  1. 添加了所需的依赖

    implementation 'org.apache.poi:poi-ooxml:5.2.3'

  2. 将模块添加到 module-info.java

    requires org.apache.poi.ooxml;

  3. 尝试在函数中使用该库:

@FXML
private void downloadTemplate() {
    XSSFWorkbook workbook = new XSSFWorkbook();
}
Run Code Online (Sandbox Code Playgroud)

这一切都很好,没有任何问题。但是,当我尝试运行该应用程序时,出现以下两个错误(互换)

> Task :Start.main() FAILED
Error occurred during initialization of boot layer
java.lang.module.FindException: Module SparseBitSet not found, required by org.apache.poi.ooxml
Run Code Online (Sandbox Code Playgroud)

> Task :Start.main() FAILED
Error occurred during initialization of boot layer
java.lang.module.FindException: Module commons.math3 not found, required by org.apache.poi.ooxml
Run Code Online (Sandbox Code Playgroud)

但是,我可以清楚地看到“外部库”下的两个库 扩展库视图

我正在使用 IntelliJ Community Edition 2022.1.2 并使用 Java 17.0.1 运行该项目。任何帮助将不胜感激。

jew*_*sea 6

SparseBitSet是一个自动模块,它没有自己的模块信息(可能 commons-math3 也是如此),并且在其清单中没有自动模块名称条目。

\n

Gradle 将没有 module-info.class 或 Automatic-Module-Name 的库放在类路径(而不是模块路径)的清单中,因此它们不会被视为模块,模块查找器也不会找到他们。

\n

你可以:

\n
    \n
  1. 破解 gradle 构建以允许找到模块。(我不使用 Gradle,所以除了参考文档之外,我没有关于如何执行此操作的具体建议)。
  2. \n
  3. 破解您想要将其视为模块的库 jar,以在其清单中包含 module-info.class 或 Automatic-Module-Name。
  4. \n
  5. 或者,切换到 Maven,它会自动将自动模块放置在模块路径上。\n\n
  6. \n
  7. 或者,正如 swpalmer 在评论中建议的那样,请求库维护者更新他们的代码库,使他们的库模块化。
  8. \n
\n

并且,当您运行应用程序时,请确保所有 jar 都位于模块路径上,而不是类路径上。

\n

或者,通过从中删除 module-info.java 使您的应用程序成为非模块化应用程序,然后手动将 JavaFX 模块放置在模块路径上并使用开关添加它们--add-modules

\n

常问问题

\n
\n

您确定 Gradle 将自动模块放入类路径中吗?

\n
\n

来自Gradle 文档部分 Building Modules for the Java Module System

\n
\n

为了告诉 Java 编译器 Jar 是一个模块,而不是传统的 Java 库,Gradle 需要将其放置在所谓的模块路径上。它是类路径的替代方案,\n这是告诉编译器有关已编译依赖项的传统方法。\n如果满足以下三项,Gradle 会自动将依赖项的 Jar 放在模块\n路径上,而不是类路径上:

\n
    \n
  • java.modularity.inferModulePath 未关闭

    \n
  • \n
  • 我们实际上正在构建一个模块(而不是传统的\n库),我们通过添加 module-info.java 文件来表达该模块。\n(另一个选项是添加自动模块名称 Jar 清单\n属性,如下所述) .)

    \n
  • \n
  • 我们的模块依赖的 Jar 本身就是一个模块,Gradles\n根据模块信息的存在来决定。class\xe2\x80\x89\xe2\x80\x94\xe2\x80\x89模块的编译\n版本Jar 中的描述符\xe2\x80\x89\xe2\x80\x94\xe2\x80\x89。(或者,\nJar 清单中是否存在自动模块名称属性)

    \n
  • \n
\n
\n

第三点才是关键。Java 可以将 Jar 清单中没有 module-info.class 且没有 Automatic-Module-Name 的库视为自动模块(如果它位于模块路径上)。但是,Gradle 默认情况下仅将满足这两个条件之一的库放置在模块路径上。

\n