Невозможно заставить тестируемые зависимости Maven работать с модулями Java 9 (или 10) - PullRequest
0 голосов
/ 01 мая 2018

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 для этих испытаний (извините за непонятное название ветки).

  1. Адаптация моей прежней командной строки, которая регистрируется 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
    
  2. Я удаляю G:\projets\wires\wires\wires\apimod\target\apimod-1.0-SNAPSHOT-tests.jar; из --module-path

  3. Я добавляю то же самое к --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>    

Ответы [ 2 ]

0 голосов
/ 18 июля 2018

Работает сейчас! Там все объяснено: https://issues.apache.org/jira/browse/MCOMPILER-348

Проблема заключалась в столкновении имен: изменение имени модулей maven на что-то отличное от исправленных java-модулей, в ветви уменьшения проблем и в ветви main-dev.

У меня все еще есть предупреждение (см. Ссылку), сейчас я его игнорирую, но оно должно пройти.

----------- Копирование содержимого ссылки в случае исчезновения JIRA -----------

Роберт Шольте : Я предполагаю, что файл apimod-1.0-SNAPSHOT-tests.jar должен был находиться в пути к классам, а не в модуле. Единственная причина, по которой я могу думать о том, что он был добавлен в путь к модулю, - это когда его автоматическое имя модуля также называется apimod. Изменение имени на то, что не вступает в конфликт с автоматическим именем по модулю, устраняет проблему (например, info.example.apimod) В общем, пожалуйста, выберите более уникальное имя модуля, оно должно быть глобально уникальным (точно так же, как классы на пути к классам). Добавьте reverseDNS или общий пакет. Постоянная ссылка Редактировать Удалить

Me : Да, это было то, что, спасибо большое! Я точно подумал, что это ошибка (но, может быть, есть еще небольшая ошибка? Я еще не посмотрел на нее больше, но все еще есть предупреждение javac - см. Конец этот комментарий).

Это исправило ветку дихотомии и основную ветку: -В ветке дихотомии, я добавил префикс для Java-модулей -После того как я вернулся в основную ветку, я переименовал модули Maven в wires.core -> wire-core и так далее, а java-модули в общий корневой пакет, также избегая конфликта имен

Если выразить это словами "Java puzzlers", возможно, урок здесь двоякий: Для пользователей API (Maven): следуйте соглашениям об именах: я не должен был называть модули Maven символом '.' разделитель. Я бы избежал столкновения имен, не думая об этом .. -Для разработчиков API: возможно, запишите значимое сообщение, если вы сможете обнаружить это столкновение, потому что трудно увидеть, когда оно произойдет

Наконец, я все еще получаю предупреждение javac. Поэтому сейчас я должен игнорировать предупреждение об экспорте.

Я еще не исследовал это, но здесь идет:

[WARNING] COMPILATION WARNING :
[INFO] -------------------------------------------------------------
[WARNING] /G:/projets/wires/wires/wires/wires-core/src/test/java/fr/cla/wires/core/MavenVsJavaModulesReproduceTest.java:[9,54] class fr.cla.wires.support.oo.ddd.AbstractValueObjectTest in module  is not exported
[INFO] 1 warning
[INFO] -------------------------------------------------------------
[INFO] -------------------------------------------------------------
[ERROR] COMPILATION ERROR :
[INFO] -------------------------------------------------------------
[ERROR] /G:/projets/wires/wires/wires/wires-core/src/test/java/fr/cla/wires/core/MavenVsJavaModulesReproduceTest.java: warnings found and -Werror specified
[INFO] 1 error

Чтобы воспроизвести его, извлеките тег WARN_IF_UNCOMMENT в главной ветви (https://github.com/vandekeiser/wires.git) и удалите исключение экспорта в: -Xlint: все, -serial, -exports

Я не могу (и не должен) добавлять экспорт fr.cla.wires.support.oo.ddd; в module-info.java, потому что это относится к пакету, который находится в src / test

Вот где он сейчас

0 голосов
/ 02 мая 2018

Похоже, maven еще не поддерживает этот вариант использования.

Проблема в том, что apimod-1.0-SNAPSHOT-tests.jar рассматривается как автоматический модуль, и его автоматическое имя модуля (полученное из имени файла) равно "apimod", поэтому фактический модуль apimod в apimod-1.0-SNAPSHOT.jar (который появится позже путь модуля) игнорируется.

Maven должен обнаружить, что apimod-1.0-SNAPSHOT-tests.jar принадлежит apimod и использовать --patch-module apimod=G:\projets\wires\wires\wires\apimod\target\apimod-1.0-SNAPSHOT-tests.jar вместо того, чтобы сделать его частью --module-path

...