具有显式finalName的Maven将无法正常工作

Pau*_*ulo 18 java stack-overflow maven maven-package

1.背景

我的Maven项目有很多的模块和子模块与jarswars一切工作.我也可以在服务器上部署它而没有任何问题.

我决定遵循这个maven命名转换,我正在进行一些测试project.nameproject.build.finalName拥有一个合适的名称.

我定义project.name为根工件创建的模式是company-${project.artifactId},对于模块和子模块是${project.parent.name}-${project.artifactId}:

  • 公司的任何伪影的任何-模块1
  • 公司的任何伪影的任何-模块2-任何-submodule1
  • 公司的任何伪影的任何-模块2-任何-submodule2

模式project.build.finalName${project.name}-${project.version}:

  • 公司的任何伪影的任何-module1-1.0.jar
  • 公司的任何伪影的任何-模块2-任何-submodule1-2.0.jar
  • 公司的任何伪影的任何-模块2-任何-submodule2-3.0.war

但maven没有生成这些文件,而是给了我一个StackOverflowError.

2.重现错误的示例

你可以从github克隆这个例子:https://github.com/pauloleitemoreira/company-any-artifact

在github中,有一个master分支,它将重现此错误.还有only-modules分支,这是一个工作示例,用于${project.parent.name}生成finalName我想要的jar .

让我们考虑一个带有一个根pom工件,一个pom模块和一个子模块的maven项目.

-any-artifact
     |
     |-any-module      
           |
           |-any-submodule
Run Code Online (Sandbox Code Playgroud)

2.1任何神器

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.company</groupId>
    <artifactId>any-artifact</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>

    <name>company-${project.artifactId}</name>

    <modules>
        <module>any-module</module>
    </modules>

    <!-- if remove finalName, maven will not throw StackOverflow error -->
    <build>
        <finalName>${project.name}-${project.version}</finalName>
    </build>
</project>
Run Code Online (Sandbox Code Playgroud)

2.2任何模块

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <artifactId>any-artifact</artifactId>
        <groupId>com.company</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <groupId>com.company.any-artifact</groupId>
    <artifactId>any-module</artifactId>
    <packaging>pom</packaging>

    <name>${project.parent.name}-${project.artifactId}</name>

    <modules>
        <module>any-submodule</module>
    </modules>
</project>
Run Code Online (Sandbox Code Playgroud)

2.3 any-submodule

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <artifactId>any-module</artifactId>
        <groupId>com.company.any-artifact</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <groupId>com.company.any-artifact.any-module</groupId>
    <artifactId>any-submodule</artifactId>

    <name>${project.parent.name}-${project.artifactId}</name>
</project>
Run Code Online (Sandbox Code Playgroud)

3.问题

当试着mvn clean install,maven给了我一个StackOverflowError:

Exception in thread "main" java.lang.StackOverflowError
    at org.codehaus.plexus.util.StringUtils.isEmpty(StringUtils.java:177)
    at org.codehaus.plexus.util.introspection.ReflectionValueExtractor.evaluate(ReflectionValueExtractor.java:194)
    at org.codehaus.plexus.util.introspection.ReflectionValueExtractor.evaluate(ReflectionValueExtractor.java:163)
    at org.apache.maven.plugin.PluginParameterExpressionEvaluator.evaluate(PluginParameterExpressionEvaluator.java:266)
    at org.apache.maven.plugin.PluginParameterExpressionEvaluator.evaluate(PluginParameterExpressionEvaluator.java:143)
    at org.apache.maven.plugin.PluginParameterExpressionEvaluator.evaluate(PluginParameterExpressionEvaluator.java:174)
    at org.apache.maven.plugin.PluginParameterExpressionEvaluator.evaluate(PluginParameterExpressionEvaluator.java:143)
    at org.apache.maven.plugin.PluginParameterExpressionEvaluator.evaluate(PluginParameterExpressionEvaluator.java:429)
    at org.apache.maven.plugin.PluginParameterExpressionEvaluator.evaluate(PluginParameterExpressionEvaluator.java:143)
    at org.apache.maven.plugin.PluginParameterExpressionEvaluator.evaluate(PluginParameterExpressionEvaluator.java:174)
    at org.apache.maven.plugin.PluginParameterExpressionEvaluator.evaluate(PluginParameterExpressionEvaluator.java:143)
    at org.apache.maven.plugin.PluginParameterExpressionEvaluator.evaluate(PluginParameterExpressionEvaluator.java:429)
    at org.apache.maven.plugin.PluginParameterExpressionEvaluator.evaluate(PluginParameterExpressionEvaluator.java:143)
    at org.apache.maven.plugin.PluginParameterExpressionEvaluator.evaluate(PluginParameterExpressionEvaluator.java:174)
    at org.apache.maven.plugin.PluginParameterExpressionEvaluator.evaluate(PluginParameterExpressionEvaluator.java:143)
Run Code Online (Sandbox Code Playgroud)

重要的是要知道只有在我们使用子模块时才会发生错误.如果我们使用根POM工件和jar模块创建项目,则不会发生错误.

这个问题

为什么只有在我们使用子模块时才会出现此错误?

有什么建议可以解决我的问题吗?我应该忘记它并按照我想要的模式手动设置project.nameproject.build.fileName手动完成每个项目吗?

重要更新:

一些答案只是说使用&{parent.name},但它不起作用.Maven version 3.3.9在回答这个问题之前,请考虑使用赏金来考虑您的解决方案.

Maven版本3.3.9

编辑 - 在错误发生时使用阶段向问题添加详细信息,直到prepare-package阶段工作正常,但StackOverflow发生在package项目的maven生命周期阶段.

Tun*_*aki 8

严格回答你的问题是,${project.parent.name}不会被解析为部分型号插值处理.反过来,你有一个StackOverflowError完全不同的代码,即...构建项目的最终JAR.

第1部分:构建的模型是错误的

这是发生了什么.当您在项目上启动Maven命令时,首先要执行的操作是创建项目的有效模型.这意味着读取您的POM文件,使用激活的配置文件进行推理,应用继承,对属性执行插值...所有这些都为您的项目构建最终的Maven模型.这项工作由Maven Model Builder组件完成.

构建模型的过程非常复杂,许多步骤可能分为两个阶段,但我们在模型插值部分对这里感兴趣的部分.这是Maven将在模型中替换所有用${...}计算值表示的标记.它在注入配置文件后发生,并执行继承.在那个时间点,由一个MavenProject对象表示的Maven项目尚不存在,只有它Model正在构建.只有在你拥有一个完整的模型之后,才可以从中开始构建Maven项目.

因此,在进行插值时,仅根据POM文件中存在的信息进行推理,并且唯一有效的值是模型参考中提到的值.(StringSearchModelInterpolator如果您想查看源代码,则此替换由类执行.)值得注意的是,您会注意到<parent>模型中的元素包含父模型的名称.类ModelMaven中实际上是与生成MODELLO从源.mdo文件,和其源仅定义groupId,artifactId,versionrelativePath(连同定制id)的<parent>元件.这在文档中也可见.

所有这些的结果是,在执行模型插值之后,${project.parent.name}不会替换令牌.而且,MavenProject从它构造的将具有包含未${project.parent.name}替换的名称.您可以在我们的示例项目的日志中看到这一点

[INFO] Reactor Build Order:
[INFO] 
[INFO] company-any-artifact
[INFO] ${project.parent.name}-any-module
[INFO] ${project.parent.name}-any-submodule
Run Code Online (Sandbox Code Playgroud)

这意味着Maven的考虑项目的实际名称any-module${project.parent.name}-any-module.

第2部分:奇怪的事情开始了

我们现在正处于反应堆中的所有项目都正确创建甚至编译的时候.实际上,理论上一切都应该工作得很好,但项目本身只有完全不知名的名字.但是你有一个奇怪的例子,它在创建JAR时失败了maven-jar-plugin.使用以下日志在您的示例中构建失败:

[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ any-submodule ---
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary:
[INFO] 
[INFO] company-any-artifact ............................... SUCCESS [  0.171 s]
[INFO] ${project.parent.name}-any-module .................. SUCCESS [  0.002 s]
[INFO] ${project.parent.name}-any-submodule ............... FAILURE [  0.987 s]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
Run Code Online (Sandbox Code Playgroud)

这意味着在模型建立之后出现了问题.原因是该插件将项目名称作为参数注入:


/**
 * Name of the generated JAR.
 *
 * @parameter alias="jarName" expression="${jar.finalName}" default-value="${project.build.finalName}"
 * @required
 */
private String finalName;
Run Code Online (Sandbox Code Playgroud)

注意project.build.finalName作为子模块生成的JAR名称的默认值.这种注入和变量的插值是由另一个叫做的类完成的PluginParameterExpressionEvaluator.

那么这会发生什么:

  • any-submodule注入JAR插件的项目的最终名称,名称${project.parent.name}-any-submodule.
  • 感谢来自父项目的继承,以及<finalName>最顶层POM项目中的声明,它继承了<finalName>${project.name}-${project.version}</finalName>.
  • Maven的现在尝试插值${project.name}any-submodule.
  • ${project.parent.name}-any-submodule由于第1部分,这解决了.
  • Maven的现在尝试插值${project.parent.name}any-submodule.这工作正常:MavenProject构建并将getParent()在项目实例上调用,返回具体的Maven父项目.因此,${project.parent.name}将尽力解决的名字any-module,这实际上是${project.parent.name}-any-module.
  • Maven现在尝试插值${project.parent.name}-any-module,但仍然在any-submodule项目实例上.因为PluginParameterExpressionEvaluator,"project"评估令牌的根没有改变.
  • Maven的现在尝试插值${project.parent.name}any-submodule,这又可以正常工作并返回${project.parent.name}-any-module.
  • Maven的现在尝试插值${project.parent.name}any-submodule......这工作,并返回${project.parent.name}-any-module所以它试图评估${project.parent.name}...

你可以看到这里发生的无休止的递归,这导致StackOverflowError你拥有.这是一个错误PluginParameterExpressionEvaluator吗?这一点尚不清楚:它的原因是模型值首先没有被正确替换.理论上,它可以处理评估${project.parent}和创建PluginParameterExpressionEvaluator此父项目的新工作的特殊情况,而不是始终处理当前项目.如果您对此有强烈的感受,请随时创建JIRA问题.

第3部分:没有子模块的原因

通过以上所述,您现在可以推断出它在这种情况下的工作原理.让我们了解Maven需要做什么来评估最终名称,因为必须在Maven Jar插件中注入:

  • any-module注入JAR插件的项目的最终名称,名称${project.parent.name}-any-module.
  • 感谢您从父项目继承,并在<finalName>最顶层的POM项目中声明它继承<finalName>${project.name}-${project.version}</finalName>.
  • Maven的现在尝试插值${project.name}any-module.
  • 这解决了${project.parent.name}-any-module,和以前一样.
  • Maven的现在尝试插值${project.parent.name}any-module.就像以前一样,这个工作正常:MavenProject构建并将getParent()在项目实例上调用,返回具体的Maven父项目.因此,${project.parent.name}将尽力解决的名字any-artifact,这实际上是company-any-artifact.
  • 插值成功并停止.

而且你没有任何错误.