As the number of dependencies from some our corporate project grew, we ran into a couple cases where we would be transitively pulling into different versions of the same classes. For a long time, we were lucky, as this did not cause any issues, until someday a developer new to our team introduced trying to run our application using a different operating system. The JVM on his machine loaded up the classes in a different order, and his application instance used an older version of a class that resulted in errors running the application.
This developer thankfully pointed out we can detect when we were pulling in different versions of classes using the Maven Enforcer plugin with some help of some extra rules. We added something like this to our parent POM:
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-enforcer-plugin</artifactId> <version>1.3.1</version> <executions> <execution> <id>enforce</id> <phase>validate</phase> <configuration> <rules> <banDuplicateClasses> <ignoreClasses> <ignoreClass>javax.*</ignoreClass> <ignoreClass>org.junit.*</ignoreClass> <ignoreClass>org.hamcrest.*</ignoreClass> <ignoreClass>org.slf4j.*</ignoreClass> </ignoreClasses> <findAllDuplicates>true</findAllDuplicates> </banDuplicateClasses> </rules> <fail>false</fail> </configuration> <goals> <goal>enforce</goal> </goals> </execution> </executions> <dependencies> <dependency> <groupId>org.codehaus.mojo</groupId> <artifactId>extra-enforcer-rules</artifactId> <version>1.0-beta-2</version> </dependency> </dependencies> </plugin>
Example output from the
validate phase of a build:
[INFO] --- maven-enforcer-plugin:1.1:enforce (enforce) @ cataloging-api --- [INFO] Adding ignore: javax.* [INFO] Adding ignore: org.junit.* [INFO] Adding ignore: org.hamcrest.* [INFO] Adding ignore: org.slf4j.* [WARNING] Rule 0: org.apache.maven.plugins.enforcer.BanDuplicateClasses failed with message: Duplicate classes found: Found in: org.company.id.api:id-api:jar:1.28.0:compile org.compnay.legacy.id-api:id-common-api:jar:2.8.0:compile Duplicate classes: org/company/service/id/SAMLEntityId.class org/company/service/id/crypto/ServiceKey.class
We were surprised at the amount of duplicate classes we were bringing in. We thought our dependency management was in pretty good shape, but adding the new rules showed we still had some work to do.
It is also worth noting, while our project is large, adding the plugin execution to the build added an insignifcat amount of time to the build overall, so there should be no performance concerns if you were considering adding something similar to your project.