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

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

{quote}This "real life example" is totally along the lines of Maven specd 
behaviour
{quote}
Tamas, many thanks for your comments, however, I still struggle to figure out 
{*}{{*}}why{{*}}{*} Maven behaves like "nearest first".
The behaviour produces hard-to-reason failures, and it is unclear what could be 
the benefits of such an algorithm except "dumb-easy to implement".
{quote}As you (I guess) implied, this can be solved by multiple means, ideally 
by depMgmt. And yes, Maven makes you able to "not care", unlike Ant and others, 
where you need to enlist (and control) all the versions, with Maven you leave 
this to resolution. Or in other words, IF you care ("user has no control"), 
then use proper means like depMgt to sort out your issues.
{quote}
I am afraid I do not understand the suggestion here.
Imagine
 * I'm the author of my-lib
 * my-lib does not use guava
 * my-lib uses both lib-a and lib-b which are third-party libraries, and I have 
no direct control over them
 * lib-a uses guava 21 (==it depends on classes added in guava 21, and it would 
work fine with guava 23)
 * lib-b uses guava 23 (== it depends on a class that was added in guava 23 
only, and it would fail with guava 21)

What is your exact suggestion?

Do you suggest that I (as an author of my-lib) should explicitly mention 
"my-lib requires guava 23 on the runtime scope"? Of course, it would workaround 
the issue, however, it is exactly the duplication I do not like. As an author 
of my-lib, I do not really want to manually collect all the third-party 
transitive dependencies and figure out the compatible versions for them. I 
expect that dependency manager would do that.

At the same time, if I just add both dependencies on lib-a and lib-b, then 
Maven would resolve a *{*}random{*}* guava version depending on which of lib-a 
or lib-b was first on the list and/or which of them listed guava "closer to the 
dependency root". Please, acknowledge that "dependency deepness" is random, and 
I don't control which of lib-a or lib-b would put guava deeper.

In other words:
 * If I omit guava in my-lib, then Maven resolves random version, and I get 
crashes when Maven resolves guava 21 (e.g. lib-a was the first)
 * If I list guava in my-lib, then I would have to list every possible 
transitive dependency explicitly, and my list might easily get out of date. 
That is not much different from using wget and putting jars on the classpath.

If Maven resolved all the versions no matter how deep they were declared, then 
Maven could figure out the latest version, and it would avoid runtime failures.
----
 
{quote}Given this example is "oddly specific", I'd assume here some integration 
happens (DI container is expected at runtime), so yes, here you should either 
use "aligned libraries" (not always possible, especially if they are from 
multiple vendors) or then it is up to you to sort out the conflicts between 
them. Many many tools out there, ranging from Maven plugins to IDEs help you 
doing this.
{quote}
I am afraid I do not understand your suggestion here :(

Imagine the case is:
 * I'm the author of my-lib
 * my-lib does not use guice
 * my-lib uses both lib-a and lib-b which are third-party libraries, and I have 
no direct control over them
 * lib-a does not use guice
 * lib-b uses guice 5
 * Imagine my-lib declared dependencies in order of "lib-a, then lib-b", 
because, well, it was just fine

So far, so good. 

Then:
 * lib-a started using guice 3

Maven would cause runtime failures, because it would resolve guice 3, while 
lib-b required guice 5.

I do not understand why do you suggest resorting to third-party plugins and 
IDEs even for such a trivial case like library with a couple of transitive 
dependencies.

I understand that I can workaround the case by declaring guice version 
explicitly, however, I do not understand why Maven requires duplicating 
dependency information. If Maven discovered all the versions (guice 3 and guice 
5), then it could resolve the conflicts and come up with guice 5 on the 
classpath.
----
 
{quote} you mention "no such method" with protobuf-java, so I assumed Maven 
"wildly mixed" versions (like major ones), but to me it seems you talk about 
this issue{quote}

No. protobuf-java issue is not 11393, but it is like "Maven downgraded 
protobuf-java dependency, so the app failed".
Here's the error message: https://youtu.be/2kooPqDguyw?t=7087

In other words: sigstore-java used protobuf compiler 3.22, however, Maven 
resolved protobuf-java 3.21 for the runtime. It failed with the dreaded 
emptyList error leaving maven users no clue on the way to fix it.


----

{quote}Best would be to move this discussion to ML instead, preferably the 
users mailing list https://maven.apache.org/mailing-lists.html{quote}

I thought users@maven list is for users searching for a piece of advice on the 
way to resolve things with Maven, however, I believe I have strong case that 
Maven itself should be improved, and it should stop using "dependency depth" 
and "dependency order" for conflict resolution.
Are you sure users@maven is the right list to discuss such a topic? Of course, 
I can send a message to users@maven, however, I thought the question was more 
related to dev@maven or JIRA which I just created. I do not want to subscribe 
to dev@maven / users@maven, so creating JIRA was easier for me.


> 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