Supplementing Missing POM Information

Note: This feature was added in version 1.0-alpha-5.

One of Maven's great strengths is that it allows you, the user, to build directly on the work of others with minimal effort. For instance, by adding five lines (or less) to your POM, you can declare a dependency on someone else's library, and instruct Maven to use that library during the build for your own project. Since the library's JAR is usually accompanied by a POM of its own, your project doesn't need to provide an exhaustive listing of all libraries used by all of your direct dependencies.

However, this approach of reusing POM metadata from your dependencies can be inhibited by a dependency POM that provides less-than-complete information about its project. While most POMs provide reasonably accurate information about their dependencies, they sometimes leave out some information critical to assembling licensing and dependency notice files.

For example, the templates used by many Apache distributions assemble a listing of project dependencies according to their organization name (and URL), along with the URL each project's website. When dependency POMs are missing this information, the dependency notice file that the Remote Resources Plugin renders can be invalid.

To compensate for incomplete dependency POMs, you can use the supplemental models support, introduced to the Remote Resources Plugin in version 1.0-alpha-5, and improved in version 1.1.

Fixing Incomplete POMs: Using Supplemental Models

For those cases where your project's dependencies don't list organization name, organization URL, project URL, or whatever other metadata you require for you legal notice files, the Remote Resources Plugin allows you to configure a series of supplemental models. These models consist of one or more model files, each of which contains one or more POM fragments that can be merged into existing dependency POMs to supplement the metadata provided there. The plugin uses the key groupId:artifactId to match each supplemental model with the dependency POM into which it should be merged.

For example, imagine that your project's POM has declared the following two dependencies:

    <dependency>
      <groupId>org.foo</groupId>
      <artifactId>missing-org-info</artifactId>
      <version>1</version>
    </dependency>
    <dependency>
      <groupId>org.foo</groupId>
      <artifactId>missing-project-url</artifactId>
      <version>1</version>
    </dependency>

Now imagine that your project needs to include a file in its distribution that lists organization and project URLs for each dependency, in a format like this:

From: Apache Software Foundation (http://www.apache.org/)

 - Commons FOO (http://commons.apache.org/foo/) org.apache.commons.foo:foo:1
 - Commons BAR (http://commons.apache.org/bar/) org.apache.commons.bar:bar:1

However, as you try generating these licensing resources for your project, you quickly learn that your dependencies provide POMs that don't always include all the information needed by this format. The first dependency is missing all of the information provided by the organization element of the POM, and the second is missing a project- specific URL (the url element of the POM).

To fix these omissions for the purposes of resource generation, we can simply provide a supplemental-model file that contains the missing information. The file, located at src/main/appended-resources/supplemental-models.xml, would look something like this:

<?xml version="1.0" encoding="UTF-8"?>
<supplementalDataModels xmlns="http://maven.apache.org/supplemental-model/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                        xsi:schemaLocation="http://maven.apache.org/supplemental-model/1.0.0 https://maven.apache.org/xsd/supplemental-model-1.0.0.xsd">
  <supplement>
    <project>
      <groupId>org.foo</groupId>
      <artifactId>missing-org-info</artifactId>
      
      <organization>
        <name>FOO, Inc.</name>
        <url>http://www.foo.org/</url>
      </organization>
    </project>
  </supplement>
  <supplement>
    <project>
      <groupId>org.foo</groupId>
      <artifactId>missing-project-url</artifactId>
      
      <url>http://www.foo.org/projects/missing-project-url/</url>
    </project>
  </supplement>
</supplementalDataModels>

Finally, we tell the Remote Resources Plugin to use the new supplemental-model file:

      <plugin>
        <artifactId>maven-remote-resources-plugin</artifactId>
        <version>3.2.0</version>
        <executions>
          <execution>
            <id>process-remote-resources</id>
            <goals>
              <goal>process</goal>
            </goals>
            <configuration>
              <supplementalModels>
                <supplementalModel>supplemental-models.xml</supplementalModel>
              </supplementalModels>
              [...]
            </configuration>
          </execution>
        </executions>
      </plugin>

After re-running the project build, the supplemental information we provided will be merged with the metadata from the dependency POMs, providing enough information to complete the dependencies listing.

Publishing and Reusing Supplemental Models

Note: This feature was added in version 1.1.

The configuration above is fine for single projects that need to address deficiencies in their dependencies' metadata. But what happens when your organization wants to use these same deficient dependencies across multiple projects? The configuration we just examined cannot handle reuse of supplemental-model files.

To address this shortcoming, version 1.1 of the Remote Resources Plugin introduces a new parameter: supplementalModelArtifacts. When combined with the supplementalModels parameter used above, this new parameter allows the Remote Resources Plugin to resolve artifacts containing supplemental model information, then search those artifacts for the paths given in the supplementalModels listing.

To make the supplemental models above reusable using this mechanism, we first publish them in their own project:

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  
  <groupId>org.myco</groupId>
  <artifactId>dependency-resource-supplement</artifactId>
  <version>1</version>
</project>

Note that this is just a simple, unadorned JAR artifact. We then move the above POM and supplemental-models.xml file into a separate project directory structure:

|-- pom.xml
`-- src
    `-- main
        `-- resources
            `-- supplemental-models.xml

Once we install this new project, we can reference it from the configuration for the Remote Resources Plugin, like this:

      <plugin>
        <artifactId>maven-remote-resources-plugin</artifactId>
        <version>3.2.0</version>
        <executions>
          <execution>
            <id>process-remote-resources</id>
            <goals>
              <goal>process</goal>
            </goals>
            <configuration>
              <!-- Reference the supplemental-model artifact from above -->
              <supplementalModelArtifacts>
                <supplementalModelArtifact>org.myco:dependency-resource-supplement:1</supplementalModelArtifact>
              </supplementalModelArtifacts>

              <!-- Specify the path, relative to the JAR root, where the supplemental model file is located -->
              <supplementalModels>
                <supplementalModel>supplemental-models.xml</supplementalModel>
              </supplementalModels>
              [...]
            </configuration>
          </execution>
        </executions>
      </plugin>

Once the supplemental-model project is released and deployed, any number of projects can then make use of the supplemental information it provides.