[ 
https://issues.apache.org/jira/browse/MNG-7852?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17749133#comment-17749133
 ] 

Vladimir Sitnikov commented on MNG-7852:
----------------------------------------

{quote}There is no proper versions nevermind which version we choose during 
resolving transitive dependencies, alway we can have an incompatibilities 
between two versions.
{quote}
The current Maven's algorithm results in *{*}downgrading{*}* versions.
Downgrading dependency versions is very often an incompatible change.

On the other hand, upgrading a version is more likely to produce a workable 
classpath because many libraries maintain backward compatibility (== further 
versions are compatible with previous versions).
----
Let us quantify this.
Imagine lib-a with Guava 21 (see 
https://issues.apache.org/jira/browse/MNG-7852?focusedCommentId=17748217&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-17748217)

Imagine I use lib-a in my project.
Imagine Maven selects Guava 19 for the runtime (e.g., another library 
introduced guava-19 a little bit earlier in the dependency tree).
Of course, the thing will fail at the runtime because lib-a might easily depend 
on a method added in guava-21.

Who will be to blame? Of course, {*}Maven would be to blame{*}, as it 
downgraded guava from 21 to 19.

Imagine an alternative case.
Imagine I use lib-a in my project.
Imagine Maven selects Guava 30 for the runtime.
Of course the thing might fail at the runtime (e.g. if Guava 30 accidentally 
fails to keep backward compatibility).

Who will be to blame in such case? Of course, {*}it would be Guava to blame{*}, 
and it is unlikely to break as Guava team tests backward compatibility.
----
In other words, almost no library tests for "forward compatibility". In other 
words, almost nobody ensures that people can compile code with the recent 
version and supply an old version in the execution.
At the same time, many teams verify backward compatibility. That means, 
upgrading dependencies is much safer than downgrading them.

 

The current Maven's algorithm seems to select semi-random transitive versions 
which are both unpredictable and might cause downgrades.

> Use all the versions for dependency resolution rather than "nearest first" or 
> "declared first"
> ----------------------------------------------------------------------------------------------
>
>                 Key: MNG-7852
>                 URL: https://issues.apache.org/jira/browse/MNG-7852
>             Project: Maven
>          Issue Type: Improvement
>          Components: Dependencies
>            Reporter: Vladimir Sitnikov
>            Priority: Major
>
> Currently, Maven uses "nearest first", "declared first" rules for conflict 
> resolution: 
> https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html
> I suggest those rules are removed since they produce hard to reason 
> resolutions for transitive dependencies.
> Below I list reasons why both "nearest wins" and "declared first" yield 
> hard-to-predict behaviours, and they are likely to produce dependency 
> downgrades and the associated runtime errors.
> Here are some examples:
> 1) "Nearest first". Even though the rule sounds easy, it is not something the 
> users can control. For instance, if the project does not use Guava library, 
> some of the transitive dependencies could add a dependency on Guava. The user 
> has no control which dependency would be "the nearest" to declare Guava, so 
> user has literally no way to tell which Guava version will be used.
> The only workaround I see for the users is to declare Guava dependency 
> explicitly even though the project does not need it directly. It sounds like 
> Maven requires users to re-declare all the possible dependencies, including 
> the runtime-only ones.
> 2) "declared first". Of course, dependency order matters for classpath order, 
> however, it is not predictable in practice, and it might result in 
> downgrading dependencies. Imagine the project does not use Guice. However, 
> transitive dependencies might use Guice. At the same time, they might start 
> using Guice and stop using Guice, so the user can never tell which will be 
> the first project that uses Guice. Unfortunately, in Maven, the first project 
> that declares dependency wins, so  it might easily be the case that the first 
> mention of Guice will reference outdated version that would be incompatible 
> with the newer one required in another dependency.
> 3) Here's a real-life case: Maven downgrades protobuf-java dependency causing 
> something like NoSuchMethodError at the runtime. The step to reproduce is to 
> add dependency on dev.sigstore:sigstore-java:0.4.0. See [~hboutemy] analysis 
> in https://github.com/hboutemy/sigstore-maven-plugin/blob/import/analysis.md
> Long story short, sigstore-java does not depend on protobuf-java directly, 
> however, sigstore-java depends on several third-party libraries that 
> eventually depend on protobuf-java. Maven's "the first wins" behaviour 
> results in incoherent set of protobuf dependencies on the classpath.
> 4) see "unexpected" in MNG-5988
> To my best understanding, when it comes to transitive dependencies, both 
> "nearest first" and "declared first" are random variables which user can't 
> control unless they re-declare all the dependencies in their local pom. I 
> suggest Maven should not use random variables like "dependency depth" or 
> "dependency order" to drive conflict resolution.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to