Куда идут файлы ресурсов в проекте Gradle, который строит модуль Java 9?
начиная с IDEA 2018.2.1, IDE запускает пакеты с подсветкой ошибок " не
в графе модуля " из зависимостей, которые были модулированы. Я добавил module-info.java
файл в мой проект и добавил
реквизит requires
заявления, но теперь у меня проблемы с доступом
файлы ресурсов в моем .
(полный пример см. В разделе этот проект GitHub.)
когда я использовал ./gradlew run
или ./gradlew installDist
+ в результате
сценарий оболочки, я смог прочитайте файлы ресурсов, но когда я запустил
app из IDE, я не был.
я подал вопрос
с JetBrains, и я узнал, что идея заключалась в использовании модуля
path, в то время как Gradle, по умолчанию, использовал classpath. Путем добавления
следующий блок для my build.gradle
, я смог получить Gradle
к и ... невозможно прочитать файлы ресурсов.
run {
inputs.property("moduleName", moduleName)
doFirst {
jvmArgs = [
'--module-path', classpath.asPath,
'--module', "$moduleName/$mainClassName"
]
classpath = files()
}
}
пробовал export
- ing каталог ресурсов, который меня интересовал как
"пакет", и во время компиляции получил сбой сборки с:
ошибка: пакет пуст или не существует: mydir
используя opens
вместо exports
получил ту же ошибку, хотя понижен
на предупреждение.
я даже попытался передвинуть ресурс src/main/java
,
но это вызвало те же ошибки / предупреждения, а также привело к
ресурсы не копируются в .
где ресурсы должен идти в Java 9, и как мне получить к ним доступ?
Примечание: я значительно отредактировал этот вопрос после продолжения
исследуйте проблему. В первоначальном вопросе я также пытался
выясните, как перечислить файлы в каталоге ресурсов, но в
в ходе расследования я выяснил, что это был отвлекающий маневр. --
во-первых, потому что чтение каталогов ресурсов работает только тогда, когда
ресурс считывается из file:///
URL (и, возможно, даже не затем),
и во-вторых, потому что простые файлы тоже не работали, так что ясно, что
проблема была с файлами ресурсов в целом, а не конкретно с
справочники.
устранение:
Per Слоу-х, я добавил следующее в 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, который делает run
задача выполнить против банки, попытка прочитать каталог ресурсов InputStream
в задаче запуска сейчас выдает IOException
вместо предоставления списка файлов. (Против банки он просто получает пустой InputStream
.)
1 ответов
в вашей щедрости вы запрашиваете официальную документацию о "правильном пути" для обработки ресурсов с помощью модулей Gradle и Jigsaw. Ответ, насколько я знаю, заключается в том, что нет "правильного пути", потому что Gradle еще (по состоянию на 4.10-rc-2) не имеет первоклассной поддержки модулей Jigsaw. Ближайший вы получите это Построение Модулей Java 9 документ.
, вы отметить речь идет о доступе к ресурсам из модуля (т. е. не из внешних модулей). Это не должно быть слишком сложно исправить с помощью простогоbuild.gradle
конфигурации.
по умолчанию Gradle разделяет выходные каталоги для классов и ресурсов. Это выглядит примерно так:
build/
|--classes/
|--resources/
при использовании run
задание classpath
значение sourceSets.main.runtimeClasspath
. Это значение включает оба каталога, и это работает из-за того, как работает путь к классам. Вы можете думать об этом, как о classpath-это всего лишь один гигантский модуль.
это не работает, однако, при использовании modulepath, потому что технически файлы внутри resources
не принадлежат к модулю, который находится внутри classes
. Это означает, что нам нужен способ сообщить системе модулей включить resources
внутри модуля внутри classes
. К счастью, есть --patch-module
. Этот параметр имеет следующий формат:
--patch-module <module>=<path>
здесь <path>
is <file>(;<file>)*
(Я предполагаю, что ;
разделитель платформы зависимый.)
чтобы позволить вашему модулю получить доступ к собственным ресурсам, просто настройте свой run
задача так:
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? Это становится немного более запутанным.
если вы хотите разрешить внешним модулям доступ к ресурсам модуль должен opens
пакет ресурса по крайней мере для модуля чтения (это относится только к капсулированные ресурсы). Однако, как вы обнаружили, это приводит к предупреждениям о компиляции и ошибкам во время выполнения.
- предупреждение компиляции, потому что вы пытаетесь
opens
пакет, который не существует в соответствии с системой модуля.- это следует ожидать, так как каталог ресурсов не включен, когда компиляция по умолчанию (при условии пакета только для ресурсов).
- ошибка выполнения заключается в том, что система модулей не может найти пакет, который вы объявили упоминалось выше. Я предполагаю, что система модуля делает некоторую проверку целостности перед применением заплатка.
Примечание: под "только для ресурсов" я имею в виду пакеты, у которых нет .java
/.class
файлы.
чтобы исправить предупреждение компиляции, вам просто нужно использовать --patch-module
снова внутри compileJava
задач. На этот раз вы будете использовать исходные каталоги ресурсов, а не выходной каталог.
compileJava {
inputs.property('moduleName', moduleName)
doFirst {
options.compilerArgs = [
'--module-path', classpath.asPath,
'--patch-module', "$moduleName=" + files(sourceSets.main.resources.srcDirs).asPath,
'--module-version', "$version"
]
}
}
ошибки времени выполнения есть несколько вариантов. Первый вариант - "объединить" выходные данные ресурсов каталог с выходным каталогом для классов. Используя эту опцию, вы можете удалить --patch-module
С run
конфигурация задачи.
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
}
второй вариант-настроить run
задача выполнить файл JAR, а не разнесенный каталог(ы). Это работает, потому что, как и первый вариант, он объединяет классы и ресурсы в одном месте, и поэтому ресурсы являются частью модуля.
run {
dependsOn += jar
inputs.property('moduleName', moduleName)
doFirst {
// add JAR file and runtime classpath. The runtime classpath includes the output of the source set
// so we remove that as well (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 {
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
. Кроме того, если run
задача настроена на выполнение банки, которую вы можете изменить:
'--module', "$moduleName/$mainClassName"
в:
'--module', "$moduleName"
P. S. Если есть лучший способ сделать пожалуйста, дайте мне знать.