0

I was studying Maven's build system and it adds a lot of transitive dependencies because of its transitive dependency system (maven itself does not add dependencies but transitive dependency system does). I see issues with it like major version conflicts and unknown dependencies coming in.

I was thinking why is the system designed this way and why not take direct dependencies. My library does not need to depend on something which my dependency is using but not my library (I mean I understand why it needs to be included in the build list, my dependencies need to build using those, but why does it needs to cause major version conflict?). Am I missing something fundamental here? One thing that I can think of is that my library's build dependency list can grow to be very big because of all the direct dependencies I will need to take, but that does seem to be as big of a problem as problems with transitive dependency system.

I am new to build systems, so please don't be too harsh. I also tried to google this question but didn't find useful answers but please feel free to comment anything that I might have missed.

Thanks

as2d3
  • 802
  • 2
  • 10
  • 27
  • Can you explain what you mean by: `and it adds a lot of transitive dependencies.` ? Maven does not add itself something. It only adds the dependencies of your own. Furthermore a misleading things is: `My library does not need to depend on something which my dependency is using but not my library.` If your library is depending on a library this means your own library depends on that as well. If your library is using a dependency (lets call it x) x also has dependencies which means that your own library depends on x as well... – khmarbaise May 31 '21 at 13:32
  • @khmarbaise Clarified the question, please see now. – as2d3 May 31 '21 at 13:49
  • A library lets call it X needs dependencies (lets call it Y).. So if you use X you are indirectly using Y that's why the transitive dependencies must be there and technically speaking are on the classpath. Otherwise you could compile but would fail at runtime...I don't understand this: `and why not take direct dependencies`? explained before... – khmarbaise May 31 '21 at 13:56
  • This sentence: `I see issues with it like major version conflicts and unknown dependencies coming in.` First. Unknown dependencies? Are coming from where? Because all dependencies are defined by entries in your pom which means the tree is known.. there is no dependency magically introduced. – khmarbaise May 31 '21 at 13:58
  • @khmarbaise Okay, can you just explain why major version conflicts happen? That might clarify my doubt and I'll modify my question accordingly. – as2d3 May 31 '21 at 13:58
  • @khmarbaise By unknown dependencies, I meant that I need to see the whole tree to resolve conflicts because I don't even know directly what is coming from where. – as2d3 May 31 '21 at 14:00
  • 2
    Ah Ok.. Now I get it. Ok You are using two libs X and Y. Both of them using another lib (A) So X is using A in version 1.0.0 but Y is using A in version 2.0.0. In the end you can't have both on the classpath there must be done a decision for one version. So depending on how X,Y are implemented either X can fail while using A in V1.0.0 or Y can fail in using A in V1.0.0 or with V2.0.0 the same... This can happen if X or Y are being updated. This is also true for different version combinations like A in 1.0.0 and 1.1.0 (if compatibility is not 100%)... – khmarbaise May 31 '21 at 14:10

2 Answers2

0

If you need library A to run, and library A needs library B to run, and this needs C to run, it is very tedious to figure this out and add all the relevant dependencies to your project.

Before Maven and Gradle, many people worked that way and found out, that it is much easier to let a build tool figure out the transitive dependencies.

J Fabian Meier
  • 33,516
  • 10
  • 64
  • 142
  • So to get all the dependencies to build, we can take transitive dependency, but why can't my final list of dependencies need to be resolved for major version conflict? – as2d3 May 31 '21 at 13:38
  • Sorry, I don't understand this question. Which conflict? – J Fabian Meier May 31 '21 at 13:45
  • Maybe this helps explain: https://stackoverflow.com/questions/7175398/maven-dependency-resolution-conflicted. If not then let me study more about Maven and get back to this question. – as2d3 May 31 '21 at 13:52
0

My library does not need to depend on something which my dependency is using but not my library [...]

This is your major misconception. There are two possibilities:

  1. The direct dependency of your library exposes types from the transitive dependency in its public API. To use this public API you need to access these types, so you need the transitive dependencies during compile time.

  2. The direct dependency of your library only uses its own dependency internally, but not in its public API. In this case, your library does not need to depend on the transitive dependency during compile time. But as soon as your library code runs (even in a test), it may use some functionality of its direct dependency that internally uses functionality of the transitive dependency, causing your library code to fail.

[...] I mean I understand why it needs to be included in the build list, my dependencies need to build using those [...]

There is no actual build list (or order) for external dependencies, because they are used when they are already built (the downloaded .jar files contain compiled .class files). But as I mentioned above, you will need the transitive dependencies either during compile time or during runtime (e.g. tests), so your build system (Maven or Gradle) will fetch them for you.

[...] but why does it needs to cause major version conflict?

@khmarbaise already explained in his comment, why and how version conflict between transitive dependencies may occur:

You are using two libs X and Y. Both of them using another lib (A) So X is using A in version 1.0.0 but Y is using A in version 2.0.0. In the end you can't have both on the classpath there must be done a decision for one version. So depending on how X,Y are implemented either X can fail while using A in V1.0.0 or Y can fail in using A in V1.0.0 or with V2.0.0 the same... This can happen if X or Y are being updated. This is also true for different version combinations like A in 1.0.0 and 1.1.0 (if compatibility is not 100%)

Lukas Körfer
  • 13,515
  • 7
  • 46
  • 62