具有显式finalName的Maven无法正常工作 [英] Maven with an explicit finalName won't work properly
问题描述
1.背景
我的maven项目中有很多带有jars
和wars
的模块和子模块,并且一切正常.我也可以毫无问题地将其部署在服务器上.
我决定遵循此maven命名转换,我正在使用project.name
和project.build.finalName
进行一些测试以使用适当的名称.
我定义的用于为根工件创建project.name
的模式是company-${project.artifactId}
,用于模块和子模块的模式是${project.parent.name}-${project.artifactId}
:
- company-any-artifact-any-module1
- company-any-artifact-any-module2-any-submodule1
- company-any-artifact-any-module2-any-submodule2
project.build.finalName
的模式为${project.name}-${project.version}
:
- company-any-artifact-any-module1-1.0.jar
- company-any-artifact-any-module2-any-submodule1-2.0.jar
- company-any-artifact-any-module2-any-submodule2-3.0.war
但是maven不会生成这些文件,而是给我一个StackOverflowError
.
2.重现错误的示例
您可以从github克隆此示例: https://github.com/pauloleitemoreira/company -任何人工制品
在github中,有一个 master
分支,将重现此错误.并且有一个 only-modules
分支,它可以正常工作我想使用${project.parent.name}
生成jar finalName
的示例.
让我们考虑一个具有一个root pom构件,一个pom模块和一个子模块的maven项目.
-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
?
重要更新:
一些答案只是说要使用 &{parent.name}
,但不起作用.拜托,这是一个悬而未决的问题,在回答这个问题之前,请考虑使用Maven version 3.3.9
测试您的解决方案.
Maven版本3.3.9
编辑 -在发生错误的阶段向问题中添加详细信息,直到prepare-package
阶段一切正常,但是StackOverflow发生在package
项目的Maven生命周期阶段.
对您问题的严格回答是,${project.parent.name}
将不作为模型插值过程的一部分进行解析.反过来,您有一个StackOverflowError
,位于代码的完全不同的位置,即在……构建项目的最终JAR时.
第1部分:建立的模型有误
这就是发生的情况.在项目上启动Maven命令时,它要执行的第一步是创建项目的有效模型.这意味着读取您的POM文件,使用已激活的概要文件进行推理,应用继承,对属性执行插值...所有这些都为您的项目构建了最终的Maven模型.这项工作是由 Maven模型构建器组件完成的. >
构建模型的过程非常复杂,许多步骤可能分为两个阶段,但是我们在在模型参考中提到. (此替换操作由 Modello 从源.mdo
文件生成的,并且该来源仅定义<parent>元素的"noreferrer"> groupId
,artifactId
,version
和relativePath
(以及自定义的id
).在文档中>
所有这些的结果是,在执行模型插值后,标记${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
.
第2部分:怪异开始
我们现在是正确创建甚至编译反应堆中所有项目的时候.实际上,理论上所有内容都可以正常工作,但项目本身的名称完全不正确.但是,您遇到了一个奇怪的情况,在使用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] ------------------------------------------------------------------------
表示在构建模型后出现了一些问题.原因是插件default-value="${project.build.finalName}"
* @required
*/
private String finalName;
注意 您会看到这里发生了无尽的递归,这导致您拥有 使用上面所说的内容,您现在可以推断出为什么在这种情况下它可以工作.让我们来解释一下Maven需要做什么来评估最终名称,就像必须注入Maven Jar插件中一样:project.build.finalName
作为子模块生成的JAR名称的默认值.注入和变量的内插由另一个名为 getParent()
将在项目实例上调用,返回具体的Maven父项目.因此,${project.parent.name}
将尝试解析any-module
的名称,该名称实际上是${project.parent.name}-any-module
.
${project.parent.name}-any-module
,,但仍在any-submodule
项目实例上.对于PluginParameterExpressionEvaluator
,评估令牌的根"project"
不变.any-submodule
上插值${project.parent.name}
,它再次正常工作并返回${project.parent.name}-any-module
.any-submodule
...上内插${project.parent.name}
,该方法可以工作并返回${project.parent.name}-any-module
,因此它尝试评估${project.parent.name}
... StackOverflowError
.这是PluginParameterExpressionEvaluator
中的错误吗?尚不清楚:这是由于最初没有正确替换的模型值所致.从理论上讲,它可以处理评估${project.parent}
的特殊情况,并在此父项目上创建一个新的PluginParameterExpressionEvaluator
,而不是始终在当前项目上工作.如果您对此有强烈的想法,请随时创建 JIRA问题.第3部分:为什么没有子模块也能工作
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
已构建并且this maven naming conversion, I am making some tests with project.name
and project.build.finalName
to have an appropriate name.
The pattern I defined to create project.name
for the root artifact is company-${project.artifactId}
and for the modules and sub-modules is ${project.parent.name}-${project.artifactId}
:
- company-any-artifact-any-module1
- company-any-artifact-any-module2-any-submodule1
- company-any-artifact-any-module2-any-submodule2
The pattern for project.build.finalName
is ${project.name}-${project.version}
:
- company-any-artifact-any-module1-1.0.jar
- company-any-artifact-any-module2-any-submodule1-2.0.jar
- company-any-artifact-any-module2-any-submodule2-3.0.war
But instead of producing these files, maven gives me a StackOverflowError
.
2. The example to reproduce the error
You can clone this example from github: https://github.com/pauloleitemoreira/company-any-artifact
In github, there is the master
branch, that will reproduce this error. And there is only-modules
branch, that is a working example that uses ${project.parent.name}
to generate the jar finalName
as I want.
Let's consider a maven project with one root pom artifact, one pom module and one submodule.
-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. Problem
When try to mvn clean install
, maven gives me a 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)
It is important to know that the error occurs only when we are working with submodules. If we create a project with a root POM artifact and a jar module, the error don't occur.
4. The question
Why this error occurs only when we are using submodules?
Any suggestion to solve my problem? Should I forget it and set project.name
and project.build.fileName
manually for each project, following the pattern I want?
IMPORTANT UPDATED:
Some answers just say to use &{parent.name}
, but it does not work. Please, it is a question with a bounty, consider test your solution with Maven version 3.3.9
, before answering this question.
Maven version 3.3.9
Edit - Adding details to the question with the phase when the error occurs, things are working fine until the prepare-package
phase, but the StackOverflow occurs at the package
phase on maven lifecycle for the project.
The strict answer to your question is that ${project.parent.name}
will not be resolved as part the model interpolation process. And in turn, you have a StackOverflowError
, in a completely different place of the code, namely when... building the final JAR of your project.
Part 1: The Model built is wrong
Here's what happens. When you're launching a Maven command on a project, the first action it takes is creating the effective model of the project. This means reading your POM file, reasoning with activated profiles, applying inheritance, performing interpolation on properties... all of this to build the final Maven model for your project. This work is done by the Maven Model Builder component.
The process of building the model is quite complicated, with a lot of steps divided in possibly 2 phases, but the part we're interested in here in the model interpolation part. This is when Maven will replace in the model all tokens denoted by ${...}
with a calculated value. It happens after profiles are injected, and inheritance is performed. At that point in time, the Maven project, as represented by a MavenProject
object, doesn't exist yet, only its Model
is being built. And it is only after you have a full model that you can start constructing the Maven project from it.
As such, when interpolation is done, it only reasons in terms of the information present in the POM file, and the only valid values are the ones mentioned in the model reference. (This replacement is performed by the StringSearchModelInterpolator
class, if you want to look at the source code.) Quite notably, you will notice that the <parent>
element in the model does not contain the name of the parent model. The class Model
in Maven is actually generated with Modello from a source .mdo
file, and that source only defines groupId
, artifactId
, version
and relativePath
(along with a custom id
) for the <parent>
element. This is also visible in the documentation.
The consequence of all that, is that after model interpolation is performed, the token ${project.parent.name}
will not be replaced. And, further, the MavenProject
constructed from it will have a name containing ${project.parent.name}
unreplaced. You can see this in the logs, in your sample project, we have
[INFO] Reactor Build Order:
[INFO]
[INFO] company-any-artifact
[INFO] ${project.parent.name}-any-module
[INFO] ${project.parent.name}-any-submodule
Meaning that Maven consider the actual name of the project any-module
to be ${project.parent.name}-any-module
.
Part 2: The weirdness begins
We're now at a time when all of the projects in the reactor were correctly created and even compiled. Actually, everything should theoretically work just fine, but with only completely borked names for the projects themselves. But you have a strange case, where it fails at the creation of the JAR with the maven-jar-plugin
. The build fails in your example with the following logs:
[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] ------------------------------------------------------------------------
meaning that something went wrong well after the model was built. And the reason is that the plugin 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;
Notice project.build.finalName
as the default value of the generated JAR name for the submodule. This injection, and the interpolation of the variables are done by another class called PluginParameterExpressionEvaluator
.
So what happens in this:
- The JAR plugin on the
any-submodule
injects the final name of the project, named${project.parent.name}-any-submodule
. - Thanks for inheritance from the parent projects, and the declaration of
<finalName>
in your top-most POM project, it inherits<finalName>${project.name}-${project.version}</finalName>
. - Maven now tries to interpolate
${project.name}
forany-submodule
. - This resolves to
${project.parent.name}-any-submodule
, due to Part 1. - Maven tries now to interpolate
${project.parent.name}
forany-submodule
. This works correctly: theMavenProject
is built andgetParent()
will be called on the project instance, returning the concrete Maven parent project. As such,${project.parent.name}
will try to resolve the name ofany-module
, which is actually${project.parent.name}-any-module
. - Maven now tries to interpolate
${project.parent.name}-any-module
, but still on theany-submodule
project instance. ForPluginParameterExpressionEvaluator
, the root"project"
on which to evaluate tokens hasn't changed. - Maven now tries to interpolate
${project.parent.name}
onany-submodule
, which, again, works correctly and returns${project.parent.name}-any-module
. - Maven now tries to interpolate
${project.parent.name}
onany-submodule
... which works and returns${project.parent.name}-any-module
so it tries to evaluate${project.parent.name}
...
And you can see the endless recursion happening here, which results in the StackOverflowError
you have. Is this a bug in PluginParameterExpressionEvaluator
? This is unclear: it reasons on model values that were not correctly replaced in the first place. In theory, it could handle the special case of evaluating ${project.parent}
and create a new PluginParameterExpressionEvaluator
working on this parent project, instead of always working on the current project. If you feel strongly about this, feel free to create a JIRA issue.
Part 3: Why it works without the sub module
With what has been said above, you could now deduce why it works in this case. Let's reason with what Maven needs to do to evaluate the final name, as has to be injected in the Maven Jar Plugin:
- The JAR plugin on the
any-module
injects the final name of the project, named${project.parent.name}-any-module
. - Thanks for inheritance from the parent project, and the declaration of
<finalName>
in your top-most POM project, it inherits<finalName>${project.name}-${project.version}</finalName>
. - Maven now tries to interpolate
${project.name}
forany-module
. - This resolves to
${project.parent.name}-any-module
, same as before. - Maven tries now to interpolate
${project.parent.name}
forany-module
. Just like before, this works correctly: theMavenProject
is built andgetParent()
will be called on the project instance, returning the concrete Maven parent project. As such,${project.parent.name}
will try to resolve the name ofany-artifact
, which is actuallycompany-any-artifact
. - Interpolation has succeeded and stops.
And you don't have any errors.
这篇关于具有显式finalName的Maven无法正常工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!