4

When I run mvn dependency:tree -Dverbose, I see the following:

[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ reddit_digest ---
...
[INFO] +- com.rajivprab:sava:jar:1.2.0:compile
[INFO] |  +- com.rajivprab:cava:jar:1.5.0:compile
[INFO] |  |  +- org.apache.commons:commons-lang3:jar:3.5:compile
...
[INFO] |  |  \- com.google.guava:guava:jar:20.0:compile

which is very surprising because the cava artifact has guava version-22 specified.

If I then go ahead and add the guava version-22 as a direct dependency on my project, and run mvn dependency:tree -Dverbose again, I now see the following, where cava's guava version is magically fixed to what it should be (22).

[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ reddit_digest ---
...
[INFO] +- com.google.guava:guava:jar:22.0:compile
[INFO] +- com.rajivprab:sava:jar:1.2.0:compile
[INFO] |  +- com.rajivprab:cava:jar:1.5.0:compile
[INFO] |  |  +- org.apache.commons:commons-lang3:jar:3.5:compile
...
[INFO] |  |  \- (com.google.guava:guava:jar:22.0:compile - omitted for duplicate)

What's causing the guava transitive dependency version to behave in such an unexpected manner?


Running the dependency-tree on cava:

[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ cava ---
....
[INFO] com.rajivprab:cava:jar:1.5.0
[INFO] +- com.google.guava:guava:jar:22.0:compile
....
[INFO] \- com.google.truth:truth:jar:0.33:test
[INFO]    +- (com.google.guava:guava:jar:20.0:test - omitted for conflict with 22.0)

Running the dependency-tree on sava, and looking for all instances of guava:

[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ sava ---
[INFO] com.rajivprab:sava:jar:1.2.0
[INFO] +- com.rajivprab:cava:jar:1.5.0:compile
...
[INFO] |  \- com.google.guava:guava:jar:22.0:compile
...
[INFO] +- com.google.truth:truth:jar:0.33:test
[INFO] |  +- (com.google.guava:guava:jar:20.0:test - omitted for conflict with 22.0)
...
[INFO] +- org.glassfish.jersey.media:jersey-media-multipart:jar:2.25.1:compile
[INFO] |  +- org.glassfish.jersey.core:jersey-common:jar:2.25.1:compile
[INFO] |  |  +- (javax.ws.rs:javax.ws.rs-api:jar:2.0.1:compile - omitted for duplicate)
[INFO] |  |  +- javax.annotation:javax.annotation-api:jar:1.2:compile
[INFO] |  |  +- org.glassfish.jersey.bundles.repackaged:jersey-guava:jar:2.25.1:compile

My maven version:

Apache Maven 3.5.0 (ff8f5e7444045639af65f6095c62210b5713f426; 2017-04-03T15:39:06-04:00)
Maven home: /usr/local/Cellar/maven/3.5.0/libexec
Java version: 1.8.0_92, vendor: Oracle Corporation
Java home: /Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre
Default locale: en_US, platform encoding: UTF-8
OS name: "mac os x", version: "10.12.5", arch: "x86_64", family: "mac"
RvPr
  • 1,074
  • 1
  • 9
  • 26
  • Is the project `com.rajivprab:sava` your project? So the dependency must be defined in one of your poms which means it's nearer to the project which has priority. Ah...the `com.rajivprab:sava:jar:1.2.0:compile` is a different version which presumably uses a different version of guava... – khmarbaise Jun 16 '17 at 14:05
  • @khmarbaise I just checked and that is not the case. I've updated the original post with logs from sava – RvPr Jun 16 '17 at 14:42
  • Do you have the project somewhere on Github or so? – khmarbaise Jun 16 '17 at 17:21
  • @khmarbaise Yes, you can find the project here: https://gitlab.com/whacks/daily-reddit/blob/master/pom.xml The dependencies Sava and cava are also on the same account. – RvPr Jun 16 '17 at 22:48

1 Answers1

3

The v22 is three level deep and the v20 is two level deep. The Maven's dependency mediation choose the "nearest definition" which is the v20.

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.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.

"nearest definition" means that the version used will be the closest one to your project in the tree of dependencies, eg. if dependencies for A, B, and C are defined as A -> B -> C -> D 2.0 and A -> E -> D 1.0, then D 1.0 will be used when building A because the path from A to D through E is shorter. You could explicitly add a dependency to D 2.0 in A to force the use of D 2.0

Source: https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html#Transitive_Dependencies

This SO answer can give you more detailed explanation about the reason behind the dependency mediation strategy: https://stackoverflow.com/a/43165652

You have two simple options:

  1. add the guava v22 to your pom to make it the nearest.
  2. add exclusion to the google truth dependency. There is an example here: https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html#Dependency_Management
Community
  • 1
  • 1
Gebezs
  • 696
  • 3
  • 9
  • Thanks for taking a look. Your explanation for why guava-v20 was getting selected, and how to workaround it, makes sense. I still think the debug-logs are buggy, because they show the guava-version listed under the cava branch as being v20, even though cava is actually using v22. But I've gone ahead and accepted your answer because the broader explanation and workaround are very useful. – RvPr Jul 03 '17 at 20:50
  • 2
    I face the same issue but there are no conflicts with the dependency, even then the transitive dependency downloaded is different – chandramohan Mar 12 '19 at 07:12