Reputation: 13
If library L
is a dependency of both X
and Y
projects, and your MainModule
has:
implementation X
implementation Y
Is the same L
shared between X
and Y
? What if X
needs a different version of L
than Y
?
Upvotes: 1
Views: 113
Reputation: 5230
It's neatly described in Gradle documentation: TL;DR In case of a version conflict the default is to select the dependency with the highest version. But note that version conflict resolution can be customized.
Version conflict resolution
A version conflict occurs when two components:
Depend on the same module, let’s say
com.google.guava:guava
But on different versions, let’s say
20.0
and25.1-android
Our project itself depends on
com.google.guava:guava:20.0
Our project also depends on
com.google.inject:guice:4.2.2
which itself depends oncom.google.guava:guava:25.1-android
Resolution strategy
Given the conflict above, there exist multiple ways to handle it, either by selecting a version or failing the resolution. Different tools that handle dependency management have different ways of handling these type of conflicts.
Apache Maven uses a nearest first strategy.
Maven will take the shortest path to a dependency and use that version. In case there are multiple paths of the same length, the first one wins.
This means that in the example above, the version of
guava
will be20.0
because the direct dependency is closer than theguice
dependency.The main drawback of this method is that it is ordering dependent. Keeping order in a very large graph can be a challenge. For example, what if the new version of a dependency ends up having its own dependency declarations in a different order than the previous version?
With Maven, this could have unwanted impact on resolved versions.
Apache Ivy is a very flexible dependency management tooling. It offers the possibility to customize dependency resolution, including conflict resolution.
This flexibility comes with the price of making it hard to reason about.
Gradle will consider all requested versions, wherever they appear in the dependency graph. Out of these versions, it will select the highest one.
As you have seen, Gradle supports a concept of rich version declaration, so what is the highest version depends on the way versions were declared:
If no ranges are involved, then the highest version that is not rejected will be selected.
- If a version declared as
strictly
is lower than that version, selection will fail.If ranges are involved:
If there is a non range version that falls within the specified ranges or is higher than their upper bound, it will be selected.
If there are only ranges, the highest existing version of the range with the highest upper bound will be selected.
If a version declared as
strictly
is lower than that version, selection will fail.Note that in the case where ranges come into play, Gradle requires metadata to determine which versions do exist for the considered range. This causes an intermediate lookup for metadata, as described in How Gradle retrieves dependency metadata?.
-- https://docs.gradle.org/current/userguide/dependency_resolution.html#sec:version-conflict
Upvotes: 1