有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

带有显式finalName的java Maven无法正常工作

1。背景

我的maven项目有很多带有jarswars的模块和子模块,而且一切正常。我还可以毫无问题地将其部署到服务器上

我决定遵循this maven naming conversion,我正在用project.nameproject.build.finalName进行一些测试,以获得一个合适的名称

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

  • 公司-任何-工件-任何-模块1
  • 公司-any-artifact-any-module2-any-submodule1
  • 公司-any-artifact-any-module2-any-submodule2

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

  • company-any-artifact-any-module1-1.0。罐子
  • company-any-artifact-any-module2-any-submodule1-2.0。罐子
  • company-any-artifact-any-module2-any-submodule2-3.0。战争

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

2。重现错误的示例

您可以从github克隆此示例:https://github.com/pauloleitemoreira/company-any-artifact

在github中,有^{}分支,它将重现此错误。还有^{}分支,这是一个工作示例,它使用${project.parent.name}生成我想要的jarfinalName

让我们考虑一个具有一个根POM工件、一个POM模块和一个子模块的Maven项目。p>

-any-artifact
     |
     |-any-module      
           |
           |-any-submodule

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>

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>

2.3任何子模块

<?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>

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)

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

4。问题

为什么只有在使用子模块时才会发生此错误

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

重要更新:

有些答案只是说使用&{parent.name},但不起作用。请回答这个问题,在回答这个问题之前,请考虑用{{CD20}}测试你的解决方案。

Maven版本3.3.9

编辑-在错误发生的阶段为问题添加详细信息,在prepare-package阶段之前一切正常,但在项目的maven生命周期的package阶段发生堆栈溢出


共 (5) 个答案

  1. # 1 楼答案

    正如我在对Difference between project.parent.name and parent.name ans use of finalName in pom.xml的答复中所说的那样

    让我们首先看一下基本知识:

    POM Reference所述:

    finalName: This is the name of the bundled project when it is finally built (sans the file extension, for example: my-project-1.0.jar). It defaults to ${artifactId}-${version}.

    name: Projects tend to have conversational names, beyond the artifactId.

    所以这两者有不同的用途

    • name纯粹是信息性的,主要用于生成的文档和构建日志。它既不会被继承,也不会在其他任何地方使用。它是人类可读的字符串,因此可以包含任何字符,即文件名中不允许的空格或字符。因此,这将是有效的:<name>My Turbo Project on Speed!</name>。这显然至少是工件的一个有问题的文件名

    • 如上所述,finalName是生成的工件的名称。它是继承的,因此通常应该依赖于属性。只有两个真正有用的选项是默认的${artifactId}-${version}和无版本的${artifactId}。其他一切都会导致混乱(例如名为foo的项目创建了一个工件bar.jar)。事实上,我的涡轮项目!可能是有效的,因为这是一个有效的文件名,但实际上,这样的文件名往往是不可用的(例如,尝试从bash中寻址一个包含!的文件名)


    因此,关于Stackoverflow发生的原因:

    • name不是继承的
    • project.parent.name在插值过程中也不会计算,因为名称是少数几个对子对象完全不可见的属性之一
    • parent.name实际上用于较旧的Maven版本,但更多是由于一个bug(另外,不推荐使用在没有前导project的情况下访问属性)
    • 缺少的特性不会被插值,即按原样保留在模型中
    • 因此,在any-submodule的有效pom中,finalName的值仍然是:${project.parent.name}-any-submodule

    到目前为止还很糟糕。现在是堆栈溢出的原因

    Maven有一个附加的特性,叫做后期插值,当插件参数实际使用时,它会计算这些参数中的值。这允许pluing使用不属于模型的属性,但由插件在生命周期早期生成的属性(例如,这允许插件为最终名称提供git版本)

    那么发生的情况是:

    编辑:使错误的实际原因更清楚(请参见注释):

    • 将评估jar插件的最终名称: @Parameter( defaultValue = "${project.build.finalName}", readonly = true )
    • PluginParameterExpressionEvaluator开始并尝试计算最终名称(${project.parent.name}-any-submodule),该名称包含属性表达式${project.parent.name}
    • 计算器询问模型,模型返回父项目的名称,即:${project.parent.name}-any-module
    • 因此,求值器尝试解决此问题,返回${project.parent.name}-any-module(再次),因为属性总是针对当前项目解决,所以循环再次开始
    • 抛出堆栈溢出错误

    如何解决这个问题

    遗憾的是,你不能

    您需要为每个项目显式指定name(以及artifactId)。没有解决办法

    然后,您可以finalName依赖它。不过,我建议不要这样做(见我对Difference between project.parent.name and parent.name ans use of finalName in pom.xml的答复)

    以这种方式更改最终名称的问题是,本地构建工件的名称与存储库中的名称不同,因此本地工件的名称为any-artifact-any-module-any-submodule.jar,但存储库中的工件名称仍然是any-submodule.jar

    暗示

    • 如果您确实需要区分这一细微差别,请改为更改artifactId:<artifactId>artifact-anymodule-anysubmodule</artifactId>
    • 不要在短名称中使用破折号来区分结构的级别
    • 提示:模块的路径仍然可以是anymodule,不需要是模块的实际artifactId
    • 当我们在使用它时,使用^ {CD1}}作为它的目的,是人类可读的,因此你可以考虑一些更吸引人的东西(因为这是生成日志中出现的名字):^ {< CD29>}。/李>
    • 实际上,使用非常短的groovy脚本自动创建名称条目非常容易
    • 您还可以编写强制规则来强制工件的命名
  2. # 2 楼答案

    有趣!我开始克隆回购协议并复制错误。我将非常感谢能够从以下提到的任何步骤中获得帮助我调试问题的任何线索-

    1. Maven Life Cycle Phases 问题发生的阶段是生命周期的package阶段。意思是mvn package会在项目中重现问题

    2. 检查了错误中的堆栈跟踪行。了解表达式计算失败的地方-

      @Override
      public Object evaluate( String expr ) throws ExpressionEvaluationException {
          return evaluate( expr, null ); // Line 143
      }
      
    3. 也不是finalName属性导致了它。因为指定了相同的默认值 <finalName>${artifactId}-${version}</finalName> 使用相同的项目配置可以正常工作

    4. 然后尝试将any-submodule的包装更改为

      <packaging>pom</packaging>
      

      错误消失了。这意味着,当打包为jarwar等时,表达式的计算结果不同,会导致溢出

    5. 修改any-moduleany-submodule{}内容我可以自信地说,是project.parent.name在计算表达式时导致递归并导致堆栈溢出(如何?-is something I am still looking for..)。还有,改变

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

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

      从某种意义上说,我没有收到错误,但生成的jar类型为-

      ${parent.name}-any-module-any-submodule-1.0-SNAPSHOT.jar

      ${parent.name}-any-submodule-1.0-SNAPSHOT分别随变化而变化

    6. 根据需求寻找解决方案,我正在寻找您正在使用的递归的尾部

    注意-仍在努力找到该问题的适当解决方案

  3. # 3 楼答案

    更换pom。xml在公司的任何工件下面,它将工作

    <?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>${project.groupId}</name>
    
    
        <modules>
            <module>any-module</module>
        </modules>
    
        <!-- if remove finalName, maven will not throw StackOverflow error -->
        <build>
            <finalName>${project.groupId}-${project.version}</finalName>
        </build>
    </project>
    

    更换pom。子模块中的xml到下面

    <?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>  
         <build>
            <finalName>${project.parent.name}-${project.artifactId}</finalName>
        </build> 
    </project>
    

    更改子模块pom。xml到下面

    <?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}-${project.version}</name>    -->
        <build>
            <finalName>company-${project.parent.name}-${project.artifactId}-${project.version}</finalName>
        </build>
    </project>
    

    然后输出为:company-any-module-any-submodule-1.0-SNAPSHOT

  4. # 4 楼答案

    对您的问题的严格回答是${project.parent.name}而不是作为模型插值过程的一部分进行解析。反过来,您有一个StackOverflowError,在代码的一个完全不同的位置,即当。。。构建项目的最终JAR

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

    下面是发生的情况。在项目上启动Maven命令时,它采取的第一个操作是创建项目的有效模型。这意味着读取POM文件,使用激活的配置文件进行推理,应用继承,对属性执行插值。。。所有这些都是为了为您的项目构建最终的Maven模型。这项工作由Maven Model Builder组件完成

    构建模型的过程相当复杂,很多步骤可能分为两个阶段,但我们感兴趣的部分是model interpolation部分。此时Maven将在模型中用计算值替换由${...}表示的所有标记。它发生在注入配置文件并执行继承之后。此时,由MavenProject对象表示的Maven项目还不存在,只构建了它的Model。只有在你有了完整的模型之后,你才能从它开始构建Maven项目

    因此,当插值完成时,它仅根据POM文件中存在的信息进行推理,并且唯一有效的值是mentioned in the model reference。(如果您想查看源代码,此替换由^{}类执行。)非常值得注意的是,您会注意到模型中的<parent>元素不包含父模型的名称。Maven中的类Model实际上是从源.mdo文件中使用Modello生成的,该源仅为<parent>元素定义^{}, ^{}, ^{} and ^{}(以及自定义的id)。这也是可见的in the documentation

    所有这些的结果是,在执行模型插值之后,将不会替换标记${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
    

    这意味着Maven将项目的实际名称^ {< CD19>}设为^ {CD20>}。

    第二部分:怪诞开始

    现在,反应堆中的所有项目都被正确创建甚至编译。实际上,从理论上讲,一切都应该很好,但项目本身的名称完全没有问题。但是您有一个奇怪的情况,它在创建带有maven-jar-plugin的JAR时失败。在您的示例中,生成失败,日志如下:

    [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] ------------------------------------------------------------------------
    

    这意味着在模型建立之后,出现了一些问题。原因是插件injects the name of the project as a parameter

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

    注意project.build.finalName作为子模块生成的JAR名称的默认值。这个注入和变量的插值由另一个名为^{}的类完成

    那么,在这种情况下会发生什么:

    • any-submodule上的JAR插件注入项目的最终名称${project.parent.name}-any-submodule
    • 感谢父项目的继承,感谢您在最顶级的POM项目中声明<finalName>,它继承了<finalName>${project.name}-${project.version}</finalName>
    • Maven现在尝试为any-submodule插入${project.name}
    • 由于第1部分的原因,这归结为${project.parent.name}-any-submodule
    • Maven现在尝试为any-submodule插入${project.parent.name}。这是正确的:构建了MavenProject,将在项目实例上调用^{},返回具体的Maven父项目。因此,${project.parent.name}将尝试解析any-module的名称,实际上是${project.parent.name}-any-module
    • Maven现在尝试插入${project.parent.name}-any-module但仍然在any-submodule项目实例上。对于PluginParameterExpressionEvaluator,要计算令牌的根"project"没有更改
    • Maven现在尝试在any-submodule上插入${project.parent.name},这同样有效ectly并返回${project.parent.name}-any-module
    • Maven现在尝试在any-submodule上插入${project.parent.name}。。。它工作并返回${project.parent.name}-any-module,因此它尝试计算${project.parent.name}

    您可以看到这里发生的无休止的递归,这导致了StackOverflowError。这是^{中的错误吗?这一点尚不清楚:它首先是因为模型值没有正确替换。理论上,它可以处理评估${project.parent}的特殊情况,并创建一个新的PluginParameterExpressionEvaluator处理此父项目,而不是总是处理当前项目。如果您对此有强烈的感觉,请随意创建a JIRA issue

    第3部分:为什么没有子模块就可以工作

    通过上面所说的,您现在可以推断出它在这种情况下工作的原因。让我们来说明Maven需要做什么来评估最终名称,正如必须注入Maven Jar插件中一样:

    • any-module上的JAR插件注入项目的最终名称${project.parent.name}-any-module
    • 感谢父项目的继承,感谢您在最顶级的POM项目中声明<finalName>,它继承了<finalName>${project.name}-${project.version}</finalName>
    • Maven现在尝试为any-module插入${project.name}
    • 这解析为${project.parent.name}-any-module,与前面相同
    • Maven现在尝试为any-module插入${project.parent.name}。与前面一样,这是正确的:构建了MavenProject,将对项目实例调用^{},返回具体的Maven父项目。因此,${project.parent.name}将尝试解析any-artifact的名称,实际上是company-any-artifact
    • 插值已成功并停止

    你没有任何错误

  5. # 5 楼答案

    这是属性继承的问题
    尝试使用${parent.name}而不是${project.parent.name}
    请看:Project name declared in parent POM isn't expanded in a module filtered web.xml

    ---更新--

    Benjamin Bentmann(maven Commitier)说:“一般来说,形式${project.parent.*}的表达式是一种不好的做法,因为它们依赖于特定的构建状态,并且通常不会在整个POM中工作,从而引起意外。”

    https://issues.apache.org/jira/browse/MNG-5126?jql=text%20~%20%22parent%20name%22

    也许你应该考虑使用{{CD3}}是一个很好的方法。