Odd maven model resolution

This article describes odd behavior of Maven when interpreting URL properties of POM files. When inheritance is involved, the default behavior is to append the artifactId to the parent project's URL which leads to unexpected results.

POM hierarchies

Maven artifacts are described in [Project Object Models (POM)] (https://maven.apache.org/guides/introduction/introduction-to-the-pom.html). A POM is an XML document named pom.xml that describes the properties of an artifact such as its name, description, dependencies and so on. It is very common that these files are organized hierarchically, i.e. properties can be inherited from a parent POM. As a result, properties shared by related projects can be defined in a central place to avoid redundancy.

For example, here's an excerpt from Guava's pom.xml:

<parent>
    <groupId>com.google.guava</groupId>
    <artifactId>guava-parent</artifactId>
    <version>19.0</version>
</parent>

We can see that the parent of guava is a project called guava-parent. That parent project has its own pom.xml:

<parent>
    <groupId>org.sonatype.oss</groupId>
    <artifactId>oss-parent</artifactId>
    <version>7</version>
</parent>

As we can see, that project is in turn a child of an artifact called org.sonatype.oss:oss-parent with yet another pom.xml.

Inheritance

Properties can be declared in one POM and then be overwritten by child POMs. For example, guava-parent defines a name property:

<name>Guava Maven Parent</name>

which is overwritten by guava:

<name>Guava: Google Core Libraries for Java</name>

Similarly, guava-parent declares a version attribute:

<version>19.0</version>

which is actually inherited by guava.

Where it becomes odd

Makes sense so far. Where it becomes weird is the inheritance of URLs. One could think that URLs are simply inherited as other properties like the version are. Wrong. For example the guava-parent declares a url property that points to the project's GitHub page:

<url>https://github.com/google/guava</url>

The guava project does not overwrite the url property and it gets inherited. However the property is not simply copied. Instead Maven appends the artifactId to the URL, resulting in this effective URL:

<url>https://github.com/google/guava/guava</url>

which leads nowhere. This produces broken links in many projects.

That behavior is documented in the Model's getUrl() method contained in the Maven Model library:

public String getUrl()
    Get the URL to the project's homepage.
    Default value is: parent value path [+ adjustment ] + artifactId.

Apparently, few people except the original authors of that library know about this concatenation of URL properties. They however are using it properly: Most artifacts in the group org.apache.maven seem to be configured properly, at least in the most recent version.

For example the Maven Model Builder's parent is Apache Maven whose URL points to http://maven.apache.org/ref/3.3.9/. When appending the artifactId of the Maven Model Builder (i.e. maven-model-builder), the URL still points to an existing document: http://maven.apache.org/ref/3.3.9/maven-model-builder.