Edit:
Я проанализировал данные ответы. В частности, я проверил гипотезу Тилла Бриччи, которая, кажется, верна, но открывает больше вопросов.
Я добавил этот анализ в конец вопроса после следующего большого разделителя:
"----------- Анализ ответа Тилла Бриччи ----------"
Каким-то образом он компилируется и работает в IJ, но mvn clean install
не может скомпилировать тест
Объяснение 2 модулей и что не получается
У меня есть проект Java 9 Maven с 2 модулями: apimod
и clientmod
.
Модуль clientmod
зависит от модуля apimod
(эти модули являются как модулями Maven, так и модулями Java 9).
Кроме того, я хочу, чтобы модуль clientmod
мог повторно использовать не только производственный код из apimod
, но и тестовый код.
Это общий шаблон, который я много раз использовал с Java 8.
С Java 9 (то же самое с Java 10) он также работает нормально, пока я не объявляю module-info.java
(то есть, пока я не работаю с модульной системой).
Но, как только я это сделаю, включение тестовой зависимости, похоже, отключит производственную зависимость: api.Base
(класс src/main
модуля apimod
) больше не виден из client.test.DerivedTest
(класс src/test
) модуля clientmod
). Тест больше не компилируется.
Это ошибка в Maven или в Java 9? Это с самыми последними выпусками: Java 9.0.4 (то же самое с Java 10), Maven 3.5.3, maven-compiler-plugin 3.7.0
Мой анализ пока
код
Исходный код:
git clone https://github.com/vandekeiser/wires.git
Я "дихотомизировал" проблему с ошибочным тестом в ветке:
git checkout MINIMIZE_ISSUE
`mvn clean install`
-> BUILD FAIL (ошибка компиляции в тесте clientmod
)
Зависимость Maven-scoped
Я хочу, чтобы модуль clientmod
мог повторно использовать не только рабочий код из apimod
, но и тестовый код. С Maven вы делаете это так (clientmod/pom.xml
):
<dependency>
<groupId>fr.cla</groupId>
<artifactId>apimod</artifactId>
<version>${project.version}</version>
<classifier>tests</classifier>
<scope>test</scope>
</dependency>
Java 9 модулей
module apimod {
exports api;
}
module clientmod {
requires apimod;
}
Ошибка при попытке включить обе системы модулей
В случае Java 9, если я объявляю и зависимость в тестовой области, и модули Java 9, тест больше не компилируется (вывод mvn clean install
):
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.7.0:testCompile (default-testCompile) on project clientmod: Compilation failure
[ERROR] /G:/projets/wires/wires/wires/clientmod/src/test/java/client/test/DerivedTest.java:[8,22] cannot access api.Base
[ERROR] class file for api.Base not found
Воспроизведение проблемы с javac: ошибка в обновлении модуля?
Как будто включение тестовой зависимости (src/test
) отключает производственную зависимость (src/main
). Я знаю, что в этом сценарии Maven должен использовать флаг javac --patch-module
.
Так что я воспроизвел проблему, используя просто javac (используя вывод отладки mvn -X
):
Же сборник, пропуская Maven:
javac "G:\projets\wires\wires\wires\clientmod\src\test\java\client\test\DerivedTest.java" \
-d "G:\projets\wires\wires\wires\clientmod\target\test-classes" \
-classpath "G:\projets\wires\wires\wires\clientmod\target\test-classes;" \
--module-path "G:\projets\wires\wires\wires\apimod\target\apimod-1.0-SNAPSHOT-tests.jar;G:\projets\wires\wires\wires\clientmod\target\classes;G:\projets\wires\wires\wires\apimod\target\apimod-1.0-SNAPSHOT.jar;" \
-sourcepath "G:\projets\wires\wires\wires\clientmod\src\test\java;" \
--release 9 \
-Xlint:all \
--patch-module clientmod="G:\projets\wires\wires\wires\clientmod\target\classes;G:\projets\wires\wires\wires\clientmod\src\test\java;"
Та же ошибка компиляции:
G:\projets\wires\wires\wires\clientmod\src\test\java\client test\DerivedTest.java:8: error: cannot access Base
new Derived().equals(null); ^
class file for api.Base not found
1 error
Я пытался использовать флаги javac, которые должны отключить систему модулей, но, похоже, их нет в моей 64-битной Windows Oracle JVM? (Java HotSpot (TM) 64-разрядная серверная виртуальная машина (сборка 9.0.4 + 11, смешанный режим):
javac --illegal-access=warn
javac: invalid flag: --permit-illegal-access
javac --permit-illegal-access
javac: invalid flag: --illegal-access=warn
Добавление (логически ненужное, выполненное в отчаянии) экспорта или чтения также ничего не меняет:
--add-reads apimod=ALL-UNNAMED \
--add-reads clientmod=ALL-UNNAMED \
--add-exports apimod/api=ALL-UNNAMED \
--add-exports clientmod/client=ALL-UNNAMED \
Вывод mvn -version:
Apache Maven 3.5.3 (3383c37e1f9e9b3bc3df5050c29c8aff9f295297; 2018-02-24T20:49:05+01:00)
Maven home: G:\software\apache-maven-3.5.3
Java version: 9.0.4, vendor: Oracle Corporation
Java home: C:\Program Files\Java\jdk-9.0.4
Default locale: fr_FR, platform encoding: Cp1252
OS name: "windows 7", version: "6.1", arch: "amd64", family: "windows"
Анализ ответа Тилла Бриччи
Спасибо за ваш подробный ответ. По сути, "похоже, maven еще не поддерживает этот вариант использования"
-> Итак, давайте попробуем воспроизвести проблему без Maven. Я создал ветку TRY_ADAPT_khmarbaise-MINIMIZE_ISSUE
для этих испытаний (извините за непонятное название ветки).
Адаптация моей прежней командной строки, которая регистрируется maven, то есть:
javac "G:\projets\wires\wires\wires\clientmod\src\test\java\client\test\DerivedTest.java"
-d "G:\projets\wires\wires\wires\clientmod\target\test-classes"
-classpath "G:\projets\wires\wires\wires\clientmod\target\test-classes;"
--module-path "G:\projets\wires\wires\wires\apimod\target\apimod-1.0-SNAPSHOT-tests.jar;G:\projets\wires\wires\wires\clientmod\target\classes;G:\projets\wires\wires\wires\apimod\target\apimod-1.0-SNAPSHOT.jar;"
-sourcepath "G:\projets\wires\wires\wires\clientmod\src\test\java;"
--release 9
-Xlint:all
--patch-module clientmod="G:\projets\wires\wires\wires\clientmod\target\classes;G:\projets\wires\wires\wires\clientmod\src\test\java;"
--add-reads apimod=ALL-UNNAMED
--add-reads clientmod=ALL-UNNAMED
--add-exports apimod/api=ALL-UNNAMED
--add-exports clientmod/client=ALL-UNNAMED
--add-modules apimod
Я удаляю G:\projets\wires\wires\wires\apimod\target\apimod-1.0-SNAPSHOT-tests.jar;
из --module-path
Я добавляю то же самое к --patch-module clientmod
, давая мне:
javac "G:\projets\wires\wires\wires\clientmod\src\test\java\client\test\DerivedTest.java" \
-d "G:\projets\wires\wires\wires\clientmod\target\test-classes" \
-classpath "G:\projets\wires\wires\wires\clientmod\target\test-classes;" \
--module-path "G:\projets\wires\wires\wires\clientmod\target\classes;G:\projets\wires\wires\wires\apimod\target\apimod-1.0-SNAPSHOT.jar;" \
-sourcepath "G:\projets\wires\wires\wires\clientmod\src\test\java;" \
--release 9 \
-Xlint:all \
--patch-module clientmod="G:\projets\wires\wires\wires\clientmod\target\classes;G:\projets\wires\wires\wires\clientmod\src\test\java;G:\projets\wires\wires\wires\apimod\target\apimod-1.0-SNAPSHOT-tests.jar;" \
--add-reads apimod=ALL-UNNAMED \
--add-reads clientmod=ALL-UNNAMED \
--add-exports apimod/api=ALL-UNNAMED \
--add-exports clientmod/client=ALL-UNNAMED \
--add-modules apimod
-> ОК, теперь он компилируется! Таким образом, ваша гипотеза о том, что maven-compiler-plugin или maven не поддерживает это, все же кажется проверенной.
Но Я думаю, что он должен поддерживаться в используемой мной версии, которая является последней. Интересно, с чего начать проверять ..
В любом случае, я пытался настроить maven-compiler-plugin явно, но безрезультатно.
Общая структура, которую я попробовал (maven-compiler-plugin.version = 3.7.0):
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<release>${java.version}</release>
<compilerArgs>
[...]
</compilerArgs>
</configuration>
</plugin>
Я попробовал следующее compilerArgs
(соответствующие ошибки mvn clean install в комментариях xml):
1
<!--1. Syntaxically OK, but:-->
<!--[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.7.0:compile (default-compile) on project apimod: Compilation failure: Compilation failure:-->
<!--[ERROR] /G:/projets/wires/wires/wires/apimod/src/main/java/api/Base.java:[1,1]-->
<!--file should be on source path, or on patch path for module-->
<!--[ERROR] /G:/projets/wires/wires/wires/apimod/src/main/java/module-info.java:[1,1]-->
<!--file should be on source path, or on patch path for module-->
<compilerArgs>
<arg>--class-path=/G/projets/wires/wires/wires/clientmod/target/test-classes;</arg>
<arg>
--module-path=/G/projets/wires/wires/wires/clientmod/target/classes;/G/projets/wires/wires/wires/apimod/target/apimod-1.0-SNAPSHOT.jar;
</arg>
<arg>--source-path=/G/projets/wires/wires/wires/clientmod/src/test/java;</arg>
<arg>-Xlint:all</arg>
<arg>
--patch-module=clientmod=/G/projets/wires/wires/wires/clientmod/target/classes;/G/projets/wires/wires/wires/clientmod/src/test/java;/G/projets/wires/wires/wires/apimod/target/apimod-1.0-SNAPSHOT-tests.jar;
</arg>
<arg>--add-reads=apimod=ALL-UNNAMED</arg>
<arg>--add-reads=clientmod=ALL-UNNAMED</arg>
<arg>--add-exports=apimod/api=ALL-UNNAMED</arg>
<arg>--add-exports=clientmod/client=ALL-UNNAMED</arg>
<arg>--add-modules=apimod</arg>
</compilerArgs>
2
<!--2.-->
<!--[ERROR] Please refer to dump files (if any exist) [date]-jvmRun[N].dump, [date].dumpstream and [date]-jvmRun[N].dumpstream.-->
<!--[ERROR] There was an error in the forked process-->
<!--[ERROR] api/foo/BaseTest (wrong name: apimod/api/foo/BaseTest)-->
<!--[ERROR] org.apache.maven.surefire.booter.SurefireBooterForkException: There was an error in the forked process-->
<!--[ERROR] api/foo/BaseTest (wrong name: apimod/api/foo/BaseTest)-->
<!--[ERROR] at org.apache.maven.plugin.surefire.booterclient.ForkStarter.fork(ForkStarter.java:673)-->
<compilerArgs>
<arg>--module-source-path=./*/src/main/java;./*/src/test/java/;</arg>
<arg>
--source-path=/G/projets/wires/wires/wires/apimod/src/main/java;/G/projets/wires/wires/wires/apimod/src/test/java;/G/projets/wires/wires/wires/clientmod/src/test/java;/G/projets/wires/wires/wires/clientmod/src/main/java;
</arg>
<arg>-Xlint:all</arg>
<arg>
--patch-module=clientmod=/G/projets/wires/wires/wires/clientmod/target/classes;/G/projets/wires/wires/wires/clientmod/src/test/java;/G/projets/wires/wires/wires/apimod/target/apimod-1.0-SNAPSHOT.jar;/G/projets/wires/wires/wires/apimod/target/apimod-1.0-SNAPSHOT-tests.jar;
</arg>
<arg>--add-reads=apimod=ALL-UNNAMED</arg>
<arg>--add-reads=clientmod=ALL-UNNAMED</arg>
<arg>--add-exports=apimod/api=ALL-UNNAMED</arg>
<arg>--add-exports=clientmod/client=ALL-UNNAMED</arg>
<arg>--add-modules=apimod</arg>
</compilerArgs>