Dav*_*les 15 java embedded-resource gradle java-9 java-module
从IDEA 2018.2.1开始,IDE从模块化的依赖项开始错误突出显示"不在模块图"中的包.我module-info.java在项目中添加了一个文件并添加了必需的requires语句,但我现在无法访问src/main/resources目录中的资源文件.
(有关完整示例,请参阅此GitHub项目.)
当我使用./gradlew run或./gradlew installDist+生成的包装器脚本时,我能够读取资源文件,但是当我从IDE运行我的应用程序时,我不是.
我向
JetBrains 提出了一个问题,我学到的是IDEA正在使用模块路径,而Gradle默认使用类路径.通过向我添加以下块build.gradle,我能够让Gradle 也 ...无法读取任何资源文件.
run {
inputs.property("moduleName", moduleName)
doFirst {
jvmArgs = [
'--module-path', classpath.asPath,
'--module', "$moduleName/$mainClassName"
]
classpath = files()
}
}
Run Code Online (Sandbox Code Playgroud)
我尝试export将我感兴趣的资源目录作为"包",并在编译时遇到构建失败:
错误:包是空的或不存在:mydir
使用opens而不是exports获得相同的错误,但降级为警告.
我甚至尝试移动mydir资源目录src/main/java,但是这产生了相同的错误/警告,并且还导致资源没有被复制到build目录中.
应该在Java 9中使用哪些资源,以及如何访问它们?
注意:在继续研究问题之后,我已经相当大地编辑了这个问题.在最初的问题中,我还试图弄清楚如何在资源目录中列出文件,但在调查过程中我确定这是一个红色的鲱鱼 - 首先,因为阅读资源目录只有在资源是从file:///URL 读取(也许甚至不是),第二,因为普通文件也没有工作,所以很明显问题是资源文件一般而不是专门用于目录.
解:
按照Slaw的回答,我将以下内容添加到build.gradle:
// at compile time, put resources in same directories as classes
sourceSets {
main.output.resourcesDir = main.java.outputDir
}
// at compile time, include resources in module
compileJava {
inputs.property("moduleName", moduleName)
doFirst {
options.compilerArgs = [
'--module-path', classpath.asPath,
'--patch-module', "$moduleName="
+ files(sourceSets.main.resources.srcDirs).asPath,
'--module-version', "$moduleVersion"
]
classpath = files()
}
}
// at run time, make Gradle use the module path
run {
inputs.property("moduleName", moduleName)
doFirst {
jvmArgs = [
'--module-path', classpath.asPath,
'--module', "$moduleName/$mainClassName"
]
classpath = files()
}
}
Run Code Online (Sandbox Code Playgroud)
旁注:有趣的是,如果我不继续添加Slaw的代码使得run任务针对JAR执行,则尝试读取InputStream运行任务中的资源目录现在会抛出IOException而不是提供文件列表.(对JAR来说,它只是一个空洞InputStream.)
Sla*_*law 16
从Gradle关于Jigsaw支持的史诗中我已经了解了一个可以简化下面描述的过程的插件:gradle-modules-plugin.史诗还提到了其他插件,如电锯(这是实验拼图插件的一个分支).不幸的是,我还没有尝试过任何一个,所以我不能评论他们如何处理资源,如果有的话.
在您的赏金中,您需要有关使用Gradle和Jigsaw模块处理资源的"正确方法"的官方文档.据我所知,答案是没有"正确的方法",因为Gradle 仍然(从4.10-rc-2开始)没有对Jigsaw模块的一流支持.最接近的是Building Java 9 Modules文档.
但是,您提到这是关于从模块内访问资源(即不是从外部模块).这不应该太难以通过简单的jlink配置来修复.
默认情况下,Gradle将类和资源的输出目录分开.它看起来像这样:
build/
|--classes/
|--resources/
Run Code Online (Sandbox Code Playgroud)
使用classes任务时module-info.class,值是resources.此值包括两个目录,这是因为类路径的工作方式.您可以将其视为类路径只是一个巨大的模块.
但是,这在使用模块路径时不起作用,因为从技术上讲,里面的文件classes不属于内部的模块opens.我们需要一种方法来告诉模块系统src/main/java是模块的一部分.幸运的是,有src/main/resources.此选项将(引自.java):
使用JAR文件或目录中的类和资源覆盖或扩充模块.
并具有以下格式(我假设.class分隔符取决于平台):
plugins {
id("org.javamodularity.moduleplugin") version "..."
}
Run Code Online (Sandbox Code Playgroud)
要允许您的模块访问它自己的资源,只需配置您的opens任务,如下所示:
plugins {
application
}
group = "..."
version = "..."
java {
sourceCompatibility = JavaVersion.VERSION_13
}
application {
mainClassName = "<module-name>/<mainclass-name>"
}
tasks {
compileJava {
doFirst {
options.compilerArgs = listOf(
"--module-path", classpath.asPath,
"--module-version", "${project.version}"
)
classpath = files()
}
}
named<JavaExec>("run") {
doFirst {
val main by sourceSets
jvmArgs = listOf(
"--module-path", classpath.asPath,
"--patch-module", "<module-name>=${main.output.resourcesDir}",
"--module", application.mainClassName
)
classpath = files()
}
}
}
Run Code Online (Sandbox Code Playgroud)
这就是我一直在做的事情,到目前为止它已经很好了.
但是,当从Gradle启动应用程序时,如何允许外部模块从模块访问资源?这需要更多参与.
当您希望允许外部模块访问资源时,您的模块必须.class(请参阅Eng.Fouad的答案)将资源的包至少读取模块(这仅适用于封装的资源).但是,正如您所发现的,这会导致编译警告和运行时错误.
run根据模块系统不存在的包.
--patch-module指令的包.
java选项,也会发生这种情况.我想模块系统在应用补丁之前会进行一些完整性检查.注意:"仅限资源"是指没有compileTestJava/ testfiles的软件包.
要修复编译警告,您只需compileJava在run任务中再次使用.这次你将使用资源的源目录而不是输出目录.
sourceSets {
main {
output.resourcesDir = java.outputDir
}
}
Run Code Online (Sandbox Code Playgroud)
对于运行时错误,有几个选项.第一个选项是将资源输出目录与类的输出目录"合并".
tasks.compileJava {
doFirst {
val main by sourceSets
options.compilerArgs = listOf(
"--module-path", classpath.asPath,
"--patch-module", "<module-name>=${main.resources.sourceDirectories.asPath}"
"--module-version", "${project.version}"
)
classpath = files()
}
}
Run Code Online (Sandbox Code Playgroud)
第二个选项是将requires任务配置为执行JAR文件而不是展开的目录(ies).这是有效的,因为像第一个选项一样,它将类和资源组合到同一个地方,因此资源是模块的一部分.
build/
|--classes/
|--resources/
Run Code Online (Sandbox Code Playgroud)
可以使用这两个选项代替--add-modules在--add-reads任务中使用(在本答案的第一部分中进行了解释).
作为奖励,这就是我将--add-opens模块化JAR 添加到我的模块中的方法:
plugins {
id("org.javamodularity.moduleplugin") version "..."
}
Run Code Online (Sandbox Code Playgroud)
这允许你使用--module <module-name>而不是--module <module-name>/<mainclass-name>.此外,如果--main-class任务配置为执行JAR,您可以更改:
plugins {
application
}
group = "..."
version = "..."
java {
sourceCompatibility = JavaVersion.VERSION_13
}
application {
mainClassName = "<module-name>/<mainclass-name>"
}
tasks {
compileJava {
doFirst {
options.compilerArgs = listOf(
"--module-path", classpath.asPath,
"--module-version", "${project.version}"
)
classpath = files()
}
}
named<JavaExec>("run") {
doFirst {
val main by sourceSets
jvmArgs = listOf(
"--module-path", classpath.asPath,
"--patch-module", "<module-name>=${main.output.resourcesDir}",
"--module", application.mainClassName
)
classpath = files()
}
}
}
Run Code Online (Sandbox Code Playgroud)
至:
sourceSets {
main {
output.resourcesDir = java.outputDir
}
}
Run Code Online (Sandbox Code Playgroud)
PS如果有更好的方法,请告诉我.
| 归档时间: |
|
| 查看次数: |
1852 次 |
| 最近记录: |