Fork me on GitHub

Managing exceptions is an important aspect for the duplicate finder plugin. Often, third-party dependencies, that can not be changed have conflicts or include classes and resources that are duplicate with other classpath elements.

The duplicate finder plugin allows listing and excluding these conflicts.

<configuration>
    <exceptions>
        <exception>
            <conflictingDependencies>
                <dependency>
                    <artifactId>...</artifactId>
                    <groupId>...</groupId>
                    <version>...</version>
                    <type>...</type>
                    <classifier>...</classifier>
                </dependency>
                ...
            </conflictingDependencies>
            <currentProject>false</currentProject>

            <!-- Version 1.1.1+, removed in 2.0.0 -->
            <bootClasspath>false</bootClasspath>
            <!-- Version 1.1.1+, removed in 2.0.0 -->

            <resourcePatterns>
                <resourcePattern>...</resourcePattern>
            </resourcePatterns>
            <classes>
                <class>...</class>
            </classes>
            <packages>
                <package>...</package>
            </packages>
            <resources>
                <resource>...</resource>
            </resources>
        </exception>
    </exceptions>
</configuration>

Exception overview

Within the plugin configuration, one or more exceptions can be listed in the <exceptions> element. Each exception is applied to all classpath scopes (compile, runtime and test).

Each exception lists its conflicting dependencies in the conflictingDependencies element and then optionally the specific conflicting classes and resources. Any conflict covered by an exception will not be reported or fail the build.

If an exception only contains a conflictingDependencies element (no classes, packages, resources or resourcePatterns), any duplicate between all the listed dependencies is ignored. If any of these elements is present, only the listed classes or resources will be ignored.

Warning! The presence of any of these elements will turn off the wildcard behavior of an exception. Especially the presence of a classes or packages element will also turn off the wildcard behavior for resources and the presence of a resources or resourcePatterns element will turn off the wildcard behavior for classes. This was undefined in previous versions of the duplicate finder plugin.

The conflictingDependencies element

The conflictingDependencies element lists all artifacts considered for an exception as dependency elements. Each dependency can be fully or partially defined.

The currentProject flag

The currentProject flag signals that the current project should be added to the exception as a dependency. Any resource or class that is duplicate between the current project and the listed dependencies will be ignored.

The option is equivalent to having the current project listed as a dependency in the conflictingDependencies element.

If the conflictingDependencies element already contains a dependency for the current project, the flag has no effect.

Warning! This flag can lead to surprising behavior, especially if it is used in the root POM of a multi-module build or a parent pom. The ‘current project’ is evaluated at runtime and in a multi-module build it will be applied each time when the plugin is executed on a sub-project. It is recommended to use this flag specifically in the project POM where conflicts are expected.

Examples

In a mult-module build with two sub-projects, sub-project sub-project-a has a conflict with commons-lang:commons-lang and sub-project-b has a conflict with commons-collections:commons-collections. It would be possible to configure the duplicate finder plugin to ignore these by adding exceptions to the project root POM:

<project>
  <modules>
    <module>sub-project-a</module>
    <module>sub-project-b</module>
  </modules>

  <build>
    <plugins>
      <plugin>
        <groupId>org.basepom.maven</groupId>
        <artifactId>duplicate-finder-maven-plugin</artifactId>
        <configuration>
          <exceptions>
            <exception>
              <currentProject>true</currentProject>
              <conflictingDependencies>
                <dependency>
                  <groupId>commons-lang</groupId>
                  <artifactId>commons-lang</artifactId>
                </dependency>
              </conflictingDependencies>
            </exception>
            <exception>
              <currentProject>true</currentProject>
              <conflictingDependencies>
                <dependency>
                  <groupId>commons-collections</groupId>
                  <artifactId>commons-collections</artifactId>
                </dependency>
              </conflictingDependencies>
            </exception>
          </exceptions>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

In this case, each of the sub projects (sub-project-a and sub-project-b) will have any possible conflicts to commons-lang:commons-lang and commons-collections:commons-collections excluded. However, this would also exclude possible conflicts between sub-project-a and commons-collections:commons-collections or sub-project-b and commons-lang:commons-lang even though each probably should have been flagged.

A better way to solve this is moving the exceptions to the actual sub-project POMs:

Root POM:

<project>
  <modules>
    <module>sub-project-a</module>
    <module>sub-project-b</module>
  </modules>

  <build>
    <pluginManagement>
      <plugins>
        <plugin>
          <groupId>org.basepom.maven</groupId>
          <artifactId>duplicate-finder-maven-plugin</artifactId>
        </plugin>
      </plugins>
    </pluginManagement>
  </build>
</project>

Sub-project POM sub-project-a:

<project>
  <build>
    <plugins>
      <plugin>
        <groupId>org.basepom.maven</groupId>
        <artifactId>duplicate-finder-maven-plugin</artifactId>
        <configuration>
          <exceptions>
            <exception>
              <currentProject>true</currentProject>
              <conflictingDependencies>
                <dependency>
                  <groupId>commons-lang</groupId>
                  <artifactId>commons-lang</artifactId>
                </dependency>
              </conflictingDependencies>
            </exception>
          </exceptions>
        </configuration>
      </plugin>
    </plugins>
    </build>
</project>

Sub-project POM sub-project-b:

<project>
  <build>
    <plugins>
      <plugin>
        <groupId>org.basepom.maven</groupId>
        <artifactId>duplicate-finder-maven-plugin</artifactId>
        <configuration>
          <exceptions>
            <exception>
              <currentProject>true</currentProject>
              <conflictingDependencies>
                <dependency>
                  <groupId>commons-collections</groupId>
                  <artifactId>commons-collections</artifactId>
                </dependency>
              </conflictingDependencies>
            </exception>
          </exceptions>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

Now, sub-project-a will have its conflicts with commons-lang:commons-lang excluded and sub-project-b will have its conflicts with commons-collections:commons-collections excluded while any other conflict will still be flagged correctly.

The bootClasspath flag

** Available in plugin version 1.1.1, removed in 2.0.0! **

This flag only works up to JDK 8! As 2.0.0 no longer supports JDK 8, it was deprecated.

The bootClasspath flag signals that an exception to elements on the boot classpath is defined. Any match between classes or resources in the listed artifacts and the boot classpath elements is ignored.

This flag can be combined with the currentProject flag.

<exception>
    <currentProject>false</currentProject>
    <bootClasspath>false</bootClasspath>
</exception>

will ignore any conflict between classes and resources in the current project and the boot classpath.

Managing class exceptions with classes and packages

The classes and packages elements control which classes are ignored by the duplicate finder plugin when determining conflicts.

Specific classes are listed as fully-qualified names in the classes element and full packages are listed in the packages element. Any package listed will match any class in that package and any sub-package. This is a very powerful mechanism and it should be used with care.

Examples

Exclude a set of classes that are copied around into different jars:

<exception>
  <conflictingDependencies>
    <dependency>
      <groupId>commons-beanutils</groupId>
      <artifactId>commons-beanutils</artifactId>
    </dependency>
    <dependency>
      <groupId>commons-beanutils</groupId>
      <artifactId>commons-beanutils-core</artifactId>
    </dependency>
    <dependency>
      <groupId>commons-collections</groupId>
      <artifactId>commons-collections</artifactId>
    </dependency>
  </conflictingDependencies>
    <!-- Well done, Apache! -->
  <classes>
    <class>org.apache.commons.collections.ArrayStack</class>
    <class>org.apache.commons.collections.Buffer</class>
    <class>org.apache.commons.collections.BufferUnderflowException</class>
    <class>org.apache.commons.collections.FastHashMap</class>
  </classes>
</exception>

Exclude a package that was copied into a jar:

<exception>
  <conflictingDependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>(,4.11)</version>
    </dependency>
    <dependency>
      <groupId>org.hamcrest</groupId>
      <artifactId>hamcrest-core</artifactId>
    </dependency>
  </conflictingDependencies>
  <packages>
    <package>org.hamcrest</package>
  </packages>
</exception>

Manging resource exceptions with resources and resourcePatterns

The resources and resourcePatterns elements control which resources are ignored. Similar to the class elements classes and packages, resource lists single resource elements and resourcePatterns can match one or many resources.

A specific resource is listed with its full path in the resources element. Any resource listed should be fully qualfied and start with a /. For backwards compatibility, relative resource names (without a leading /) are accepted but internally treated like absolute resource names.

The resourcePatterns element accepts any standard Java regular expression. Resource names are matched against these expressions. If relative matching is not desired, a pattern must be anchored with either a a start anchor (^) or an end anchor ($).

Examples

Exclude a specific resource that is duplicate in the Jersey jars:

<exception>
  <conflictingDependencies>
    <dependency>
      <groupId>com.sun.jersey</groupId>
      <artifactId>jersey-core</artifactId>
    </dependency>
    <dependency>
      <groupId>com.sun.jersey</groupId>
      <artifactId>jersey-client</artifactId>
    </dependency>
    <dependency>
      <groupId>com.sun.jersey</groupId>
      <artifactId>jersey-server</artifactId>
    </dependency>
  </conflictingDependencies>
  <resources>
    <resource>/META-INF/jersey-module-version</resource>
  </resources>
</exception>