Difference between project.parent.name and parent.

2019-07-19 10:33发布

问题:

Research on the thread Maven with an explicit finalName won't work properly. I am left wondering with -

Question 1 - What is the difference between project.parent.attribute and parent.attribute in maven's pom.xml?

Currently using Maven 3.3.9 along with intellJ as IDE all I get to see is both the properties navigate to the same attribute. Also a thought to the fact that

<project> is the root of the descriptor.

for defining any pom.xml, in which case project.parent.* shall be equivalent to parent.* for a module.

Question 2 - If the above explanation is justified, then does the finalName attribute overrides the <name> attribute of a parent when called by its child module pom.xml?

Question 3 - What is the value of ${project.name} in the finalName of a parent module? Is it the name of the parent OR the name of the innermost [packaged as jar, war etc] child?

回答1:

Edit: expanded answer with links / examples

Question 1

project.parent.attribute is the correct way to access parent project properties. parent.attribute points to the same value, but is deprecated (which Maven 3.3+ does clearly complain about at the beginning of the build)

(see Model Builder, which states that * and pom.* access is deprecated)

Question 2

name and finalName are completely unrelated. name is a clear text name of the project (and is one of the few elements never inherited by child projects), finalName is the name of the artifact file.

as stated in 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.

So these two have different uses.

  • name is purely informational and mainly used for generated documentation and in the build logs. It is not inherited nor used anywhere else. It is a human readable String and can thus contain any character, i.e. spaces or characters not allowed in filenames. So, this would be valid: <name>My Turbo Project on Speed!</name>. Which is clearly at least a questionable file name for an artifact.

  • as stated above, finalName is the name of the generated artifact. It is inherited, so it should usually rely on properties. The only two really useful options are the default ${artifactId}-${version} and the versionless ${artifactId}. Everything else leads to confusion (such as a project named foo creating an artifact bar.jar). Actually, My turbo Project! would be valid, since this is a valid filename, but in reality, filenames like that tend to be rather unusable (try adressing a filename containing ! from a bash, for example)

Question 3

In the resolution of the pom, first all parents are applied in order, and only then properties are resolved (always against the current project). So the name would be the name of the innermost child (however, see above: do not use project.name, as it might contain spaces and other illegal characters)

see Model Builder for more details, the relevant steps here are marked bold:

  • 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)

So given two files (only relevant parts):

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>

The steps are performed in the following order (only the two important steps):

  • create a "generational pom" containing the contents of all poms up to the super pom:

Generational 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>

Not that the generational pom still only contains the properties, not there values.

Finally, in Model interpolation, the properties are resolved. In this step, the parent pom is not used anymore, after the previous step, everything is ONLY done on the (generational) model of the current project:

Effective 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>

Generally spoken, finalName should be used with care. It can be useful to remove the version in the locally generated artifact to make testing in a local container easier (${project.artifactId} instead of the default ${project.artifactId}-${project.version}), but I strongly advise against using anything else, because the uploaded artifact (to the repository) will have the original artifactId as filename anyway, and it might confuse to have to different names for the same file.