Reputation: 2076
I looked for these answers on google but couldn't find exact answers to my questions, usually just an overview on Maven and the pom and the lifecycle phases. My exact questions are:
spring-boot-starter-jpa-1.X.X
version listed in its POM. Now say I also declare spring-boot-starter-jpa-2.X.X
(notice the version) directly in Java Project-A's POM. If I understand transitive dependencies correctly, the spring-boot-starter-jpa-1.X.X (from Dependency-X db project) will get imported transitively (indirectly) through the Dependency-X (db) project. So which dependency wins? which gets imported? Being that they are two-different versions, that's obviously a problem. Do you have to explicitly add an <exclusion>
tag to all your dependencies in your POM that PULL in other transitive dependencies that conflict with your projects current dependencies???<repositories>
list (assuming you had more than 1 repo listed) your pom, it will go down the list 1-by-1 until it finds it correct?
i.e.<dependency>
<groupId>org.mydependency</groupId>
<artifactId>dependency-a</artifactId>
<version>6.6.6</version>
</dependency>
<dependency>
<groupId>org.mydependency</groupId>
<artifactId>dependency-a</artifactId>
<version>8.8.8</version>
</dependency>
<parent></parent>
tags with a dependency inside, and I can click ctrl + B (windows) or command + B (mac) and it will take me to source pom (parent) and I can view all the contents. How is this working - where is it getting this file from?Are all "parent" poms, like the "spring-boot-starter-jpa" dependencies literally just pointing to POM files on the maven central repo, which further point to individual JARS, that maven resolves and imports into your project???
i.e.
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.4</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>${spring.boot.version}</version>
</dependency>
Upvotes: 0
Views: 882
Reputation: 131506
How exactly is the parent-pom working? I
You seem to want to understand how project inheritance works in Maven. It is a vast subject. That addresses the major way to structure a pom (which project inheritance) and the consequences associated to .
About your two first questions :
So which dependency wins? which gets imported?
what happens when you include the same dependency two times which different versions; which gets selected/imported into your project and how does Maven decide that?
While your question make sense, Maven doesn't provide any specific guarantee about that over the time. The outcome in case of conflicted version is just an implementation detail.
I prefer tell you that in order to guarantee a consistent packaging according to your requirements in terms of dependency versions, you have to perform a explicit check for that.
You can implement it or just use maven plugins such as the maven-enforcer-plugin with existing rules such as :
The rule lists is really dense and you can even write your own rule if no one matches your need.
Example on how to declare the plugin execution with the dependencyConvergence rule :
<project>
...
<build>
<plugins>
...
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<version>3.0.0-M3</version>
<executions>
<execution>
<id>enforce</id>
<configuration>
<rules>
<dependencyConvergence/>
</rules>
</configuration>
<goals>
<goal>enforce</goal>
</goals>
</execution>
</executions>
</plugin>
...
</plugins>
</build>
...
</project>
Upvotes: 0
Reputation: 35853
Usually, the "nearest" dependency wins if you have different versions of the same jar in the dependency tree.
You can override this behaviour by explicitly setting a version for a transitive dependency in <dependencyManagement>
. Don't use exclusions to manage versions.
Parents are resolved like dependencies, i.e. from the repositories like MavenCentral.
The contents of the parent and of your POM are "merged", leading to the "effective POM" which you can view on command line or in an IDE.
Upvotes: 0
Reputation: 93
As far as resolving transitive dependencies are concerned, the shortest path wins. This is also documented here.
Dependency mediation - this determines what version of an artifact will be chosen when multiple versions are encountered as dependencies. Maven picks the "nearest definition". That is, it uses the version of the closest dependency to your project in the tree of dependencies. You can always guarantee a version by declaring it explicitly in your project's POM. Note that if two dependency versions are at the same depth in the dependency tree, the first declaration wins.
"nearest definition" means that the version used will be the closest one to your project in the tree of dependencies. Consider this tree of dependencies:
A
├── B
│ └── C
│ └── D 2.0
└── E
└── D 1.0
In text, dependencies for A, B, and C are defined as A -> B -> C -> D 2.0 and A -> E -> D 1.0, then D 1.0 will be used when building A because the path from A to D through E is shorter.
so which dependency wins? which gets imported?
boot starter jpa 2.x wins since that has the shortest path.
For multiple versions of the same dependency, I would recommend running
mvn dependency:tree
to see which one gets included or if there is an error.
How exactly is the parent-pom working?
The parent pom is just a reference to a project which the current project "inherits" from. There are certain rules on how the dependencies are resolved from parents. Most important thing in my opinion is that the parent allows you add dependencies for common sibling projects in a place where all of them can inherit their dependencies from. Spring boot follows this pattern to introduce starter pom version resolution. Offcourse, having a parent pom is optional and you can have a project without one.
Upvotes: 1