Maven:不正确的(和片状的)传递依赖版本

Maven: Incorrect (and flaky) transitive dependency version

当我 运行 mvn dependency:tree -Dverbose 时,我看到以下内容:

[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

这非常令人惊讶,因为 the cava artifact has guava version-22 specified

如果我继续添加 guava version-22 作为对我项目的直接依赖,然后再次 运行 mvn dependency:tree -Dverbose,我现在看到以下内容,其中 cava 的 guava 版本神奇地固定为它应该的样子 (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)

是什么导致 guava 传递依赖版本以如此意外的方式运行?


运行 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)

运行 sava 上的依赖树,并查找 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

我的maven版本:

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"

v22 是三层深,v20 是两层深。 Maven 的依赖中介选择“最近的定义”,即 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

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

这个SO答案可以给你更详细的解释依赖调解策略背后的原因:

您有两个简单的选择:

  1. 将 guava v22 添加到您的 pom 以使其最接近。
  2. 添加对 google 真值依赖的排除。这里有一个例子:https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html#Dependency_Management