I've written about Maven before, so this is not a long post about its merits. However a problem I've encountered a few times now is that of the use of one Maven dependency in turn bringing in some other undesirable older dependency (which is to say an older transitive dependency).
The fix to this is to add an exclusion to the dependency in question. For example, if we start with a dependency upon version 1.2.1 of the spring-ldap library:
<dependency> <groupId>org.springframework.ldap</groupId> <artifactId>spring-ldap</artifactId> <version>1.2.1</version> <scope>compile</scope> </dependency>
This dependency will bring in the old version 2.0.6 of spring-beans and spring-core. In order to ensure that I am using the latest versions of these, I need to put in an exclusion for these transitive dependencies of spring-ldap, which I do as follows:
<dependency>
<groupId>org.springframework.ldap</groupId>
<artifactId>spring-ldap</artifactId>
<version>1.2.1</version>
<scope>compile</scope>
<exclusions>
<exclusion>
<artifactId>spring-beans</artifactId>
<groupId>org.springframework</groupId>
</exclusion>
<exclusion>
<artifactId>spring-core</artifactId>
<groupId>org.springframework</groupId>
</exclusion>
</exclusions>
</dependency>
Having excluded them, they will no longer be in the build. I can now either explicitly include the versions that I want (ideally), which in my case are 2.5.1, or if I am using some other library with a transitive dependency upon these then they will be brought in for that automatically.
All very well, but how do I find out what these transitive dependencies are? I don't want to read every wretched pom.xml file involved directly or indirectly in my build - ideally I want to get the listing automatically. You can, it's nice and simple, and the command is:
mvn dependency:tree
Here's an example of the output when I ran it against the the JA-SIG Central Authentication Server (CAS), while I was debugging exactly this ldap dependency issue:
[INFO] [dependency:tree] [INFO] org.jasig.cas:cas-server-webapp:war:3.2.1 [INFO] +- log4j:log4j:jar:1.2.15:runtime [INFO] +- net.sf.ehcache:ehcache:jar:1.4.0-beta2:runtime [INFO] | +- net.sf.jsr107cache:jsr107cache:jar:1.0:runtime [INFO] | - backport-util-concurrent:backport-util-concurrent:jar:3.0:runtime [INFO] +- commons-lang:commons-lang:jar:2.2:runtime (scope not updated to compile) [INFO] +- quartz:quartz:jar:1.5.2:compile [INFO] +- org.springframework.ldap:spring-ldap:jar:1.2.1:compile [INFO] | +- org.springframework:spring-beans:jar:2.0.6:compile [INFO] | - org.springframework:spring-core:jar:2.0.6:compile [INFO] +- org.springframework.ldap:spring-ldap-tiger:jar:1.2.1:compile [INFO] +- org.springframework:spring-webmvc:jar:2.5.1:compile [INFO] | +- org.springframework:spring-context:jar:2.5.1:compile [INFO] | +- org.springframework:spring-context-support:jar:2.5.1:compile [INFO] | - org.springframework:spring-web:jar:2.5.1:compile [INFO] +- javax.servlet:jstl:jar:1.1.2:compile [INFO] +- javax.servlet:servlet-api:jar:2.4:provided (scope not updated to compile) [INFO] +- ognl:ognl:jar:2.6.9:runtime (scope not updated to compile) [INFO] +- junit:junit:jar:3.8.1:test [INFO] +- org.acegisecurity:acegi-security:jar:1.0.6:runtime [INFO] | +- commons-codec:commons-codec:jar:1.3:runtime [INFO] | - oro:oro:jar:2.0.8:runtime [INFO] +- cas:casclient:jar:2.1.1:runtime [INFO] +- org.springframework:spring-aop:jar:2.5.1:compile [INFO] | - aopalliance:aopalliance:jar:1.0:compile [INFO] +- org.springframework:spring-test:jar:2.5.1:test [INFO] +- commons-logging:commons-logging:jar:1.1:compile [INFO] +- org.springframework:spring-webflow:jar:1.0.5:compile [INFO] | - org.springframework:spring-binding:jar:1.0.5:compile [INFO] +- org.inspektr:inspektr-core:jar:0.6.1:compile [INFO] | +- aspectj:aspectjweaver:jar:1.5.3:runtime [INFO] | +- aspectj:aspectjrt:jar:1.5.3:compile [INFO] | - org.springframework:spring-jdbc:jar:1.2.9:compile [INFO] | - org.springframework:spring-tx:jar:2.5.1:compile [INFO] +- org.jasig.cas:cas-server-core:jar:3.2.1:compile [INFO] | +- org.jasig.service:person-directory-impl:jar:1.1.1:compile [INFO] | | +- org.jasig.service:person-directory-api:jar:1.1.1:compile [INFO] | | - commons-collections:commons-collections:jar:3.2:compile [INFO] | +- jdom:jdom:jar:1.0:compile [INFO] | +- org.springframework:spring-orm:jar:2.5.1:compile [INFO] | +- org.apache.santuario:xmlsec:jar:1.4.0:runtime [INFO] | +- org.opensaml:opensaml:jar:1.1b:compile [INFO] | +- javax.persistence:persistence-api:jar:1.0:compile [INFO] | - javax.xml:xmldsig:jar:1.0:compile [INFO] - taglibs:standard:jar:1.1.2:compile
Note the (bold) section where the dependencies of spring-ldap are described, and the old version numbers of spring-beans and spring-core. And here's the same tree after I had excluded those libraries.
[INFO] [dependency:tree] [INFO] org.jasig.cas:cas-server-webapp:war:3.2.1 [INFO] +- log4j:log4j:jar:1.2.15:runtime [INFO] +- net.sf.ehcache:ehcache:jar:1.4.0-beta2:runtime [INFO] | +- net.sf.jsr107cache:jsr107cache:jar:1.0:runtime [INFO] | \- backport-util-concurrent:backport-util-concurrent:jar:3.0:runtime [INFO] +- commons-lang:commons-lang:jar:2.2:runtime (scope not updated to compile) [INFO] +- quartz:quartz:jar:1.5.2:compile [INFO] +- org.springframework.ldap:spring-ldap:jar:1.2.1:compile [INFO] +- org.springframework.ldap:spring-ldap-tiger:jar:1.2.1:compile [INFO] +- org.springframework:spring-webmvc:jar:2.5.1:compile [INFO] | +- org.springframework:spring-beans:jar:2.5.1:compile [INFO] | +- org.springframework:spring-context:jar:2.5.1:compile [INFO] | +- org.springframework:spring-context-support:jar:2.5.1:compile [INFO] | +- org.springframework:spring-core:jar:2.5.1:compile [INFO] | \- org.springframework:spring-web:jar:2.5.1:compile [INFO] +- javax.servlet:jstl:jar:1.1.2:compile [INFO] +- javax.servlet:servlet-api:jar:2.4:provided (scope not updated to compile) [INFO] +- ognl:ognl:jar:2.6.9:runtime (scope not updated to compile) [INFO] +- junit:junit:jar:3.8.1:test [INFO] +- org.acegisecurity:acegi-security:jar:1.0.6:runtime [INFO] | +- commons-codec:commons-codec:jar:1.3:runtime [INFO] | \- oro:oro:jar:2.0.8:runtime [INFO] +- cas:casclient:jar:2.1.1:runtime [INFO] +- org.springframework:spring-aop:jar:2.5.1:compile [INFO] | \- aopalliance:aopalliance:jar:1.0:compile [INFO] +- org.springframework:spring-test:jar:2.5.1:test [INFO] +- commons-logging:commons-logging:jar:1.1:compile [INFO] +- org.springframework:spring-webflow:jar:1.0.5:compile [INFO] | \- org.springframework:spring-binding:jar:1.0.5:compile [INFO] +- org.inspektr:inspektr-core:jar:0.6.1:compile [INFO] | +- aspectj:aspectjweaver:jar:1.5.3:runtime [INFO] | +- aspectj:aspectjrt:jar:1.5.3:compile [INFO] | \- org.springframework:spring-jdbc:jar:1.2.9:compile [INFO] | \- org.springframework:spring-tx:jar:2.5.1:compile [INFO] +- org.jasig.cas:cas-server-core:jar:3.2.1:compile [INFO] | +- org.jasig.service:person-directory-impl:jar:1.1.1:compile [INFO] | | +- org.jasig.service:person-directory-api:jar:1.1.1:compile [INFO] | | \- commons-collections:commons-collections:jar:3.2:compile [INFO] | +- jdom:jdom:jar:1.0:compile [INFO] | +- org.springframework:spring-orm:jar:2.5.1:compile [INFO] | +- org.apache.santuario:xmlsec:jar:1.4.0:runtime [INFO] | +- org.opensaml:opensaml:jar:1.1b:compile [INFO] | +- javax.persistence:persistence-api:jar:1.0:compile [INFO] | \- javax.xml:xmldsig:jar:1.0:compile [INFO] \- taglibs:standard:jar:1.1.2:compile
Here you can see that no dependencies are brought in for spring-ldap, but the dependencies of spring-webmvc that were previously suppressed by the earlier versions are being brought in correctly. This dependency tree is a very useful tool, so it's well worth being aware of it.
Update: you may (will?) need to add the following configuration to your top level pom.xml in order to enable this feature:
<project ... >
...
<pluginRepositories>
<pluginRepository>
<id>maven.shapshot</id>
<name>Maven snapshot repository</name>
<url>http://people.apache.org/repo/m2-snapshot-repository</url>
</pluginRepository>
</pluginRepositories>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>