If you have a largish set of internal libraries with a complex dependency graph, chances are you’ll be including different versions of the same class via different paths. The exact version of the class that gets loaded seems to depend on the combination of JVM, class loader and operating system that happens to be used at the time. This can cause builds to fail on some systems but not others and is quite annoying. When this has been happening to me, it’s usually been for one of two reasons:
- We’ve been restructuring our internal artifacts, and something was moved from artifact A to B, only the project in question is still on a version of artifact A that is “pre-removal”. This often leads to binary incompatibilities if the class has evolved since being moved to artifact B.
- Two artifacts in the dependency graph have dependencies on artifacts that, while actually different as artifacts, contain class files for the same class. This can typically happen with libraries that provide jar distributions that include all dependencies, or where there are distributions that are partial or full.
On a couple of previous occasions, when trying to figure out how duplicate class definitions made it into projects I’ve been working on, I’ve gone through a laborious manual process to list class names defined in jars, and see which ones are repeated in more than one. I thought that a better option might be to see if that functionality could be added into the Maven dependency plugin.
My original idea was to add a new goal, something like ‘dependency:duplicate-classes’, but when looking a little more closely at the source code of the dependency plugin, I found that the dependency:analyze goal had all the information needed to figure out which classes are defined more than once. So I decided to make a version of the maven-dependency-plugin where it is possible to detect duplicate class definitions using ‘mvn dependency:analyze’.
The easiest way to run the updated plugin is like this:
mvn dependency:analyze -DcheckDuplicateClasses
The output if duplicate classes are found is something like:
[WARNING] Duplicate class definitions found: [WARNING] com.shopzilla.common.data.ObjectFactory defined in: [WARNING] com.shopzilla.site.url.c14n:model:jar:1.4:compile [WARNING] com.shopzilla.common.data:data-model-schema:jar:1.23:compile [WARNING] com.shopzilla.site.category.CategoryProvider defined in: [WARNING] com.shopzilla.site2.sasClient:sas-client-core:jar:5.47:compile [WARNING] com.shopzilla.site2.service:common-web:jar:5.50:compile
If you would like to try the updated plugin on your project, here’s how to do it:
- Get the forked code for the dependency analyzer goal from http://github.com/pettermahlen/maven-dependency-analyzer-fork and install it in your local Maven repo by running ‘mvn install’. (It appears that for some people, the unit tests fail during this process – I’ve not been able to reproduce this, and it’s not the tests that I wrote, so in this case my recommendation would be to simply use -DskipTests=true to ignore them).
- Get the forked code for the dependency plugin from http://github.com/pettermahlen/maven-dependency-plugin-fork and install it in your local Maven repo by running ‘mvn install’.
- Update your pom.xml file to use the forked version of the dependency plugin (it’s probably also possible to use the plugin registry, but I’ve not tested that):
<build> <pluginManagement> <plugins> <plugin> <artifactId>maven-dependency-plugin</artifactId> <version>2.2.PM-SNAPSHOT</version> </plugin> </plugins> </pluginManagement> </build>
I’ve filed a JIRA ticket to get this feature included into the dependency plugin – if you think it would be useful, it might be a good idea to vote for it. Also, if you have any feedback about the feature, feel free to comment here!