The maven-duplicate-finder-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.)
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>
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:maven-duplicate-finder-plugin:1.0.2:check
If you want to include it in the normal build, configure it like this:
<plugin> <groupId>com.ning.maven.plugins</groupId> <artifactId>maven-duplicate-finder-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 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 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 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
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>maven-duplicate-finder-plugin</artifactId> <version>1.0.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>
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>maven-duplicate-finder-plugin</artifactId> <version>1.0.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!
<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.
Adding exceptions for resources works the same way:
<exception> <conflictingDependencies> ... </conflictingDependencies> <resources> <resource>log4j.xml</resource> </resources> </exception>
Note that there is no corresponding concept to packages for resources, you’ll have to specify each resource individually.
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>maven-duplicate-finder-plugin</artifactId> <version>1.0.0</version> <configuration> <useDefaultResourceIgnoreList>false</useDefaultResourceIgnoreList> ... </configuration> </plugin>
It is possible to specify additional resources on the classpath that are excluded from the duplication check:
<ignoredResources> <ignoredResource>overview\.html</ignoredResource> </ignoredResource>
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.
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>maven-duplicate-finder-plugin</artifactId> <configuration> <failBuildInCaseOfConflict>true</failBuildInCaseOfConflict> ... </configuration> </plugin>
See COPYING file.