编辑:
我分析了给出的答案。特别是我测试了 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
对于这些试验(抱歉分支名称令人困惑)。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>
最佳答案
看起来 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
的一部分
关于java - 无法使 Maven 测试范围的依赖项与 Java 9(或 10)模块一起使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50122838/