模块化Java程序运行时ModuleReader无法遍历资源,Jar包运行正常
问题:ModuleReader.list()在直接运行编译代码时无法获取资源文件
项目结构
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
打包为模块化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
核心疑问
在主方法中调用java.lang.module.ModuleReader的list()方法遍历模块内容:
- 运行Jar包时能获取
ResourceParentFolder下的所有资源 - 直接运行编译后的代码时,仅返回
.class文件
想明确这是模块配置错误,还是ModuleReader.list()仅支持Jar包?已知其他资源获取方式可行,但需了解此方式是否可行,若不可行请说明原因。
已尝试的失败方案
- 复制
src/main/resources到classes目录,未生效; - 使用命令
javac --patch-module ModuleName=src/main/resources,报错:
error: no source files
解答
原因分析
ModuleReader.list()的行为和模块的封装形式直接相关:
- Jar包形式:打包时你把
classes/ModuleName的类文件和src/main/resources的资源文件合并到了同一个Jar中,此时整个Jar内的所有文件都属于ModuleName模块的一部分,list()自然能遍历到所有内容。 - 松散目录结构:你把
classes(存类文件)和src/main/resources(存资源)同时加到--module-path中,Java模块系统会将它们视为两个独立的模块单元——classes下的是ModuleName模块,而src/main/resources会被识别为一个无模块描述符的自动模块,两者完全独立,因此ModuleReader只能读取到ModuleName模块本身的.class文件。
可行解决方案
要让松散目录结构下的ModuleReader.list()能读取到资源,需要让资源文件成为ModuleName模块的一部分,有两种方式:
方案1:编译时将资源复制到模块目录
把src/main/resources下的所有内容直接复制到classes/ModuleName目录下(注意不是复制整个resources目录),让资源和类文件处于同一模块目录中。比如执行:
cp -r src/main/resources/* classes/ModuleName/
之后再运行原Java命令,ModuleReader.list()就能遍历到资源文件。
方案2:运行时用--patch-module挂载资源目录
修改Java运行命令,用--patch-module将src/main/resources的内容“补丁”到ModuleName模块中,命令如下:
java \ --module-path="classes" \ --patch-module ModuleName=src/main/resources \ --module=ModuleName/PackageName.Main
--patch-module的作用是将指定路径下的内容合并到目标模块中,此时ModuleReader会把这些资源视为ModuleName模块的一部分,就能遍历到。
关于之前失败尝试的说明
- 复制整个
src/main/resources到classes目录:资源被放到了classes/resources下,而非classes/ModuleName,不属于ModuleName模块的内容,因此无效。 - 单独执行
javac --patch-module ModuleName=src/main/resources:javac需要编译源文件,你只指定了--patch-module但没有传入任何要编译的文件,所以报错error: no source files。正确用法是把--patch-module加到原编译命令中,用于编译时补全模块内容,但对于资源文件来说,运行时补丁更直接。
内容的提问来源于stack exchange,提问作者davidalayachew
相关产品推荐
相关产品推荐

