资源文件放在构建Java 9模块的Gradle项目中的哪个位置?
作者:互联网
从IDEA 2018.2.1开始,IDE启动错误突出显示包“不是
在模块图中“来自已经模块化的依赖项.我在我的项目中添加了一个module-info.java文件并添加了
必需要求声明,但我现在无法访问
我的src / main / resources目录中的资源文件.
(有关完整示例,请参阅this GitHub project.)
当我使用./gradlew run或./gradlew installDist时产生的结果
包装脚本,我能够读取资源文件,但当我运行我的
来自IDE的app,我不是.
我提交了issue
与JetBrains一起,我学到的是IDEA正在使用该模块
path,而Gradle默认使用classpath.通过增加
以下块到我的build.gradle,我得到了Gradle
还…无法读取任何资源文件.
run {
inputs.property("moduleName", moduleName)
doFirst {
jvmArgs = [
'--module-path', classpath.asPath,
'--module', "$moduleName/$mainClassName"
]
classpath = files()
}
}
我尝试将我感兴趣的资源目录导出为
“package”,并在编译时遇到构建失败:
error: package is empty or does not exist: mydir
虽然降级了,但使用opens而不是export会出现同样的错误
发出警告
我甚至尝试在src / main / java下移动mydir资源目录,
但这产生了相同的错误/警告,并导致了
资源未复制到构建目录.
应该在Java 9中使用哪些资源,以及如何访问它们?
注意:继续之后,我已经大大编辑了这个问题
研究这个问题.在最初的问题中,我也在尝试
弄清楚如何列出资源目录中的文件,但是在
调查过程我确定这是一个红鲱鱼 –
首先,因为只读取资源目录时才有效
正在从file:/// URL读取资源(甚至可能不会)
第二,因为普通文件也没有工作,所以很清楚
问题是一般的资源文件,而不是具体的
目录.
解:
根据Slaw’s answer,我在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()
}
}
旁注:有趣的是,如果我不继续添加Slaw的代码,使运行任务针对JAR执行,则尝试在运行任务中读取资源目录InputStream,而不是提供文件列表. (对于JAR,它只是获取一个空的InputStream.)
解决方法:
从Gradle’s epic关于Jigsaw支持我已经了解了一个可以简化下面描述的过程的插件:gradle-modules-plugin.史诗还提到了其他插件,如chainsaw(这是实验拼图插件的一个分支).不幸的是,我还没有尝试过任何一个,所以我不能评论他们如何处理资源,如果有的话.
在您的赏金中,您需要有关使用Gradle和Jigsaw模块处理资源的“正确方法”的官方文档.据我所知,答案是没有“正确的方法”,因为Gradle仍然(从4.10-rc-2开始)没有对Jigsaw模块的一流支持.你得到的最接近的是Building Java 9 Modules文件.
但是,您mention这是关于从模块内(即不是从外部模块)访问资源.使用简单的build.gradle配置解决这个问题应该不会太难.
默认情况下,Gradle将类和资源的输出目录分开.它看起来像这样:
build/
|--classes/
|--resources/
使用run任务时,classpath是sourceSets.main.runtimeClasspath的值.此值包括两个目录,这是因为类路径的工作方式.您可以将其视为类路径只是一个巨大的模块.
但是,这在使用模块路径时不起作用,因为从技术上讲,资源内的文件不属于类内部的模块.我们需要一种方法来告诉模块系统资源是模块的一部分.幸运的是,有--patch-module
.这个选项将(引自java –help-extra):
override or augment a module with classes and resources in JAR files or directories.
并具有以下格式(我假设;分隔符取决于平台):
--patch-module <module>=<file>(;<file>)*
要允许您的模块访问它自己的资源,只需配置您的运行任务,如下所示:
run {
input.property('moduleName', moduleName)
doFirst {
jvmArgs = [
'--module-path', classpath.asPath,
'--patch-module', "$moduleName=" + files(sourceSets.main.output.resourcesDir).asPath,
'--module', "$moduleName/$mainClassName"
]
classpath = files()
}
}
这就是我一直在做的事情,到目前为止它已经很好了.
但是,当从Gradle启动应用程序时,如何允许外部模块从模块访问资源?这需要更多参与.
如果要允许外部模块访问资源,则模块必须打开(参见Eng.Fouad’s answer)资源的包至少读取模块(这仅适用于encapsulated资源).但是,正如您所发现的,这会导致编译警告和运行时错误.
>编译警告是因为您尝试打开根据模块系统不存在的包.
>这是预期的,因为默认情况下编译时不包括资源目录(假设只有资源的包).
>运行时错误是因为模块系统找不到您声明为open指令的包.
>再次,假设只有资源的包.
>即使使用上面提到的–patch-module选项,也会发生这种情况.我想模块系统在应用补丁之前会进行一些完整性检查.
注意:“仅限资源”是指没有.java / .class文件的软件包.
要修复编译警告,您只需在compileJava任务中再次使用–patch-module.这次你将使用资源的源目录而不是输出目录.
compileJava {
inputs.property('moduleName', moduleName)
doFirst {
options.compilerArgs = [
'--module-path', classpath.asPath,
'--patch-module', "$moduleName=" + files(sourceSets.main.resources.srcDirs).asPath,
'--module-version', "$version"
]
}
}
对于运行时错误,有几个选项.第一个选项是将资源输出目录与类的输出目录“合并”.
sourceSets {
main.output.resourcesDir = main.java.outputDir
}
jar {
// I've had bad experiences when "merging" output directories
// where the jar task ends up creating duplicate entries in the JAR.
// Use this option to combat that.
duplicateStrategy = DuplicatesStrategy.EXCLUDE
}
第二个选项是配置运行任务以执行JAR文件而不是展开的目录.这是有效的,因为像第一个选项一样,它将类和资源组合到同一个地方,因此资源是模块的一部分.
run {
dependsOn += jar
inputs.property('moduleName', moduleName)
doFirst {
// add JAR file and runtime classpath. The runtime classpath includes the output of the main source set
// so we remove that to avoid having two of the same module on the modulepath
def modulepath = files(jar.archivePath) + (sourceSets.main.runtimeClasspath - sourceSets.main.output)
jvmArgs = [
'--module-path', modulepath.asPath,
'--module', "$moduleName/$mainClassName"
]
classpath = files()
}
}
可以使用这两个选项代替在运行任务中使用–patch-module(在本答案的第一部分中进行了解释).
作为奖励,这就是我将-main-class属性添加到模块化JAR中的方式:
jar {
inputs.property('mainClassName', mainClassName)
doLast {
exec {
executable = 'jar'
args = [
'--update', '--file', "$archivePath",
'--main-class', "$mainClassName"
]
}
}
}
这允许您使用java -m module.name而不是java -m module.name/some.package.Main.此外,如果运行任务配置为执行JAR,您可以更改:
'--module', "$moduleName/$mainClassName"
至:
'--module', "$moduleName"
附:如果有更好的方法,请告诉我.
标签:java-module,java,gradle,embedded-resource,java-9 来源: https://codeday.me/bug/20190926/1818643.html