project.parent.name 和 parent.name 之间的区别以及在 pom.xml 中使用 finalName

Difference between project.parent.name and parent.name ans use of finalName in pom.xml

对线程的研究 。我想知道 -

问题1 - maven的[=15=中project.parent.attributeparent.attribute有什么区别]?

目前使用 Maven 3.3.9 和 intellJ 作为 IDE 我所看到的只是这两个属性都导航到同一个属性。还想到

<project> is the root of the descriptor.

用于定义任何 pom.xml,在这种情况下,project.parent.* 应等同于模块的 parent.*

问题2 - 如果上述解释成立,那么finalName属性是否覆盖<name> 由其子模块调用时父项的属性 pom.xml?

问题 3 - 父模块的 finalName 中的 ${project.name} 的值是多少?它是父级的 name 还是最里面 [打包为 jarwar 等] 子级的 name

编辑: 带有链接/示例的扩展答案

问题 1

project.parent.attribute 是访问 parent 项目属性的正确方法。 parent.attribute 指向相同的值,但已弃用(Maven 3.3+ 确实在构建开始时明确抱怨)

(参见 Model Builder,其中声明 *pom.* 访问权限已弃用)

问题 2

namefinalName 完全无关。 name 是项目的明文名称(并且是 child 项目从未继承的少数元素之一),finalName 是工件文件的名称。

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 中寻址包含 ! 的文件名)

问题 3

在pom的解析中,首先按顺序应用所有parent,然后才解析属性(总是针对当前项目)。所以名称将是最里面的名称 child(但是,见上文:不要使用 project.name,因为它可能包含空格和其他非法字符)

详见Model Builder,此处相关步骤已加粗加粗:

  • phase 1
    • profile activation: see available activators. Notice that model interpolation hasn't happened yet, then interpolation for file-based activation is limited to ${basedir} (since Maven 3), System properties and request properties
    • raw model validation: ModelValidator (javadoc), with its DefaultModelValidator implementation (source)
      • model normalization - merge duplicates: ModelNormalizer (javadoc), with its DefaultModelNormalizer implementation (source)
      • profile injection: ProfileInjector (javadoc), with its DefaultProfileInjector implementation (source)
      • parent resolution until super-pom
      • inheritance assembly: InheritanceAssembler (javadoc), with its DefaultInheritanceAssembler implementation (source). Notice that project.url, project.scm.connection, project.scm.developerConnection, project.scm.url and project.distributionManagement.site.url have a special treatment: if not overridden in child, the default value is parent's one with child artifact id appended
      • model interpolation (see below)
      • url normalization: UrlNormalizer (javadoc), with its DefaultUrlNormalizer implementation (source)

所以给出两个文件(只有相关部分):

parent

<artifactId>parent</artifactId>

<name>Parent Project</name>

<properties>
  <myProp>in-parent</myProp>
</properties>

<build>
  <finalName>${project.artifactId}-${myProp}</finalName>
</build>

child

<parent>
    <artifactId>parent</artifactId>
</parent>
<artifactId>child</artifactId>

<properties>
  <myProp>in-child</myProp>
</properties>

步骤按以下顺序执行(只有两个重要步骤):

  • 创建一个 "generational pom" 包含所有 pom 的内容直到超级 pom:

代 POM

<parent>
    <artifactId>parent</artifactId>
</parent>
<artifactId>child</artifactId> <!-- artifact id is never inherited -->

<!-- name is NOT inherited, so no name for child -->

<properties>
  <myProp>in-child</myProp> <!-- from child -->
</properties>

<build> <!-- inherited from parent -->
  <finalName>${project.artifactId}-${myProp}</finalName>
</build>

并不是说世代 pom 仍然只包含属性,没有值。

最后,在模型插值中,属性被解析。在这一步中,不再使用 parent pom,在上一步之后,一切都只在当前项目的(世代)模型上完成:

有效 POM

<parent>
    <artifactId>parent</artifactId>
</parent>
<artifactId>child</artifactId> <!-- artifact id is never inherited -->

<!-- name is NOT inherited, so no name for child -->

<properties>
  <myProp>in-child</myProp> <!-- from child -->
</properties>

<build> <!-- inherited from parent -->
  <finalName>child-in-child</finalName> <!-- resolved against generational pom -->
</build>

一般来说,finalName要谨慎使用。删除本地生成的工件中的版本以使本地容器中的测试更容易(${project.artifactId} 而不是默认的 ${project.artifactId}-${project.version})可能很有用,但我强烈建议不要使用其他任何东西,因为上传的artifact(到存储库)无论如何都会将原始 artifactId 作为文件名,并且可能会混淆同一文件的不同名称。