带有显式finalName的java Maven无法正常工作
1。背景
我的maven项目有很多带有jars
和wars
的模块和子模块,而且一切正常。我还可以毫无问题地将其部署到服务器上
我决定遵循this maven naming conversion,我正在用project.name
和project.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.name
和project.build.fileName
重要更新:
有些答案只是说使用
Maven版本3.3.9 编辑-在错误发生的阶段为问题添加详细信息,在&{parent.name}
,但不起作用。请回答这个问题,在回答这个问题之前,请考虑用{{CD20}}测试你的解决方案。prepare-package
阶段之前一切正常,但在项目的maven生命周期的package
阶段发生堆栈溢出
# 1 楼答案
正如我在对Difference between project.parent.name and parent.name ans use of finalName in pom.xml的答复中所说的那样
让我们首先看一下基本知识:
如POM Reference所述:
所以这两者有不同的用途
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版本)
那么发生的情况是:
编辑:使错误的实际原因更清楚(请参见注释):
@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>artifact-anymodule-anysubmodule</artifactId>
李>anymodule
,不需要是模块的实际artifactId李># 2 楼答案
有趣!我开始克隆回购协议并复制错误。我将非常感谢能够从以下提到的任何步骤中获得帮助我调试问题的任何线索-
Maven Life Cycle Phases 问题发生的阶段是生命周期的
package
阶段。意思是mvn package
会在项目中重现问题检查了错误中的堆栈跟踪行。了解表达式计算失败的地方-
也不是
finalName
属性导致了它。因为指定了相同的默认值<finalName>${artifactId}-${version}</finalName>
使用相同的项目配置可以正常工作然后尝试将
any-submodule
的包装更改为错误消失了。这意味着,当打包为
jar
、war
等时,表达式的计算结果不同,会导致溢出修改}内容我可以自信地说,是
any-module
或any-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
分别随变化而变化根据需求寻找解决方案,我正在寻找您正在使用的递归的尾部
注意-仍在努力找到该问题的适当解决方案
# 3 楼答案
更换pom。xml在公司的任何工件下面,它将工作
更换pom。子模块中的xml到下面
更改子模块pom。xml到下面
然后输出为:company-any-module-any-submodule-1.0-SNAPSHOT
# 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。(如果您想查看源代码,此替换由^{} 类执行。)非常值得注意的是,您会注意到模型中的}, ^{}, ^{} and ^{} (以及自定义的
<parent>
元素不包含父模型的名称。Maven中的类Model
实际上是从源.mdo
文件中使用Modello生成的,该源仅为<parent>
元素定义^{id
)。这也是可见的in the documentation所有这些的结果是,在执行模型插值之后,将不会替换标记
${project.parent.name}
。而且,进一步地,由它构造的MavenProject
将具有包含${project.parent.name}
未替换的名称。您可以在日志中看到这一点,在您的示例项目中,我们有这意味着Maven将项目的实际名称^ {< CD19>}设为^ {CD20>}。
第二部分:怪诞开始
现在,反应堆中的所有项目都被正确创建甚至编译。实际上,从理论上讲,一切都应该很好,但项目本身的名称完全没有问题。但是您有一个奇怪的情况,它在创建带有
maven-jar-plugin
的JAR时失败。在您的示例中,生成失败,日志如下:这意味着在模型建立之后,出现了一些问题。原因是插件injects the name of the project as a parameter:
注意} 的类完成
project.build.finalName
作为子模块生成的JAR名称的默认值。这个注入和变量的插值由另一个名为^{那么,在这种情况下会发生什么:
any-submodule
上的JAR插件注入项目的最终名称${project.parent.name}-any-submodule
李><finalName>
,它继承了<finalName>${project.name}-${project.version}</finalName>
李>any-submodule
插入${project.name}
李>${project.parent.name}-any-submodule
李>any-submodule
插入${project.parent.name}
。这是正确的:构建了MavenProject
,将在项目实例上调用^{${project.parent.name}
将尝试解析any-module
的名称,实际上是${project.parent.name}-any-module
李>${project.parent.name}-any-module
,但仍然在any-submodule
项目实例上。对于PluginParameterExpressionEvaluator
,要计算令牌的根"project"
没有更改李>any-submodule
上插入${project.parent.name}
,这同样有效ectly并返回${project.parent.name}-any-module
李>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
李><finalName>
,它继承了<finalName>${project.name}-${project.version}</finalName>
李>any-module
插入${project.name}
李>${project.parent.name}-any-module
,与前面相同李>any-module
插入${project.parent.name}
。与前面一样,这是正确的:构建了MavenProject
,将对项目实例调用^{${project.parent.name}
将尝试解析any-artifact
的名称,实际上是company-any-artifact
李>你没有任何错误
# 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}}是一个很好的方法。