Programmers' Pain
28Feb/112

maven-duplicate-finder-plugin: find duplicate classes in maven artefacts

Lately I was looking for a Maven plugin to solve the problem that I want a certain Maven build to fail as soon as new duplicate classes have been introduced by other developers / third party dependencies while knowing that I already have some duplicate classes that I can’t get rid of right now. Basically a duplicate classes detector with the possibility to define an exclude list – that’s where the maven-duplicatefinder-plugin of Ning Inc. will give you a helping hand.

Currently the plugin doesn’t seem to be available in any public Maven repository so that you have to compile the plugin yourself before you can use it. The plugin is currently hosted on github using the Apache 2.0 License. The project page contains all information necessary to checkout and compile the plugin.

git clone https://github.com/ning/maven-duplicate-finder-plugin
cd maven-duplicate-finder-plugin
mvn clean install

You can use the plugin in two different ways: Command line usage via: mvn com.ning.maven.plugins:maven-duplicate-finder-plugin:1.0.0-SNAPSHOT:check or in-line as part of a Maven projects pom.xml file.

<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>

If you launch the compiled plugin against the plugin sources you’ll already see some warning about duplicate resources.

mvn com.ning.maven.plugins:maven-duplicate-finder-plugin:1.0.0-SNAPSHOT:check
[INFO] Scanning for projects...
[INFO] ------------------------------------------------------------------------
[INFO] Building maven-duplicate-finder-plugin Maven Mojo
[INFO]    task-segment: [com.ning.maven.plugins:maven-duplicate-finder-plugin:1.0.0-SNAPSHOT:check]
[INFO] ------------------------------------------------------------------------
[INFO] [duplicate-finder:check {execution: default-cli}]
[INFO] Checking compile classpath
[WARNING] Found duplicate resources in [org.apache.maven:maven-artifact:2.0.9,org.apache.maven:maven-artifact-manager:2.0.9,org.apache.maven:maven-plugin-registry:2.0.9,org.apache.maven:maven-profile:2.0.9,org.apache.maven:maven-project:2.0.9,org.apache.maven:maven-settings:2.0.9] :
[WARNING]   META-INF/plexus/components.xml
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------

Now it’s time to configure the plugin to match the use case. Since the Maven build should fail in case there are any duplicate classes the value of the <failBuildInCaseOfConflict> tag has to be set to true. Here’s a little sample project that will throw an error in case one of the dependencies does introduce duplicate classes.

<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 http://maven.apache.org/maven-v4_0_0.xsd"
>
	<modelVersion>4.0.0</modelVersion>
	<groupId>test</groupId>
	<artifactId>test</artifactId>
	<version>1.0-SNAPSHOT</version>
	<name>test</name>
	<packaging>jar</packaging>
	<dependencies>
		<dependency>
			<groupId>commons-collections</groupId>
			<artifactId>commons-collections</artifactId>
			<version>3.2</version>
			<scope>compile</scope>
		</dependency>
		<dependency>
			<groupId>commons-beanutils</groupId>
			<artifactId>commons-beanutils</artifactId>
			<version>1.7.0</version>
			<scope>compile</scope>
		</dependency>
	</dependencies>
	<build>
		<plugins>
			<plugin>
				<groupId>com.ning.maven.plugins</groupId>
				<artifactId>maven-duplicate-finder-plugin</artifactId>
				<version>1.0.0-SNAPSHOT</version>
				<configuration>
					<failBuildInCaseOfConflict>true</failBuildInCaseOfConflict>
				</configuration>
				<executions>
					<execution>
						<phase>package</phase>
						<goals>
							<goal>check</goal>
						</goals>
					</execution>
				</executions>
			</plugin>
		</plugins>
	</build>
</project>
[WARNING] Found duplicate classes in [commons-beanutils:commons-beanutils:1.7.0,commons-collections:commons-collections:3.2] :
[WARNING]   org.apache.commons.collections.ArrayStack
[WARNING]   org.apache.commons.collections.Buffer
[WARNING]   org.apache.commons.collections.BufferUnderflowException
[WARNING]   org.apache.commons.collections.FastHashMap
[INFO] ------------------------------------------------------------------------
[ERROR] BUILD ERROR
[INFO] ------------------------------------------------------------------------
[INFO] Found duplicate classes/resources
[INFO] ------------------------------------------------------------------------

The sample Maven project shows a pretty common scenario of external third-party dependencies that do contain duplicate classes: the Apache Commons libraries. An example: there’s an ongoing fight between developers if commons-beanutils should contain a dependency to commons-collections or not since commons-beanutils does use certain commons-collections classes to provide methods for collections of beans. Currently commons-beanutils does duplicate four classes of commons-collections so that a dependency to commons-collections isn’t necessary. This leads to duplicate classes in your classpath and sometimes to weird runtime effects if you mix incompatible library versions.

Since you can’t easily change external third-party libraries like commons-collections or commons-beanutils you’ll need to exclude those colliding classes somehow. For this purpose the maven-duplicate-finder-plugin provides so called <conflictingDependencies> exceptions that can be added to the plugins <configuration> tag.

<exceptions>
	<exception>
		<conflictingDependencies>
			<dependency>
				<groupId>commons-beanutils</groupId>
				<artifactId>commons-beanutils</artifactId>
				<version>1.7.0</version>
			</dependency>
			<dependency>
				<groupId>commons-collections</groupId>
				<artifactId>commons-collections</artifactId>
				<version>3.2</version>
			</dependency>
		</conflictingDependencies>
		<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>
</exceptions>

This exception allows four duplicate classes between the commons-collections and commons-beanutils libraries so that the resulting Maven build won’t fail any more. Those exceptions are only valid for the specified library versions! – which is a good thing since you’ll get noticed if some other third-party dependency did upgrade it’s dependencies to a more recent version of an Apache Commons library. On the other hand it would also be a nice if a future version of commons-beanutils would finally contain a dependency to the commons-collections library and no duplicate classes any more. At some point.. Maybe..

To sum it up: The maven-duplicate-finder-plugin is a very handy Maven plugin that will keep you informed as soon a your build contains any new duplicate classes that you usually don’t want to have in your application scope. At the same time the plugin is flexible enough to define exceptions for duplicates that you can’t fix right now or which aren’t under your control. Therefore the plugin should be deployed to a public Maven repository ASAP from my point of view 🙂

Comments (2) Trackbacks (0)
  1. Thank you very much. In the last 2 weeks your plugin has saved hours for me thrice. I have compiled in the latest SNAPSHOT and it rocks. I will add some feature support for include, exclude like the dependency-plugin does, and will contribute back.

    Once again, thank you!

    • Good to hear that you’ve been able to solve your problem with the help of this blog post. But just for clarification: I’m not the original author of this plugin, I just had to use this plugin once and thought it might be a good idea to write something about it. Credits for the plugin still have to go to the guys at Ning Inc. 🙂


Leave a comment

Connect with Facebook

No trackbacks yet.