java - 无法使 Maven 测试范围的依赖项与 Java 9(或 10)模块一起使用

标签 java maven java-9 java-10

编辑:
我分析了给出的答案。特别是我测试了 Till Brychcy 的假设,该假设似乎成立,但引发了更多问题。
我将该分析添加到问题的末尾,在以下大分隔符之后:
“-----------分析Till Brychcy的答案---------”

它以某种方式在 IJ 中编译和运行,但是 mvn clean install无法编译测试

2个模块的解释,以及失败的地方

我有一个带有 2 个模块的 java 9 maven 项目:apimodclientmod .
模块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>    
    

    最佳答案

    看起来 maven 还不支持这个用例。

    问题是apimod-1.0-SNAPSHOT-tests.jar被视为自动模块,其自动模块名称(源自文件名)为“apimod”,因此实际模块apimodapimod-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/

    相关文章:

    java - 尝试使用 OnClickListener 时出错

    java - gradle到Maven转换,在依赖项的依赖项版本名称中解析通配符 “+”?

    maven - pom.xml 中 <dependency> 下的 <scope> 是做什么用的?

    java - 如何将模块声明注入(inject) JAR?

    java - 安装 JDK 9 后无法启动 Spring Tool Suite

    java - @JsonFormat 在嵌套对象中不起作用

    java - 在一个项目中运行两个带有 main 的类

    java - 在 JAR 中构建 Maven 多模块项目

    eclipse - 升级到 4.7 后无法在 Eclipse 运行配置中添加 Java 应用程序

    java - Java 中的流分词器 : Trying to implement