Skip to content

ning/maven-duplicate-finder-plugin

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

81 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Maven duplicate finder plugin

** PLUGIN HAS MOVED **

Starting with version 1.1.0, the duplicate finder plugin has moved.

Please contribute any pull requests, but reports etc. to the the new location.

** PLUGIN HAS MOVED **

Major changes from Version 1.0.x

Starting with version 1.1.0 of the duplicate finder plugin, Maven 3.x and Java 6 or better are required.

Also, the plugin artifact id has been changed to duplicate-finder-maven-plugin as is required with Maven 3.x (and probably enforced at some point).

If upgrading to version 1.1.0 or newer is not possible, use

<plugin>
  <groupId>com.ning.maven.plugins</groupId>
  <artifactId>maven-duplicate-finder-plugin</artifactId>
  <version>1.0.8</version>
</plugin>

What is it

The duplicate-finder-maven-plugin is a plugin that will search for classes with the same name, as well as resources with the same path, in the classpaths of a maven project. More specifically, it will check the compile, runtime, and test classpaths for

  • Classes with the same qualified name in the current project and all dependencies relevant for that classpath
  • Files that are not class files, with the same resource path (i.e. as if it would be accessed via the classloader) in the current project and all dependencies relevant for that classpath (Note that at the moment, the plugin does not check if the files are actually the same or not, it only looks for the same file/class name.)

How to use it

Configuration

To make commandline usage a bit easier, you should add the com.ning.maven.plugins group to the pluginGroups section in your settings file:

<settings>
  ...
  <pluginGroups>
    <pluginGroup>com.ning.maven.plugins</pluginGroup>
  </pluginGroups>
  ...
</settings>

Running it

Usually, the plugin does not need to be configured in the POM. You can simply execute it via maven command line in a directory that contains a POM (which can be a multi-module POM):

mvn duplicate-finder:check

This will check for the latest version of the plugin, download it if necessary, and then execute it. Note that you might get snapshot versions this way. You can also run a specific version using the fully qualified plugin identifier:

    mvn com.ning.maven.plugins:duplicate-finder-maven-plugin:1.1.0:check

If you want to include it in the normal build, configure it like this:

<plugin>
  <groupId>com.ning.maven.plugins</groupId>
  <artifactId>duplicate-finder-maven-plugin</artifactId>
  <executions>
    <execution>
      <phase>verify</phase>
      <goals>
        <goal>check</goal>
      </goals>
    </execution>
  </executions>
</plugin>

A successful run will look like this:

[INFO] [duplicate-finder:check {execution: default-cli}]
[INFO] Checking compile classpath
[INFO] Checking runtime classpath
[INFO] Checking test classpath

If you run the plugin on its own source code, you'll instead get something like

[WARNING] Found duplicate and different classes in [commons-logging:commons-logging:1.1.1,commons-logging:commons-logging-api:1.1] :
[WARNING]   org.apache.commons.logging.Log
[WARNING]   org.apache.commons.logging.LogConfigurationException
[WARNING]   org.apache.commons.logging.LogFactory
[WARNING]   org.apache.commons.logging.LogSource
[WARNING]   org.apache.commons.logging.impl.Jdk14Logger
[WARNING]   org.apache.commons.logging.impl.LogFactoryImpl
[WARNING]   org.apache.commons.logging.impl.NoOpLog
[WARNING]   org.apache.commons.logging.impl.SimpleLog
[WARNING]   org.apache.commons.logging.impl.WeakHashtable
[WARNING] Found duplicate and different resources in [org.springframework:spring-aop:3.0.3.RELEASE,org.springframework:spring-beans:3.0.3.RELEASE,org.springframework:spring-context:3.0.3.RELEASE,org.springframework:spring-core:3.0.3.RELEASE] :
[WARNING]   overview.html
[WARNING] Found duplicate and different resources in [org.springframework:spring-aop:3.0.3.RELEASE,org.springframework:spring-beans:3.0.3.RELEASE,org.springframework:spring-context:3.0.3.RELEASE] :
[WARNING]   META-INF/spring.tooling

The above example shows a duplicate resource and a duplicate class in the current POM. In either case, it will print the qualified names of all artifacts that have these classes/resources - this includes the current project. To make the output a bit easier to read, all duplicate classes are grouped by the set of artifacts that have it. E.g. in the example, the org.apache.commons.logging.* classes are all found in two particular artifacts, so they are all combined in one group.

The plugin can also be configured to fail the build (see below), in which case it will print an additional

[ERROR] Found duplicate classes/resources

Configuring it

In some cases you need to configure the plugin to make exceptions, i.e. allow duplicate classes or resources for specific artifacts. For instance, multiple dependencies might contain base XML classes in the javax.xml and org.w3c packages. If you are sure that these are the same and thus the duplication can be ignored, you can define exceptions like this:

<plugin>
  <groupId>com.ning.maven.plugins</groupId>
  <artifactId>duplicate-finder-maven-plugin</artifactId>
  <version>1.1.0</version>
  <configuration>
    <exceptions>
      <exception>
        <conflictingDependencies>
          <dependency>
            <groupId>jaxen</groupId>
            <artifactId>jaxen</artifactId>
            <version>1.1.1</version>
          </dependency>
          <dependency>
            <groupId>xml-apis</groupId>
            <artifactId>xml-apis</artifactId>
            <version>[1.3.02,1.3.03]</version>
          </dependency>
        </conflictingDependencies>
        <classes>
          <class>org.w3c.dom.UserDataHandler</class>
        </classes>
      </exception>
      <exception>
        <conflictingDependencies>
          <dependency>
            <groupId>xerces</groupId>
            <artifactId>xercesImpl</artifactId>
            <version>2.6.2</version>
          </dependency>
          <dependency>
            <groupId>xml-apis</groupId>
            <artifactId>xml-apis</artifactId>
            <version>[1.3.02,1.3.03]</version>
          </dependency>
        </conflictingDependencies>
        <packages>
          <package>org.w3c.dom.ls</package>
        </packages>
      </exception>
      <exception>
        <conflictingDependencies>
          <dependency>
            <groupId>xerces</groupId>
            <artifactId>xmlParserAPIs</artifactId>
            <version>2.6.2</version>
          </dependency>
          <dependency>
            <groupId>xml-apis</groupId>
            <artifactId>xml-apis</artifactId>
            <version>[1.3.02,1.3.03]</version>
          </dependency>
          <dependency>
            <groupId>xmlrpc</groupId>
            <artifactId>xmlrpc</artifactId>
            <version>2.0</version>
          </dependency>
        </conflictingDependencies>
        <classes>
          <class>org.apache.xmlcommons.Version</class>
        </classes>
        <packages>
          <package>javax.xml.parsers</package>
          <package>javax.xml.transform</package>
          <package>org.w3c.dom</package>
          <package>org.xml.sax</package>
        </packages>
      </exception>
      <exception>
        <conflictingDependencies>
          <dependency>
            <groupId>stax</groupId>
            <artifactId>stax-api</artifactId>
            <version>1.0.1</version>
          </dependency>
          <dependency>
            <groupId>xml-apis</groupId>
            <artifactId>xml-apis</artifactId>
            <version>[1.3.02,1.3.03]</version>
          </dependency>
        </conflictingDependencies>
        <classes>
          <class>javax.xml.XMLConstants</class>
          <class>javax.xml.namespace.NamespaceContext</class>
          <class>javax.xml.namespace.QName</class>
        </classes>
      </exception>
      <exception>
        <conflictingDependencies>
          <dependency>
            <groupId>xalan</groupId>
            <artifactId>xalan</artifactId>
            <version>2.6.0</version>
          </dependency>
          <dependency>
            <groupId>xml-apis</groupId>
            <artifactId>xml-apis</artifactId>
            <version>[1.3.02,1.3.03]</version>
          </dependency>
        </conflictingDependencies>
        <packages>
          <package>org.w3c.dom.xpath</package>
        </packages>
      </exception>
    </exceptions>
  </configuration>
  <executions>
    <execution>
      <phase>verify</phase>
      <goals>
        <goal>check</goal>
      </goals>
    </execution>
  </executions>
</plugin>

Ignoring dependencies

In some rare cases, you want to completely remove a dependency from the check. For instance, in the above example, it might be better to completely ignore the xml-apis:xml-apis dependencies:

<plugin>
  <groupId>com.ning.maven.plugins</groupId>
  <artifactId>duplicate-finder-maven-plugin</artifactId>
  <version>1.1.0</version>
  <configuration>
    <ignoredDependencies>
      <dependency>
        <groupId>xml-apis</groupId>
        <artifactId>xml-apis</artifactId>
        <version>1.3.02</version>
      </dependency>
      <dependency>
        <groupId>xml-apis</groupId>
        <artifactId>xml-apis</artifactId>
        <version>1.3.03</version>
      </dependency>
    </ignoredDependencies>
    ...
  </configuration>
</plugin>

Please use this only if absolutely necessary!

Allowing classes

<exception>
  <conflictingDependencies>
    <dependency>
      <groupId>xerces</groupId>
      <artifactId>xmlParserAPIs</artifactId>
      <version>2.6.2</version>
    </dependency>
    <dependency>
      <groupId>xml-apis</groupId>
      <artifactId>xml-apis</artifactId>
      <version>[1.3.02,1.3.03]</version>
    </dependency>
    <dependency>
      <groupId>xmlrpc</groupId>
      <artifactId>xmlrpc</artifactId>
      <version>2.0</version>
    </dependency>
  </conflictingDependencies>
  <classes>
    <class>org.apache.xmlcommons.Version</class>
  </classes>
  <packages>
    <package>javax.xml.parsers</package>
    <package>javax.xml.transform</package>
    <package>org.w3c.dom</package>
    <package>org.xml.sax</package>
  </packages>
</exception>

The conflictingDependencies section states the artifacts for which duplicate class conflicts are allowed. Note that in a particular project, not all of these artifacts have to participate. E.g. for the above example, a duplicate class for class org.apache.xmlcommons.Version between artifacts xerces:xmlParserAPIs:2.6.2 and xml-apis:xml-apis:1.3.03 would be matched even if xmlrpc:xmlrpc is not involved.

The version identifier uses the normal Maven version specification.

Please use version ranges only if you are sure that all of these versions are fine.

You can specify the classes via direct class elements (e.g. for org.apache.xmlcommons.Version in the above section), or via packages elements. Note that a <package>org.xml.sax</package> element will match the org.xml.sax package plus all sub packages.

You want to be as exact as possible. Use packages only if necessary, and use the most specific package.

Allowing resources

Adding exceptions for resources works the same way:

<exception>
  <conflictingDependencies>
    ...
  </conflictingDependencies>
  <resources>
    <resource>log4j.xml</resource>
  </resources>
  <resourcePatterns>
    <resourcePattern>files.*</resourcePattern>
  </resourcePatterns>
</exception>

Note that there is no corresponding concept to packages for resources, you'll have to specify each resource individually.

The Resource pattern allows excluding multiple files or pathes by applying regular expressions to the resources in question.

The plugin by default ignores several resources that are frequently found in dependencies. They follow these regular expressions (case-insensitive):

(META-INF/)?ASL2\.0(\.TXT)?
META-INF/DEPENDENCIES(\.TXT)?
META-INF/DISCLAIMER(\.TXT)?
(META-INF/)?[A-Z_-]*LICENSE.*
META-INF/MANIFEST\.MF
META-INF/INDEX\.LIST
META-INF/MAVEN/.*
META-INF/SERVICES/.*,
(META-INF/)?NOTICE(\.TXT)?
README(\.TXT)?
.*PACKAGE\.HTML
.*OVERVIEW\.HTML
META-INF/SPRING\.HANDLERS
META-INF/SPRING\.SCHEMAS
META-INF/SPRING\.TOOLING
.GIT
.SVN
.HG
.BZR

You can turn these default resource exceptions off via the useDefaultResourceIgnoreList configuration option:

<plugin>
  <groupId>com.ning.maven.plugins</groupId>
  <artifactId>duplicate-finder-maven-plugin</artifactId>
  <version>1.1.0</version>
  <configuration>
    <useDefaultResourceIgnoreList>false</useDefaultResourceIgnoreList>
    ...
  </configuration>
</plugin>

Globally ignoring additional resources

It is possible to specify additional resources on the classpath that are excluded from the duplication check:

<ignoredResources>
  <ignoredResource>overview\.html</ignoredResource>
</ignoredResources>

will ignore all occurences of overview.html on the classpath. This is useful for resources that are present in many dependencies.

The resource definition is a pattern as consumed by java.util.regex.Pattern.

Failing the build

By default, the plugin will only print warning. However, you can configure it to fail the build using the failBuildInCaseOfConflict configuration option:

<plugin>
  <groupId>com.ning.maven.plugins</groupId>
  <artifactId>duplicate-finder-maven-plugin</artifactId>
  <configuration>
    <failBuildInCaseOfConflict>true</failBuildInCaseOfConflict>
    ...
  </configuration>
</plugin>

This will fail the build even in case of duplicate but identical classes/resources (as per their SHA256). If you don't want that, then use these two for more fine-grained control:

<failBuildInCaseOfDifferentContentConflict>true</failBuildInCaseOfDifferentContentConflict>
<failBuildInCaseOfEqualContentConflict>false</failBuildInCaseOfEqualContentConflict>

Verbose output

By default the plugin will not print duplicate but identical classes/resources (as per SHA256). If you want to see those classes/resources, add this configuration option:

<printEqualFiles>true</printEqualFiles>

Note that this flag is ignored if either failBuildInCaseOfConflict or failBuildInCaseOfEqualContentConflict are set to true.

License

(C) 2010 Ning, Inc.

Licensed under the Apache Software License, Version 2.0. For details see the COPYING file.