更新时间:2022-10-14 23:09:37
对您问题的严格回答是,${project.parent.name}
将不作为模型插值过程的一部分进行解析.反过来,您有一个***Error
,位于代码的完全不同的位置,即在……构建项目的最终JAR时.
这就是发生的情况.在项目上启动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
.
我们现在是正确创建甚至编译反应堆中所有项目的时候.实际上,理论上所有内容都可以正常工作,但项目本身的名称完全不正确.但是,您遇到了一个奇怪的情况,在使用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}
... ***Error
.这是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}
:
The pattern for project.build.finalName
is ${project.name}-${project.version}
:
But instead of producing these files, maven gives me a ***Error
.
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 *** 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 ***Error
:
Exception in thread "main" java.lang.***Error
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 *** 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 ***Error
, in a completely different place of the code, namely when... building the final JAR of your project.
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
.
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:
any-submodule
injects the final name of the project, named ${project.parent.name}-any-submodule
.<finalName>
in your top-most POM project, it inherits <finalName>${project.name}-${project.version}</finalName>
.${project.name}
for any-submodule
.${project.parent.name}-any-submodule
, due to Part 1.${project.parent.name}
for any-submodule
. This works correctly: the MavenProject
is built and getParent()
will be called on the project instance, returning the concrete Maven parent project. As such, ${project.parent.name}
will try to resolve the name of any-module
, which is actually ${project.parent.name}-any-module
.${project.parent.name}-any-module
, but still on the any-submodule
project instance. For PluginParameterExpressionEvaluator
, the root "project"
on which to evaluate tokens hasn't changed.${project.parent.name}
on any-submodule
, which, again, works correctly and returns ${project.parent.name}-any-module
.${project.parent.name}
on any-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 ***Error
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.
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:
any-module
injects the final name of the project, named ${project.parent.name}-any-module
.<finalName>
in your top-most POM project, it inherits <finalName>${project.name}-${project.version}</finalName>
.${project.name}
for any-module
.${project.parent.name}-any-module
, same as before.${project.parent.name}
for any-module
. Just like before, this works correctly: the MavenProject
is built and getParent()
will be called on the project instance, returning the concrete Maven parent project. As such, ${project.parent.name}
will try to resolve the name of any-artifact
, which is actually company-any-artifact
.And you don't have any errors.