We encountered a situation where Maven chose an inconsistent version of an indirect dependency, and I’d like to understand why, and how to prevent this in the future.
Our pom.xml file had the following dependencies:
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>1.1.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>3.1.2.RELEASE</version>
</dependency>
but without a direct dependency on spring-core.
Both depend on spring-core: spring-web 3.1.2.RELEASE depends on spring-core 3.1.2.RELEASE (see its pom-file), and spring-data-jpa 1.1.0.RELEASE depends on an arbitrary 3.x version of spring-core (to be precise [3.0.7.RELEASE,4.0.0.RELEASE), see its pom-file).
Combining both, I would expect Maven to choose spring-core version 3.1.2.RELEASE. However, it does not. Instead, it chooses the highest from the range [3.0.7.RELEASE,4.0.0.RELEASE), which currently is 3.2.0.RELEASE.
(Reproduction scenario: put the above pom.xml file (gist) in its own directory, and run mvn dependency:tree -Dverbose=true: for me the result is this tree (gist). I get the same result for both Maven 2.2.1 on Linux and Maven 3.0.4 on Windows.)
This seems wrong, because it is inconsistent: a version of spring-core which spring-web’s pom-file does not allow is used.
(This occurred for us when spring-core 3.2.0.RC1 became available: on the next update it was suddenly selected, and we were lucky that we got a build error because of an incompatible change between spring-core 3.1 and 3.2. But next time we may not be so lucky, and have runtime errors which are very difficult to track down.)
Urghh: I just notice that the order of <dependency> declarations matters: if I put spring-web first, then spring-core 3.1.2.RELEASE is selected. What gives?
Question: How can we make Maven choose consistent versions of indirect dependencies, or at least warn if it makes a choice which goes against a version specified in a pom-file?
Update: I am asking for a general solution here. For this specific case, I know that I can get the correct behavior by adding a dependency in <dependencyManagement>, specifying that I always want spring-core 3.1.2.RELEASE. However, I would like Maven to do the Right Thing (TM) without such specific declarations.
What you expect seems logic but Maven has no chance to do this. It just resolves dependencies without the knowledge that
spring-data-jpamight have somethig to do withspring-core.The dependency resolution works as describe here and is the way you already described:
So I think the only way to prevent this situation is to be aware of it and to explecitly set the version you need in your own pom.
By the way, why do you think “This seems wrong, because it is inconsistent: a version of spring-core is used which spring-web’s pom-file does not allow.“?
A version specification of
<version>x.y</version>is only a recommendation (see ‘Note’ here) to use this version. If you intend to force to use this version you have to set<version>[x.y]</version>.