At my current position we use Maven for handling our project’s dependencies. This is not only useful for easy management of 3rd party dependencies you have, but also for handling internal dependencies between artifacts we develop (besides loads of other extra’s). Using Maven we’ve been able to develop several components (or modules) that you can easily use to set up a new project. It’s like you’re in a candy shop with a basket and pulling stuff from the shelves. At home you take your stuff and create a new project using these modules. Reuse to the max!
However (sence the tone in the title
) things do not turn out that magnificent as we’d hoped. If you’d check out. You’d see a three level dependency graph. Main artifact A depends on B,C and D, which in turn all depend on E. However, they each depend on a different version of E. The order of the dependencies in A’s POM is first A, then B and finally C. My idea always was that Maven would check depth and versioning and would actually compare different versions of the same artifact. In this example, Maven would compare versions 1.0.0, 1.0.3 and 1.5.0 and would come to the conclusion that at this level version 1.5.0 would be considered the best. Maven would come to this conclusion by using the <major>.<minor>.<revision> scheme. Only a major upgrade of E – so a version 2.x.y – could break stuff, so while you’re safely in the 1.x.y zone, you’re good. Just take the highest referenced version.
Unfortunately…
Maven does not work this way. A tiny note in the Maven docs (which I should’ve noticed of course) states the following:
Dependency mediation – this determines what version of a dependency will be used when multiple versions of an artifact are encountered. Currently, Maven 2.0 only supports using the “nearest definition” which means that it will use the version of the closest dependency to your project in the tree of dependencies. You can always guarantee a version by declaring it explicitly in your project’s POM. Note that if two dependency versions are at the same depth in the dependency tree, until Maven 2.0.4 it was not defined which one would win, but since Maven 2.0.5 it’s the order in the declaration that counts: the first declaration wins.
So the closest dependency to the root gets to win and order in your pom.xml matters. In our example version 1.0.0 of artifact E will prevail – see Figure 2 why. The only way to fix this (currently) is to change the order of the dependencies in your POM, or to explicitly list a dependency of E in your POM with the version you would like to have. This could be a real bugger as components C and D may expect bugs to have been fixed or interfaces to be present (say stuff that has been introduced since 1.0.3). You could end up with nasty runtime issues.
Now what?
I’m currently working on a plugin that will try to traverse the graph and list the maximum version of each dependency (including transitive ones). Then it will match this with the actual version that Maven decides to use. If this does not match it will list in in some kind of report. Still work in progress, so things might turn out differently.
Registered an issue at Maven’s JIRA: http://jira.codehaus.org/browse/MNG-4175