Transitive effect of dependencyManagement - java

In Maven you can override the version number of a transitive dependency by an entry in dependencyManagement because dependencyManagement takes precedence over transitive dependency definitions.
But what about dependencyManagement definitions in the poms of (transitive) dependencies? Are they considered at all? If so, what do they override, how are they overridden?

Dependency management is implied to be transitive. There doesn't need to be a special rule for this, but rather it's a consequence of the already mentioned rules: Transitive Dependencies.
Consider this example structure:
your module
A - dependency
D - transitive dependency
B - dependency
D - transitive dependency
When A or B are built, their corresponding dependencyManagement section is checked to pick version for D, if it's not explicitly specified. Here's the important part: exactly the same process is used when A or B are used as dependencies to determine which version of D they depend on. Consequently, they do not affect each other in any way.
This could result, for example, in A depending on D:1.0, and B depending on D:1.1, their dependencyManagement sections have already been applied at this point to determine this and will not be taken into account anymore. With this information as input, dependency mediation rules are applied to pick just one version of D for your module.
Dependency mediation rules are also described in the linked page. But in a nutshell, the nearest definition wins and ties are broken based on order. Naturally, definitions in your module itself are always the nearest.
Now let's say your module is used as a dependency. Your project could depend on D:1.2 based on all the rules above due to a definition in your dependencyManagement section, but that's where the scope of your dependencyManagement ends.
(Note that import scope is an exception as it behaves completely differently from the other scopes.)

dependencyManagement definitions in the poms of transitive dependencies are considered as long as they are not been overridden in the dependencyManagement of your project or a closer dependency (in the tree of dependencies).
in another words,
Dependency mediation: the rule is easy
"nearest definition" which means that it will use the version of the closest dependency to your project in the tree of dependencies.
if two dependency versions are at the same depth in the dependency tree, the first declaration wins (declaration order).
for more details see Transitive Dependency
hope this helps.

Related

Using dependency management in a child pom

Is there any reason to use the dependency management section in a child pom? I'm looking at a maven project in my organization that uses inheritance and aggregation, where the parent and child poms both have a dependency management section. Is the child one doing anything?
I found this question really helpful but didn't find the answer to my specific question - Differences between dependencyManagement and dependencies in Maven
It can be used to control the version of transitive dependencies (libraries that your direct dependencies depend on) without adding a direct dependency.
Child POM will add or override dependency management entries of the parent POM.
Keep in mind that you really, really don't want to have different versions of the same dependency in your codebase. So use this feature judiciously. Preferably you should have organization-wide parent POM file with all dependency versions defined and child POMs don't change them.
In a child pom it does not make sense.
In a multi module setup you should control everything for all children in the parent. For example solve version conflicts / excluding transitive dependencies or import BOM files from other frameworks/libraries (for example spring boot/junit 5/etc.) makes handling of those libs including the centralised maintenance location...

Maven: how to handle conflicting dependencies

I want (have to) to use two maven dependencies "Y" and "G" next to each other, while they share the same dependency with different versions.
By default behavior, the older version will be overwritten by the newer one. However this would ruin the performance.
How can I isolate the two dependencies and make sure they use their proper dependency?
By default behavior, the older version will be overwritten by the newer one.
This is not true. By default, Maven uses the nearest definition strategy when resolving conflicting versions of the same dependency. It does not necessarily take the new version. This means that the version declared by a POM at a higher level in the dependency tree overrides versions declared in lower level POMs. In case the two versions are on the same level, as is the case in your diagram, the one declared first is taken.
The best way to force a specific version of the dependency is to explicitly define a dependency in the parent POM inside a dependencyManagement section:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>groupId-z</groupId>
<artifactId>dependency-z</artifactId>
<version>1.0</version>
</dependency>
...
Then all of the child projects and their dependencies will automatically use the specified version.
For more details on dependency conflict resolution in Maven, see this page.
Assuming that "X" is one module which has dependencies on both Y and G, then the answer depends on how it is being run. For example: if X is a WAR containing Y and G, then you won't be able to have two different versions of the same dependency or you'll run into class loading issues.
Could you not therefore explicitly declare the correct version for Y and G in their own POMs for when they are used independently, but override it to the necessary shared version when they are being used side by side?

Maven dependency version conflict resolution: Which is better, adding exclusion, or adding a dependency?

We have a case in our dependency tree where we have two version of the same jar coming in from different sources, the version we want to use is lower in the tree, so maven is picking the other version using the nearest wins method.
To resolve this, We could either exclude this incorrect version from its source dependency, or directly add that version as another dependency in our pom.
I preferred the latter since it is quicker. But I am not sure if that is the best way of doing it, or are their any drawbacks of adding a dependency. So, is adding an exclusion better than what I did? In what cases and how?
I would suggest to explicitly define your dependency in order to make it clear which version you are expecting through transitive dependencies.
Although you would normally declare only dependencies directly referenced by your code (i.e. you use import statements in Java to include classes from these dependencies), it is also recommended to have control over your dependencies resolution via explicit declaration. Explicit declaration will have priority over Maven dependencies mediation.
Exclusions make your build harder to maintain and potentially you would need to replicate the same exclusion over and over if, for instance, the same dependency would be required transitively via other dependencies and every time with a different version (not the one you want). Moreover, exclusions can have undesired effects as it may take precedence when it is not expected.
Declaring it as part of your dependencies makes it clear, centralized and easier to update/maintain in the future.
Update: An even better approach is to use the dependenciesManagement section, which also takes priority over Maven dependencies mediation, as stated in the official documentation, here
dependency management takes precedence over dependency mediation for transitive dependencies

Different scopes of the same artifact and transitive dependencies issue

I have a project A that use library L v1.0.0 with test scope. Project A also depends on project B (with scope compile), with B transitively depending on the library L v1.0.0 (with scope compile).
Why the final scope of the library L for project A is 'test'? It causes me NotClassDefFoundError at runtime. It seems that the dependency definition of project A on library L overrides those of the transitive dependencies on L.
What's wrong here? My project A only uses L for unit tests so I define the dependency with 'test' scope. But, at the end, I want L to be on my classpath since project A depends on project B for production, and B needs (transitively) library L.
Thanks for helping me
Are you using Maven? In that case, if I remember correctly Maven will use the "nearest" definition to determine the actual scope. In this case module A specifies test and the transitive scope from B is overridden, because A is nearest since you're actually in A :)
This gets more complicated when you have multiple modules with dependencies between them.
A common cure is to define all dependencies (and scopes and versions) in a common parent Pom.xml in the <dependencyManagement> tag.
As an alternative to Peter's suggestion, just leave L out of the dependencies for A. You should be able to access it anyway, and Maven will treat it as a compile-scoped dependency.
This hides that A's tests depend on L, though.

Maven: How do you deal with dependencies that are both direct and transitive?

I'm trying to determine an approach to the following situation:
There are 3 Maven artifacts: A, B, and C.
B depends on A. (i.e. it uses some of A's code)
C depends on both A and B (i.e. it uses some of A's code and B's code).
Assume I want to use the same version of A for both B and C.
What approach should be used?
1) Declare A as a dependency in C's pom.xml.
Pro: It's clear to the developer that C depends on A.
Con: If A's version changes, it needs to be updated in multiple places. (both B and C)
2) Don't declare A as a dependency in C's pom.xml.
Pro/Con: Opposite of option 1.
I think you should have all direct dependencies declared in your pom. Transitive dependencies are just a convenience for automagically resolving your dependencies dependencies.
If you change a version of a direct dependency, the transitive dependencies will likely change along with it, and thus potentially breaking the module. The module should build as an independent unit and thus should have well defined dependencies that will not break due to external changes.
I disagree that this violates the DRY principal, as maven defines things within the confines of a single project and its pom. And within this scope there is no repetition.
Update:
The reliance on transitive dependencies existing makes the project frail on it's own, and may also lead to more complex issues like when to include it.
For example, if C has a compile dependency on A, but a runtime dependency on B, then you now have to either add the dependency (since it is no longer in your build path) or declare B as compile even though it isn't. There is a lot to be said for clarity. Explicitly define what your dependencies are and what their scope is, and expect your dependencies to do the same. For the most part, your dependency is a black box, until it causes problems and you have to open it.
1) Declare A as a dependency in C's pom.xml.
The dependency is readableDependency is flexible. If you want to remove A's dependency from B, you do not need to think of the projects that dependend on B.As suggested in other answer, that it is a good practice to write down direct dependencies in pom.xml and let maven handle it.
2) Don't declare A as a dependency in C's pom.xml.
Mostly, no developer going to see pom.xml. And if they want they can see it by using mvn dependency:tree and it will show transitive dependency.There will be single point of change when a new version of A is released. If you define dependency at more than one place, you may forget to update all the places. In that case, Maven automatically uses the latest one. But, it does sting sometimes. Some people prefer this because, mostly, this type of dependency is common knowledge (e.g. MyWebApp -> MyWebAppLib -> MySharedLib and MyWebApp -> MySharedLib) and they want to avoid added step of updating versions at multiple places on each release.
I have written down pros-and-cons, you should evaluate what suits you the best yourself.
Edit#1: tsk! I have switched my comments.
Edit#2: updated the answer after a discussion done on this answer.

Categories