Maven
2011.12.15

Using Maven tooling to manage dependencies

Samuel Langlois
Posted by Samuel Langlois

When presenting the Antepedia Reporter, several people asked us whether we were also analyzing Maven pom.xml files to extract its dependencies.
This question was a surprise to us, because Maven already provides several tools to list and manage dependencies.

Let's have a look at them, and how they can help.

Listing your dependencies

Of course, having a look at the content of the pom.xml file is not enough, because Maven also fetches transitive dependencies (i.e. the dependencies of the dependencies, etc.). But a very simple command tells Maven to compute the list of all the transitive dependencies and list them :

$ mvn dependency:list

[INFO] 
[INFO] --- maven-dependency-plugin:2.4:list (default-cli) @ sourcesquare-client ---
[INFO]
[INFO] The following files have been resolved:
[INFO]    org.easymock:easymock:jar:3.1:test
[INFO]    org.hamcrest:hamcrest-core:jar:1.1:test
[INFO]    log4j:log4j:jar:1.2.16:compile
[INFO]    org.springframework:spring-asm:jar:3.0.6.RELEASE:compile
[INFO]    org.springframework:spring-core:jar:3.0.6.RELEASE:compile
[INFO]    commons-logging:commons-logging:jar:1.1.1:compile
[INFO]    org.springframework:spring-web:jar:3.0.6.RELEASE:compile
[INFO]    org.springframework:spring-expression:jar:3.0.6.RELEASE:compile
[INFO]    org.springframework:spring-beans:jar:3.0.6.RELEASE:compile
[INFO]    com.google.code.gson:gson:jar:2.0:compile
[INFO]    commons-io:commons-io:jar:2.0.1:compile
[INFO]    org.objenesis:objenesis:jar:1.2:test
[INFO]    junit:junit:jar:4.10:test
[INFO]    commons-httpclient:commons-httpclient:jar:3.1:compile
[INFO]    cglib:cglib-nodep:jar:2.2.2:test
[INFO]    commons-codec:commons-codec:jar:1.2:compile
[INFO]    com.jgoodies:forms:jar:1.2.1:compile
[INFO]    aopalliance:aopalliance:jar:1.0:compile
[INFO]    org.springframework:spring-context:jar:3.0.6.RELEASE:compile
[INFO]    org.codehaus.jackson:jackson-core-asl:jar:1.9.2:compile
[INFO]    org.springframework:spring-aop:jar:3.0.6.RELEASE:compile
[INFO]    org.codehaus.jackson:jackson-mapper-asl:jar:1.9.2:compile
[INFO]

(Unfortunately, since version 2.2 of the maven-dependency-plugin, the output is not sorted any more. Vote for this bug if, like me, it annoys you!)

Another command displays the result in a tree, in an ASCII art way. It is very convenient to check which dependency pulls which:

$ mvn dependency:tree

[INFO]
[INFO] --- maven-dependency-plugin:2.4:tree (default-cli) @ sourcesquare-client ---
[INFO] com.antelink.sourcesquare:sourcesquare-client:jar:1.0.2-SNAPSHOT
[INFO] +- com.jgoodies:forms:jar:1.2.1:compile
[INFO] +- commons-httpclient:commons-httpclient:jar:3.1:compile
[INFO] |  \- commons-codec:commons-codec:jar:1.2:compile
[INFO] +- com.google.code.gson:gson:jar:2.0:compile
[INFO] +- org.springframework:spring-web:jar:3.0.6.RELEASE:compile
[INFO] |  +- aopalliance:aopalliance:jar:1.0:compile
[INFO] |  +- org.springframework:spring-beans:jar:3.0.6.RELEASE:compile
[INFO] |  +- org.springframework:spring-context:jar:3.0.6.RELEASE:compile
[INFO] |  |  +- org.springframework:spring-aop:jar:3.0.6.RELEASE:compile
[INFO] |  |  +- org.springframework:spring-expression:jar:3.0.6.RELEASE:compile
[INFO] |  |  \- org.springframework:spring-asm:jar:3.0.6.RELEASE:compile
[INFO] |  \- org.springframework:spring-core:jar:3.0.6.RELEASE:compile
[INFO] +- commons-logging:commons-logging:jar:1.1.1:compile
[INFO] +- log4j:log4j:jar:1.2.16:compile
[INFO] +- org.codehaus.jackson:jackson-mapper-asl:jar:1.9.2:compile
[INFO] |  \- org.codehaus.jackson:jackson-core-asl:jar:1.9.2:compile
[INFO] +- commons-io:commons-io:jar:2.0.1:compile
[INFO] +- junit:junit:jar:4.10:test
[INFO] |  \- org.hamcrest:hamcrest-core:jar:1.1:test
[INFO] \- org.easymock:easymock:jar:3.1:test
[INFO]    +- cglib:cglib-nodep:jar:2.2.2:test
[INFO]    \- org.objenesis:objenesis:jar:1.2:test

Note that all scopes are included in the output by default. You can limit the scopes using excludeScope or includeScope options.

For instance, to check what would be packaged in your application, use the following:

$ mvn dependency:list -DincludeScope=runtime

At last, Maven is able to generate a static HTML page with all this information, and much more, using its reporting capability :

$ mvn dependency:list -DincludeScope=runtime

You will get in target/site/dependencies.html a nice report with all the information above and much more on each dependency: size, number of classes, JDK version, etc.

One information of this report is especially important: the license of the component.

But since you are on Antelink blog, you know that open source licenses are a serious matter! :-)

Checking what you use

Listing what you declare is all fine, but what about matching that against what you actually use in your code?
This is possible with the analyze goal of the maven-dependency-plugin. After the code is compiled, it will compare the declared dependencies with the API which are actually used in the bytecode:
$ mvn dependency:analyze
[INFO]
[INFO] --- maven-dependency-plugin:2.4:analyze (default-cli) @ sourcesquare-client ---
[WARNING] Used undeclared dependencies found:
[WARNING]    commons-codec:commons-codec:jar:1.2:compile
[WARNING]    org.codehaus.jackson:jackson-core-asl:jar:1.9.2:compile
[WARNING] Unused declared dependencies found:
[WARNING]    log4j:log4j:jar:1.2.16:compile
The output may require a little explanation! The goal lists two sets of dependencies:
used and undeclared
This usually happens when you use an API which you do not declare directly in the POM file, but which you get through transitive dependency.
It is not a good practice, and you should explicitly depend on what you use, instead of expecting another dependency to pull it for you
unused and declared
This is a dependency which is probably useless, and you can delete it from the POM file... unless it is used through reflection! In this case, the goal cannot see that it is used by simply reading the bytecode, it could only discover it at runtime.
If you have a valid set of tests you can trust, delete it safely, otherwise be careful!

Keeping up-to-date

Another very interesting feature is to check whether your dependencies are up-to-date.
This is done with the maven-versions-plugin, which connects to your Maven repository and checks for newer versions:

$ mvn versions:display-dependency-updates
[INFO]
[INFO] The following dependencies in Dependencies are using the newest version:
[INFO]   com.google.code.gson:gson ........................................ 2.0
[INFO]   com.jgoodies:forms ............................................. 1.2.1
[INFO]   commons-httpclient:commons-httpclient ............................ 3.1
[INFO]   commons-logging:commons-logging ................................ 1.1.1
[INFO]   junit:junit ..................................................... 4.10
[INFO]   log4j:log4j ................................................... 1.2.16
[INFO]   org.codehaus.jackson:jackson-mapper-asl ........................ 1.9.2
[INFO]   org.easymock:easymock ............................................ 3.1
[INFO]   org.springframework:spring-web ......................... 3.0.6.RELEASE
[INFO]
[INFO] The following dependencies in Dependencies have newer versions:
[INFO]   commons-io:commons-io ............................................ 2.1
[INFO]

Here, only the dependencies which are explicitly cited in the POM file are listed.
Indeed, you probably don't want to upgrade a dependency that you pull transitively: it is not your responsibility to manage its version, it is the one of what you depend on.

 

Note that this plugin also provides another goal to perform the same task on your plugin dependencies :

$ mvn versions:display-plugin-updates
[INFO]
[INFO] The following plugin updates are available:
[INFO]   com.mycila.maven-license-plugin:maven-license-plugin  1.9.0 -> 1.10.b1
[INFO]
[INFO] All plugins have a version specified.

The maven-versions-plugin contains many other goals to help you manage the version you declare in your POM - it is definitely a plugin to keep in mind.

 

 

These are the plugins I use routinely. I hope they will be useful to you as well.
Maven is an amazingly rich set of tools, and one can always some advice!

Which ones are you using to manage your dependencies?

Stay informed on our latest news!

Follow us