我有以下项目结构。
ProjectName
|
|---src
|
|---main
|
|---java
| |
| |---ModuleName
| |
| |---module-info.java
| |
| |---PackageName
| |
| |---Main.java
|
|---resources
|
|---ResourceParentFolder
|
|---ResourceSubFolderA
| |
| |---Resource1A.png
| |---Resource2A.png
| |---Resource3A.png
|
|---ResourceSubFolderB
|
|---Resource1B.png
|---Resource2B.png
|---Resource3B.png
我有一个 shell 脚本来编译代码,然后运行该代码。
javac \
--module-source-path="src/main/java" \
--module=ModuleName \
-d classes
java \
--module-path="classes;src/main/resources" \
--module=ModuleName/PackageName.Main
我还有一个 shell 脚本,可以将编译后的代码转换为模块化 jar,然后运行该 jar。
jar \
--verbose \
--create \
--file run/executable/jar/ProjectName.jar \
--main-class PackageName.Main \
-C classes/ModuleName . \
-C src/main/resources .
java \
--module-path="run/executable/jar" \
--module=ModuleName/PackageName.Main
在我的 main 方法中,我调用了java.lang.module.ModuleReader
,特别是它的list()方法,它允许我遍历我的模块及其内容。
如果我获取 jar 文件并尝试运行它,我就可以看到 my 的内容ResourceParentFolder
,但调用仅在我仅运行编译的代码时list()
返回文件。.class
这是因为我的模块配置错误吗?或者这只是不受支持的功能?
再次,ModuleReader.list()
当作为 jar 运行时,返回源代码和资源文件夹内容的递归列表,但它仅在作为编译代码运行时返回源代码。如何让编译后的代码也填充ModuleReader.list()
?或者这只是不支持的功能,除非它在罐子或其他东西中?
需要明确的是,我很清楚有一百万种和其他一种获取资源的方法。但我想知道是否可以按照我上面要求的方式做到这一点。如果不是,那又是为什么呢?
编辑——详细说明我的一些失败的尝试。
我尝试将src/main/resources
目录复制到classes
模块的位置,然后将其变成 jar 。不幸的是,它什么也没捡到。
我也尝试这样做--patch-modules
,但也失败了,但出现错误。
error: no source files
这是我使用的命令。
javac --patch-module ModuleName=src/main/resources
您尝试添加
src/main/resources
到模块路径将无法按预期工作。简单地将目录添加到模块路径并不会使它们的内容成为模块的一部分。您需要:将类和资源放在同一位置,无论是目录还是 JAR 文件。这使得资源成为模块的一部分。请注意,这就是您的 JAR 文件按预期工作的原因,因为您已将类和资源打包在同一个 JAR 文件中。
这种方法本质上就是“应该如何做”。
--patch-module
在运行时使用。请注意,此方法不需要将资源文件移动到任何地方。如果您尝试使用
opens
纯资源包,您还可以在编译时使用此参数;否则,会发出警告,指出该包不存在。opens
不过,如果我没记错的话,在这种情况下(包本质上不是模块的一部分),即使有参数,您也会在运行时收到错误--patch-module
。尽管如此,我确实建议对重要的 Java 项目使用构建工具(例如 Maven、Gradle 等)。他们通常会为您处理所有这些事情。
例子
这是上面讨论的两种方法的示例。请注意,所有命令都是使用 PowerShell Core 7.2.13 和 Java 20.0.1 在 Windows 10 上的项目目录中执行的。
虽然下面的输出列出了资源目录以及实际资源,但不能保证这一点。事实上,如果我没有记错的话,当模块打包在运行时映像中(通过 /
jlink
)时,这些相同的目录将不会列出jpackage
。源代码
两种方法的源代码是相同的。
模块信息
样本.Main
目录结构
注意我
app
在下面添加了一个“模块目录”,src/main/resources
只是为了镜像下面所做的事情(如果您想使用and withsrc/main/java
,则需要它)。这不是必需的,尽管没有它需要稍微更改下面使用的命令(只需更改路径)。--module-source-path
--module
javac
方法 1 - 合并类和资源
命令
输出
如您所见,资源
foo/res.txt
(甚至目录foo/
)已列出。目录结构(运行命令后)
方法 2 - 使用
--patch-module
命令
输出
同样,您可以看到列出了资源
foo/res.txt
(和目录)。foo/
目录结构(运行命令后)