1。背景
我的maven项目有很多模块和子模块jars
和wars
,一切正常。我也可以在服务器上部署它而没有任何问题。
我决定关注this maven naming conversion,我正在使用project.name
和project.build.finalName
进行一些测试以获得适当的名称。
我为根工件创建project.name
所定义的模式是company-${project.artifactId}
,模块和子模块的模式是${project.parent.name}-${project.artifactId}
:
project.build.finalName
的模式是${project.name}-${project.version}
:
但maven没有生成这些文件,而是给了我StackOverflowError
。
2。重现错误的示例
您可以从github克隆此示例:https://github.com/pauloleitemoreira/company-any-artifact
在github中,有master
分支,它将重现此错误。还有only-modules
分支,这是一个使用${project.parent.name}
生成jar finalName
的工作示例。
让我们考虑一个带有一个根pom工件,一个pom模块和一个子模块的maven项目。
-any-artifact
|
|-any-module
|
|-any-submodule
2.1 any-artifact
<?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 any-module
<?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 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>
第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
吗?
重要更新:
有些答案只是说使用 &{parent.name}
,但是它不起作用。这是一个带有赏金的问题,请在回答此问题之前考虑使用Maven version 3.3.9
测试您的解决方案。
Maven版本3.3.9
编辑 - 在错误发生时添加阶段问题的详细信息,工作正常,直到prepare-package
阶段,但StackOverflow发生在该项目的maven生命周期的package
阶段。
答案 0 :(得分:8)
对您的问题的严格回答是${project.parent.name}
将不作为模型插值过程的一部分进行解析。反过来,你有一个StackOverflowError
,在一个完全不同的代码位置,即当...构建项目的最终JAR时。
这里发生了什么。当您在项目上启动Maven命令时,首先要做的是创建项目的有效模型。这意味着读取您的POM文件,使用激活的配置文件进行推理,应用继承,对属性执行插值...所有这些都为您的项目构建最终的Maven模型。这项工作由Maven Model Builder组件完成。
构建模型的过程非常复杂,许多步骤可能分为两个阶段,但我们在model interpolation部分对此感兴趣的部分。这是Maven将在模型中用${...}
表示的所有标记替换计算值。它在注入配置文件后发生,并执行继承。在那个时间点,由MavenProject
对象表示的Maven项目尚未存在,只有Model
正在构建。只有在你拥有一个完整的模型之后,才可以从中开始构建Maven项目。
因此,当插值完成时,它仅根据POM文件中存在的信息进行推理,并且唯一有效的值是mentioned in the model reference。 (如果您想查看源代码,则此替换由StringSearchModelInterpolator
类执行。)值得注意的是,您会注意到模型中的<parent>
元素不包含父模型的名称。 Maven中的类Model
实际上是使用来自源.mdo
文件的Modello生成的,并且该来源仅定义了groupId
, artifactId
, version
and relativePath
(以及自定义id
) <parent>
元素。这也是可见的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将项目any-module
的实际名称视为${project.parent.name}-any-module
。
我们现在正处于反应堆中的所有项目都已正确创建甚至编译的时刻。实际上,理论上一切都应该工作得很好,但项目本身只有完全不知名的名字。但是你有一个奇怪的例子,它在用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名称的默认值。此注入和变量的插值由另一个名为PluginParameterExpressionEvaluator
的类完成。
所以会发生什么:
any-submodule
上的JAR插件会注入项目的最终名称,名为${project.parent.name}-any-submodule
。<finalName>
的声明,它继承了<finalName>${project.name}-${project.version}</finalName>
。${project.name}
插入any-submodule
。${project.parent.name}-any-submodule
。${project.parent.name}
插入any-submodule
。这样可以正常工作:构建MavenProject
并在项目实例上调用getParent()
,返回具体的Maven父项目。因此,${project.parent.name}
会尝试解析any-module
的名称,实际上是${project.parent.name}-any-module
。${project.parent.name}-any-module
,但仍在any-submodule
项目实例上。对于PluginParameterExpressionEvaluator
,评估令牌的根"project"
未发生变化。${project.parent.name}
上插入any-submodule
,再次正常工作并返回${project.parent.name}-any-module
。${project.parent.name}
上插入any-submodule
...工作并返回${project.parent.name}-any-module
,以便它尝试评估${project.parent.name}
... 你可以在这里看到无休止的递归,这导致你拥有StackOverflowError
。这是PluginParameterExpressionEvaluator
中的错误吗?这一点尚不清楚:它的原因是模型值首先没有被正确替换。从理论上讲,它可以处理评估${project.parent}
的特殊情况,并创建一个处理此父项目的新PluginParameterExpressionEvaluator
,而不是始终处理当前项目。如果您对此有强烈的感受,请随时创建a JIRA issue。
通过以上所述,您现在可以推断出在这种情况下它的工作原理。让我们了解Maven需要做什么来评估最终名称,因为必须在Maven Jar插件中注入:
any-module
上的JAR插件会注入项目的最终名称,名为${project.parent.name}-any-module
。<finalName>
的声明,它继承了<finalName>${project.name}-${project.version}</finalName>
。${project.name}
插入any-module
。${project.parent.name}-any-module
,与之前相同。${project.parent.name}
插入any-module
。就像以前一样,这可以正常工作:构建MavenProject
并在项目实例上调用getParent()
,返回具体的Maven父项目。因此,${project.parent.name}
会尝试解析any-artifact
的名称,实际上是company-any-artifact
。你没有任何错误。
答案 1 :(得分:4)
正如我在回答Difference between project.parent.name and parent.name ans use of finalName in pom.xml
时所述让我们先来看看基础知识:
如POM Reference中所述:
finalName :这是捆绑项目最终构建时的名称(没有文件扩展名,例如:my-project-1.0.jar)。它默认为$ {artifactId} - $ {version}。
名称:除了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版本,但更多是由于某个错误(已弃用来访问没有前导project
的属性)。any-submodule
的有效pom中,finalName
的值是(尝试使用mvn help:effective-pom
)仍为:${project.parent.name}-any-submodule
到目前为止一直很糟糕。现在出现了StackOverflow的原因
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!name
来实现它的目的,是人类可读的,所以你可能会考虑更具视觉吸引力的东西(因为这是构建日志中出现的名称):{ {1}}。答案 2 :(得分:2)
这是属性继承的问题。
尝试使用${parent.name}
代替${project.parent.name}
。
请看:Project name declared in parent POM isn't expanded in a module filtered web.xml。
--- --- UPDATE
Benjamin Bentmann(maven committier)说:&#34;一般来说,${project.parent.*}
形式的表达是一种不好的做法,因为它们依赖于某种构建状态,并且通常不会在整个POM中工作,出现惊喜&#34;。
https://issues.apache.org/jira/browse/MNG-5126?jql=text%20~%20%22parent%20name%22
也许您应该考虑使用${project.parent.*}
是一种好方法。
答案 3 :(得分:-1)
将company-any-artifact中的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 :(得分:-2)
有趣!我开始克隆回购并重现错误。我将不胜感激任何可以从下面提到的帮助我调试问题的步骤中获取的任何线索 -
Maven Life Cycle Phases
发生问题的阶段是生命周期的package
阶段。含义mvn package
表示您的项目存在问题。
在错误中浏览堆栈跟踪线。在失败的地方了解表达式评估 -
@Override
public Object evaluate( String expr ) throws ExpressionEvaluationException {
return evaluate( expr, null ); // Line 143
}
它也不是造成它的finalName
属性。由于指定了相同的默认值
<finalName>${artifactId}-${version}</finalName>
使用相同的项目配置工作正常。
然后尝试将any-submodule
的包装更改为
<packaging>pom</packaging>
并且错误消失了。包装为jar
,war
等时的含义表达式评估不同,导致溢出。
修改any-module
或any-submodule
pom.xml
内容我可以肯定地说,project.parent.name
导致评估表达式的递归导致堆栈溢出(如何? - 是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
分别进行了更改。
根据要求寻找解决方案,我正在寻找你正在使用的递归的尾部。
注意 - 仍在努力寻找适合此问题的解决方案。