Monthly Archives: April 2016

Maven is a weirdo when it comes to resolving dependencies

The other day, I was experimenting with maven dependency conflicts. That is, if your project uses the¬†dependency with conflicting versions, maven will resolve/pick one for you depending on your rules and it’s heuristics.

For the record, I’m using maven 3.3

According to maven docs

“by default Maven resolves version conflicts with a nearest-wins strategy”

You’d think these heuristics are simple, but not really. Let’s look at some examples.

Let’s say you have a pom with two conflicting dependencies

<dependencies>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.4</version>
</dependency>

<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.5</version>
</dependency>
</dependencies>

You can run “mvn dependency:tree -Dverbose” to see which of the two commons-codec version it picks.

In this case, maven seems to prefer the last commons-codec in the list of dependencies. 

That makes some sense. Maybe developers have the habit of adding dependencies to the end of the list so maven prefers that one

Let’s suppose we have a dependency, such as hadoop-common, that depends on commons-codec 1.4 and we have a commons-codec 1.5 dependency at the top-level. Which version would it prefer then?

<dependencies>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.5</version>
</dependency>

<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-common</artifactId>
<version>2.4.0</version>
</dependency>
</dependencies>

Maven prefers the top-level commons-codec 1.5 version here.

Even though the commons-codec 1.4 within hadoop-common comes later in the dependency list, it prefers the top-level one that the develop explicitly chose. This makes sense since the top-level dependency is explicitly chosen by the developer while the one within hadoop-common is somewhat more implicit. So maven seems to obey explicit top-level dependencies.

Here’s where it gets a little weird. What happens if we have two dependencies that depend on different versions of commons-codec?

poi depends on commons-codec 1.5 and hadoop-common depends on commons-codec 1.4

<dependencies>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.8-beta5</version>
</dependency>

<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-common</artifactId>
<version>2.4.0</version>
</dependency>
</dependencies>

Maven will choose the FIRST version it sees, in this case, it will prefer commons-codec 1.5 found in the earlier poi dependency.

This is a bit counter-intuitive. Remember that previously, maven prefers the LAST version of commons-codec when both were listed in the top-level.

Let’s dive deeper. Does the depth at which commons-codec is found matter?

hadoop-client depends on hadoop-common which depends on commons-codec 1.4. And poi depends on commons-codec 1.5

<dependencies>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-client</artifactId>
<version>2.4.0</version>
</dependency>

<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.8-beta5</version>
</dependency>
</dependencies>

Maven prefers poi’s common-codec 1.5 since it is found at the 2nd-level, whereas common-codec 1.4 is found at the 3rd-level of hadoop-client.

It seems that the closer to the top-level the dependency is, the more maven prefers it. This is probably consistent with the fact that maven picks explicit top-level dependencies over sub-dependencies at lower levels. You can try switching the order of hadoop-client and poi and you’ll see that the depth is more important than the dependency order here.

So do you think you have a good handle on how maven resolves dependencies?