无法使Maven测试范围的依赖项与Java 9(也不是10个)模块

时间:2018-05-01 19:47:23

标签: 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.Basesrc/main模块apimod类)不再可见{{1 (client.test.DerivedTest模块src/test类。测试不再编译。

这是Maven还是Java 9中的错误?这是最新版本:Java 9.0.4(与Java 10相同),Maven 3.5.3,maven-compiler-plugin 3.7.0

到目前为止我的分析

代码

源代码位于:

clientmod

我在分支机构中测试失败的问题“二分”:

git clone https://github.com/vandekeiser/wires.git

- > BUILD FAIL(git checkout MINIMIZE_ISSUE `mvn clean install` 的测试中的编译错误)

Maven测试范围依赖

我希望模块clientmod不仅能够重用clientmod的生产代码,还能重用测试代码。使用Maven,你可以这样做(apimod):

clientmod/pom.xml

Java 9模块

<dependency>
    <groupId>fr.cla</groupId>
    <artifactId>apimod</artifactId>
    <version>${project.version}</version>
    <classifier>tests</classifier>
    <scope>test</scope>
</dependency>

尝试启用两个模块系统时失败

使用Java 9,如果我声明测试范围的依赖项和Java 9模块,则测试不再编译(module apimod { exports api; } module clientmod { requires apimod; } 输出):

mvn clean install

使用javac重现问题:模块修补中的错误?

就好像启用测试依赖项([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 )会禁用生产依赖项(src/test)。我知道在这种情况下,Maven应该使用javac src/main标志。 所以我只使用javac(使用--patch-module的调试输出)重现了这个问题:

相同的编译,跳过Maven:

mvn -X

相同的编译错误:

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;"

我尝试使用应该禁用模块系统的javac标志,但它们似乎不存在于我的64位Windows Oracle JVM中? (Java HotSpot(TM)64位服务器VM(版本9.0.4 + 11,混合模式):

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 --illegal-access=warn
javac: invalid flag: --permit-illegal-access
javac --permit-illegal-access
javac: invalid flag: --illegal-access=warn

mvn -version的输出:

--add-reads apimod=ALL-UNNAMED \
--add-reads clientmod=ALL-UNNAMED \
--add-exports apimod/api=ALL-UNNAMED \
--add-exports clientmod/client=ALL-UNNAMED \

分析Till Brychcy的回答

感谢您的详细解答,基本上就是“看起来maven还不支持这个用例” - &gt;所以让我们尝试重现没有maven的问题。我为这些试验创建了分支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" (抱歉这个令人困惑的分支名称)。

  1. 调整我以前的maven记录的命令行,即:

    TRY_ADAPT_khmarbaise-MINIMIZE_ISSUE
  2. 我从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

  3. 中删除G:\projets\wires\wires\wires\apimod\target\apimod-1.0-SNAPSHOT-tests.jar;
  4. 我将其添加到--module-path,给我:

    --patch-module clientmod
  5. - &gt;好的,它现在编译!所以你的假设maven-compiler-plugin或maven不支持这个似乎已经过验证。 但是我认为它应该在我使用的版本中得到支持,这是最新版本。我想知道从哪里开始检查..

    无论如何,与此同时,我尝试明确配置maven-compiler-plugin,但无济于事。 我试过的一般结构是(maven-compiler-plugin.version = 3.7.0):

    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
    

    我尝试了以下<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> (xml注释中相应的mvn clean install错误):

    1:

    compilerArgs

    2:

    <!--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 个答案:

答案 0 :(得分:2)

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

问题是apimod-1.0-SNAPSHOT-tests.jar被视为自动模块,其自动模块名称(从文件名派生)是&#34; apimod&#34;,因此实际模块{{ <{1}}中的{}}(稍后出现在模块路径上)将被忽略。

Maven应检测到apimod属于apimod-1.0-SNAPSHOT.jar并使用apimod-1.0-SNAPSHOT-tests.jar而非使其成为apimod的一部分

答案 1 :(得分:1)

现在可以使用!在那里有所有解释:https://issues.apache.org/jira/browse/MCOMPILER-348

问题是名称冲突:在问题减少分支和main-dev分支中,将maven模块的名称更改为不同于修复它的Java模块的名称。

尽管如此,我仍然有一个警告(请参阅链接),现在我忽略了它,但是它需要继续。

---------------如果JIRA消失了,链接内容的副本-----------

Robert Scholte : 我的猜测是apimod-1.0-SNAPSHOT-tests.jar应该在类路径上,而不是在模块路径上。我能想到的唯一原因就是它的自动模块名称也是apimod。 将名称更改为与自动模块名称不冲突的名称可解决此问题(例如info.example.apimod) 通常,请选择一个更唯一的模块名,它必须是全局唯一的(就像classpath上的类一样)。添加reverseDNS或共享软件包。 永久链接编辑删除

: 是的,非常感谢!我以为这是一个bug(但是,可能还有一些较小的bug?我还需要进一步研究,但是仍然有javac警告-请参阅结尾)。此评论)。

它固定了二分法分支和主分支: -在二分法分支中,我为java模块添加了前缀 -回到主分支后,我将Maven模块wires.core-> wires-core等重命名,并将java模块重命名为共享根包,也避免了名称冲突

用“ Java迷惑者”的术语来说,这也许是双重的: -对于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

要重现它,请在master分支(https://github.com/vandekeiser/wires.git)中检出标签WARN_IF_UNCOMMENT并在以下位置删除导出异常: -Xlint:所有,串行,导出

我不能(也不必)从fr.cla.wires.support.oo.ddd添加出口;进入module-info.java,因为它引用的是src / test中的软件包

那是现在的地方