Minimally Complete Dependency Declaration in Maven
|January 31, 2012||Posted by Stuart Gunter under Uncategorized|
One of the great things about Maven is that it automatically downloads and manages the transitive dependencies within your project. This has the unfortunate side-effect of making it easy to start using libraries that you haven’t explicitly included. Luckily this is something that can be checked as part of your regular Maven build.
Simply configure the maven-dependency-plugin to execute the analyze-only goal as part of your build and specify that it should fail the build whenever a dependency warning is emitted. This actually ensures that you don’t have any warnings related to dependencies in your project, like forgetting to explicitly specify the version of a dependency.
Here’s how to configure it (copied straight from the plugin docs ):
This binds to the verify phase and will fail the build with errors that look something like this…
If a dependency version is missing:
[ERROR] The project org.stuartgunter.demo:maven-demo:1.0 (/code/maven-demo/pom.xml) has 1 error[ERROR] 'dependencies.dependency.version' for org.slf4j:slf4j-log4j12:jar is missing. @ line 39, column 21
If dependency declarations are incorrect:
[WARNING] Used undeclared dependencies found:[WARNING] com.google.code.findbugs:jsr305:jar:1.3.9:compile[WARNING] Unused declared dependencies found:[WARNING] com.google.guava:guava:jar:10.0.1:compile[WARNING] ch.qos.logback:logback-classic:jar:1.0.0:test
Sometimes it’s easier to just see it in action, so I’ve put together a very basic application (barely modified from the maven-archetype-quickstart) that demonstrates this in action. Feel free to fork it on GitHub and experiment with other options: https://github.com/stuartgunter/maven-demo
So what’s the big deal about using transitive dependencies?
The first problem I can see with it is that you’re not managing that dependency. Maven’s dependency resolution mechanism is takes into account the proximity of the dependency to the project when determining which version to use, so if you haven’t specified it explicitly it might not be completely obvious which version you’re using. While that may not be a major problem, it is still an issue that can be fixed very easily.
The second problem is that you’re relying on your direct dependencies to always depend on that artifact. If you’re developing against a SNAPSHOT version (which is only transient anyway), there’s a possibility that your code could break if your immediate dependency suddenly doesn’t depend on the artifact you’re using anymore. Because you haven’t told Maven you’re using it, it won’t be included and your build will break.
The bottom line is that it’s an easy problem to fix, so I don’t see any reason why not to.
The other issue this plugin highlights is the declaration of dependencies that you’re not using anymore. While not a major issue, it does mean that you’re forcing all upstream projects to download that unnecessary artifact. The ripple effect of that problem is potentially far-reaching and could make other packages a lot bigger than they need to be. So if you’re not using, stop depending on it.
As much as we gain from fixing these problems, for me the biggest gain is the awareness of what you’re actually using. Projects – particularly large ones with multiple teams – can grow very quickly and incorporate a number of external libraries. Over time, it’s very easy to find that you’re using multiple libraries that solve the same problem. For example, one team might prefer the Gson parser while another prefers Jackson . Unless there’s a good reason to have both, it often makes sense to standardise on the one that fits best and remove the other. Even if you decide to keep both, the knowledge that you are using both is powerful and can aid further decisions you make while programming.
Room for Improvement
The one feature missing from this plugin is the ability to selectively exclude certain dependency scopes from the verification. The plugin currently allows you to configure whether to only run against compile dependencies (ignoreNonCompile) or all of them. But it would be very useful to include all compile and test scoped dependencies in the analysis.
Aside from that shortcoming, the plugin is actually very useful and has helped to substantially improve the configuration in my current project. Hopefully you find the same.
Come back soon for another nice feature of Maven related to dependency management! I’ll post it as soon as I have the demo setup.