45

This is a dependency tree generated by Maven 2.2.1 with mvn -o dependency:tree -Dverbose -Dincludes=log4j

[INFO] [dependency:tree {execution: default-cli}]
[INFO] com.openboxes.renderingservice:common:jar:1.0
[INFO] +- org.springframework:spring:jar:2.0.4:compile
[INFO] |  \- commons-logging:commons-logging:jar:1.1:compile
[INFO] |     \- log4j:log4j:jar:1.2.12:compile
[INFO] \- it.mycompany.portal:server:jar:1.5-SNAPSHOT:compile
[INFO]    \- org.slf4j:slf4j-log4j12:jar:1.1.0:compile
[INFO]       \- (log4j:log4j:jar:1.2.13:compile - omitted for conflict with 1.2.12)

As you can see log4j v1.2.12 is preferred over v1.2.13.

I know that "Maven resolves version conflicts with a nearest-wins strategy" (see http://maven.apache.org/plugins/maven-dependency-plugin/examples/resolving-conflicts-using-the-dependency-tree.html) but these two dependencies seem to be at the same distance (two nesting levels, am I wrong?) so I expect that the most recent one is used.

Can someone explain this result?

Yes, log4j is not explicitly declared in this POM (and I think it should be), but I would like to better understand the way Maven works.

Thx

Pino
  • 7,468
  • 6
  • 50
  • 69

2 Answers2

79

I've found the answer by myself at http://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html: "if two dependency versions are at the same depth in the dependency tree, until Maven 2.0.8 it was not defined which one would win, but since Maven 2.0.9 it's the order in the declaration that counts: the first declaration wins".

It seems a very questionable strategy to me. :-\

Pino
  • 7,468
  • 6
  • 50
  • 69
  • 39
    It's questionable, but at least deterministic. – TWiStErRob Nov 18 '13 at 12:27
  • 2
    https://maven.apache.org/plugins/maven-dependency-plugin/examples/resolving-conflicts-using-the-dependency-tree.html – daemon54 May 10 '16 at 22:38
  • 1
    thank you ! had a dependency problem .. changed the order and now its working – Ohad Bitton May 26 '19 at 15:07
  • we hit this way too many times, there should be a strategy that maven provides on how to resolve this. the only one currently is `dependencyManagement` which for transitive dependencies is not really a solution, gradle has much, much better support for this. – Eugene Dec 26 '21 at 19:50
  • what strikes me most of this strategy is that it does it regardless of the dependency scope. It'll pick a test scoped dep over a compile scoped one, which does not make any sense. – mrod Jul 12 '22 at 08:01
7

if two dependency versions are at the same depth in the dependency tree, or if not at the same depth which is more closure to the project will be pointed to the Project.

There are Two solutions To resolve that once you know your dependency depth.

First: if those dependencies are included as part of another project in the library you can remove them manually, But you don't want your project to point that dependency as it was point due to being closest to your project. You can exclude jar of particular project as shown below in your project pom.xml

 <dependency>
        <groupId>org.cassandraunit</groupId>
        <artifactId>cassandra-unit</artifactId>
        <version>3.1.3.2</version>
        <exclusions>
            <exclusion>
                <groupId>org.apache.commons</groupId>
                <artifactId>commons-lang3</artifactId>
            </exclusion>
        </exclusions>
    </dependency>

Second: You directly add the jar of the expected version in the pom.xml of your project. Then that would be the closest jar to your project.

Using Both ways mentioned above you can solve the problem.

Arpan Saini
  • 4,623
  • 1
  • 42
  • 50