【问题标题】:Maven: Incorrect (and flaky) transitive dependency versionMaven:不正确(且不稳定)的传递依赖版本
【发布时间】:2017-06-16 14:02:02
【问题描述】:

当我运行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"

【问题讨论】:

  • 项目com.rajivprab:sava是你的项目吗?因此,必须在您的一个 pom 中定义依赖项,这意味着它更接近具有优先权的项目。啊...com.rajivprab:sava:jar:1.2.0:compile 是一个不同的版本,大概使用了不同版本的番石榴......
  • @khmarbaise 我刚刚检查过,但事实并非如此。我已经用 sava 的日志更新了原始帖子
  • 你在 Github 上的某个地方有这个项目吗?
  • @khmarbaise 是的,你可以在这里找到项目:gitlab.com/whacks/daily-reddit/blob/master/pom.xml 依赖项 Sava 和 cava 也在同一个帐户上。

标签: java maven jar dependency-management


【解决方案1】:

v22 是三级深度,v20 是两级深度。 Maven 的依赖中介选择“最近的定义”,即 v20。

依赖中介——这决定了当遇到工件的多个版本时将使用哪个版本的依赖。目前,Maven 2.0 仅支持使用“最近定义”,这意味着它将使用依赖树中与您的项目最接近的依赖版本。您始终可以通过在项目的 POM 中明确声明来保证版本。请注意,如果两个依赖版本在依赖树中的深度相同,则在 Maven 2.0.8 之前没有定义哪个会获胜,但从 Maven 2.0.9 开始,声明中的顺序很重要:第一个声明获胜。

“最近的定义”意味着使用的版本将是依赖树中最接近您的项目的版本,例如。如果 A、B 和 C 的依赖项定义为 A -> B -> C -> D 2.0 和 A -> E -> D 1.0,则在构建 A 时将使用 D 1.0,因为从 A 到 D 的路径通过E 更短。您可以在 A 中显式添加对 D 2.0 的依赖项以强制使用 D 2.0

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

这个SO答案可以给你更详细的解释依赖中介策略背后的原因:https://stackoverflow.com/a/43165652

您有两个简单的选择:

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

【讨论】:

  • 感谢您的浏览。您对为什么选择 guava-v20 以及如何解决它的解释是有道理的。我仍然认为调试日志有问题,因为它们将 cava 分支下列出的 guava 版本显示为 v20,即使 cava 实际上使用的是 v22。但我已经接受了您的回答,因为更广泛的解释和解决方法非常有用。
  • 我遇到了同样的问题,但是依赖没有冲突,即使下载的传递依赖不同
猜你喜欢
  • 2016-11-30
  • 2011-12-22
  • 2020-06-24
  • 2023-04-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-17
  • 2022-06-21
相关资源
最近更新 更多