编辑:我分析了给定的答案。特别是我测试了 Till Brychcy 的假设,该假设似乎成立,但提出了更多问题。我将该分析添加到问题的末尾,在以下大分隔符之后:“------------Till Brychcy 的答案分析----------”
它以某种方式在 IJ 中编译和运行,但mvn clean install
无法编译测试
2个模块的解释,以及失败的原因
我有一个带有 2 个模块的 java 9 maven 项目: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 测试范围的依赖
我希望模块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 位服务器 VM(内部版本 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"
分析 Till Brychcy 的答案
感谢您的详细回答,本质上是“看起来 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
(对应的 xml 注释中的 mvn clean install 错误):
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>