如何将带有额外模块的 JavaFX 导出到 JAR

How do I export a JavaFX with extra modules to a JAR

我目前有一个应用程序使用了一些导入的模块,例如 Jackson 和 MSSQL JDBC。我目前不使用 Maven、Gradle 或 ANT 等任何工具。 我尝试导出 JavaFX JAR,并将它们提取到 JAR 中,如下图所示。

但是我得到了错误:

Error: Could not find or load main class apicall.Main
Caused by: java.lang.ClassNotFoundException: apicall.Main

当我包含它们而不提取它们时,如下图所示:

然后应用程序 运行s 但是当我尝试调用 SQL 数据库时抛出以下错误:java.sql.SQLException: No suitable driver found for jdbc:sqlserver

我目前通过在控制台中键入以下命令来 运行 JAR:

java --module-path "C:\Program Files\Java\javafx-sdk-15\lib" --add-modules javafx.controls,javafx.fxml -jar APICall.jar

如何使用上面列出的相同或类似命令将 JavaFX JAR 和我需要的所有模块导出到 运行?

编辑:JAR结构如下:

堆栈跟踪如下所示:

答案取决于一件事:

is APICall a modular jar? does it contains a module-info.java?
  • 如果APICall是一个模块化jar,它只能访问模块导出的包而不能访问class路径。

  • 如果 APICall 不是模块化 jar,那么它必须成为一个“自动模块”才能访问模块和 classpath 导出的包。

来自提供的依赖项列表:

  • javafx 依赖项是模块
  • jackson 依赖是模块
  • commons-io 不是模块
  • mysql-jdbc不是模块

那么我们来说说第一个选项

API调用是一个模块

这意味着,jar 包含一个 module-info 并且明确需要他执行所需的包。这也意味着 APICall 无法访问 commons-io 和 mysql-jdbc 如果它们在 class 路径中。因此必须将 commons-io 和 mysql-jdbc 添加到要转换为自动模块并可访问的模块路径。必须将适当的“require”子句添加到模块信息文件中。

对于 运行 应用程序,您需要提供 3 样东西:

  • 使用--module-path 或-p
  • 在哪里可以找到依赖模块和主模块
  • 哪个模块是主模块使用--module或-m
  • 主要class到运行(如果MANIFEST文件没有提供)

命令类似于:

java --module-path <list of folders containing javafx/jacksons/commons/mysqljdbc/APICall jars> --module <APICall module name>/apicall.Main

API调用不是模块

这意味着,jar 不包含模块信息,并且必须在命令行中显式提供所需的模块依赖项。这也意味着 APICall 必须成为一个自动模块来访问模块和 classpath.

对于运行申请,您需要提供 4 样东西:

  • 使用 --module-path 或 -p
  • 在何处查找依赖模块
  • 在哪里可以使用 --class-path 或 -classpath 或 -cp
  • 找到相关的非模块化 jar
  • 哪个模块是主模块使用--module或-m
  • 主要class到运行(如果MANIFEST文件没有提供)

知道自动模块名称如果未在 MANIFEST 文件中提供是从版本中剥离的 jar 名称,那么 APICall.jar 自动模块名称将是“APICall”

命令类似于:

java --module-path <list of folders containing javafx/jacksons/APICall jars> --add-modules <list of module names required by APICall> --class-path <path to commons-io/mysql-jdbc jars> --module APICall/apicall.Main

PS:如果你不想提供要加载的模块列表到 --add-modules 参数,你可以使用这个常量“ALL-MODULE-PATH”,它将加载所有在模块路径

中找到的模块

英语不是我的语言所以我希望我足够清楚

编辑:

关于你的APICall.jar:

无法按原样加载内部结构。 Jar 不能包含 jar。 它可以通过使用自定义 classloader 来实现,但这将是一个棘手的问题。 springboot就用了这种classloader,想看的话

无论如何,我猜您正在尝试创建一个“胖”罐子。手动创建一个 fat jar 是个坏主意。可以犯这么多错误。所以我建议你使用一些构建工具,比如 gradle 或 maven 来创建它。

这些是关于您的 jar 内容的一些评论:

  • apicall: 你的app的基础包,这个就可以了
  • com:又是一个基础包,可能是提取javafx或者jackson依赖的结果。好的
  • javafx:基础包,javafx的jar解压后的结果。您已经使用 --module-path 提供了这些模块,那么为什么将它们包含在您的 jar 中?
  • javafx.base:从javafx.base.jar 中提取的模块。 KO。 jar 不能包含模块,只能包含包。 “javafx.base”不是有效的程序包名称。这不会被加载
  • javafx.controls:同上
  • javafx.fxml:同上
  • javafx.graphics:同上
  • javafx.media:同上
  • javafx.swing:同上
  • javafx.web:同上
  • META-INF:包含一个 MANIFEST 文件,其中可能包含您应用的主要 class。最重要的一点是“服务”文件夹。它必须包含与它们提供的服务接口同名的文件,其中包含实现 classes 的列表。 Jackson 和 mssql jar 提供这些服务。你 add/merge 那些文件了吗?
  • microsoft:如果您正在创建一个 fat jar,则缺少这个。这个包存在于 mssql-driver jar 但不在你的 jar
  • mssql:如果你正在创建一个 fat jar,这个就丢失了。这个包存在于 mssql-driver jar 但不在你的 jar
  • org:如果你正在创建一个胖罐子,这个就不见了。这个包存在于 commons-io jar 但不在你的 jar
  • commons-io-2.8.0.jar:无法访问,必须提取
  • jackson-annotations-2.11.3.jar:无法访问,必须提取
  • jackson-core-2.11.3.jar:无法访问,必须提取
  • jackson-databind-2.11.3.jar:无法访问,必须提取
  • 模块-info.class:里面是什么?
  • mssql-jdbc-8.4.1.jre14.jar:无法访问,必须提取

总而言之:你的罐子一团糟。

我建议你:

  • 不要创建 fat jar 并使用本文顶部提供的解决方案 post
  • 使用 fat jar 但使用 gradle 或 maven

编辑:

并添加到列表中 错误的

根据您的评论,您缺少文件

/META-INF/services/java.sql.Driver

需要此文件来为 java.sql API

注册驱动程序

您可以在 mssql-jdbc-8.4.1.jre14.jar 中找到一个,其中包含行

com.microsoft.sqlserver.jdbc.SQLServerDriver

没有它,你将永远得到:

java.sql.SQLException: No suitable driver found for jdbc:sqlserver