I have the following maven structure.
Parent Pom
<dependencyManagement>
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-client</artifactId>
<version>2.27</version>
</dependency>
</dependencyManagement>
Service Pom
<parent>
<groupId>com.aliseeks.dependencies</groupId>
<artifactId>AliseeksLive</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-client</artifactId>
</dependency>
</dependencies>
Dependency Conflict:
[INFO] +- org.glassfish.jersey.core:jersey-client:jar:2.27:compile
[INFO] | +- org.glassfish.jersey.core:jersey-common:jar:2.25.1:compile
[INFO] | | +- org.glassfish.jersey.bundles.repackaged:jersey-guava:jar:2.25.1:compile
Why does Maven pull in JerseyCommon 2.25? JerseyClient 2.27 clearly depends on JerseyCommon 2.25? Is this because JerseyClient 2.27 POM has ${project.version} as a variable and its somehow getting messed up with Dependency Management?
Dependency Tree Dump
jersey-client 2.27 version depends on jersey-common 2.27 version as per following link:
https://mvnrepository.com/artifact/org.glassfish.jersey.core/jersey-client/2.27
But it is definitely pulling 2.25 version of jersey-common after resolving transitive dependencies and maven finds 2.25 version as the nearest child. That's reason it decides to pull 2.25 version.
For the reference that such type of dependency conflict issues can be easily investigated with the help of maven-enforcer-plugin. Following link further explains usage of this plugin with example:
https://dzone.com/articles/solving-dependency-conflicts-in-maven
Related
The problem I encountered is this, here is the definition in my POM file.\
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.0.0.RELEASE</version>
</dependency>
In this dependency, It's having a sub-dependency which is starter-tomcat
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<version>2.0.0.RELEASE</version>
<scope>compile</scope>
</dependency>
But In my maven tree
[INFO] +- org.springframework.boot:spring-boot-starter-web:jar:2.0.0.RELEASE:compile
[INFO] | +- org.springframework.boot:spring-boot-starter-tomcat:jar:2.3.6.RELEASE:compile
By the way this project have a parent, In parent There is a 2.3.6 starter-webdependency.
I want to know why the sub-dependency starter-tomcat in the web-starter I referenced 2.0.0 is not the 2.0.0 I see, but 2.3.6 in the parent dependency.
I got it.
There are two ways to solve this question
exclude your sub-dependency and add a new version dependency.
use to control this denpendency
I use IDEA,My springboot app contains multiple modules like that:
parent
-web
-service
-dao
There is a jar dependency common:1.2.0-SNAPSHOT in service module defined in pom.xml, I updated its version to 1.3.0-SNAPSHOT, after that i do maven reimport and run mvn clean install -U but these two versions still in dependencies list, and in dependency tree, two jar in the dependencies, also when i run the app, it throw NoClassDefFoundError error which i added in 1.3.0-SNAPSHOT
This is my maven dependenct tree:
service:jar
+- dao:jar
\- common:jar:1.3.0-SNAPSHOT
web:jar
+- service:jar
+- dao:jar
\- common:jar:1.2.0-SNAPSHOT
\- others:jar
service pom dependency:
<dependency>
<groupId>com</groupId>
<artifactId>common</artifactId>
<version>1.3.0-SNAPSHOT</version>
</dependency>
How can i update the dependency?
As #Haroon #chrylis said, i checked the parent pom.xml and found <parent> configured in this pom.
<parent>
<groupId>insight.plat</groupId>
<artifactId>insight-bom-base</artifactId>
<version>1.0.0-SNAPSHOT</version>
</parent>
in pom insight-bom-base, common 1.3.0-SNAPSHOT is configured, so web module depend this version not version 1.2.0-SNAPSHOT.
<dependencyManagement>
<dependency>
<groupId>com</groupId>
<artifactId>common</artifactId>
<version>1.2.0-SNAPSHOT</version>
</dependencyManagement>
As maven doc Transitive Dependencies shows,
Dependency management - this allows project authors to directly specify the
versions of artifacts to be used when they are encountered in transitive
dependencies or in dependencies where no version has been specified.
In the example in the preceding section a dependency was directly added to A even though
it is not directly used by A.
Instead, A can include D as a dependency in its dependencyManagement section and directly
control which version of D is used when, or if, it is ever referenced.
The parent dependencyManagement has higher priority than Transitive Dependencies, so in service module, it use common 1.2.0-SNAPSHOT
I have such configuration in pom.xml:
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.9.4</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.4</version>
</dependency>
But unfortunately mvn dependency:tree shows me that commons-beanutils has dependency: commons-collections 3.x:
[INFO] +- commons-beanutils:commons-beanutils:jar:1.9.4:compile
[INFO] | \- commons-collections:commons-collections:jar:3.2.2:compile
[INFO] +- org.apache.commons:commons-collections4:jar:4.4:compile
I don't want Common Collection 3 in my code but it's possible that someone uses a class from this library by mistake (instead of Common Collective 4, which is preferred version).
As you see in dependency tree - I can't exclude the Common Collection 3, because it is used (can occur java.lang.NoClassDefFoundError).
Question:
How to protect my code base against pollution of Commons Collection 3 API?
You can use the dependency:analyze-only
https://maven.apache.org/plugins/maven-dependency-plugin/analyze-only-mojo.html
to check whether you use undeclared dependencies, i.e. you use a transitive dependency without explicitly declaring it.
If you don't want this in your build, but just check it occasionally, you can use dependency:analyze from the command line.
Consider following pom.xml using maven 3.6.2
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>foo</artifactId>
<groupId>bar</groupId>
<version>1.0.0</version>
<dependencies>
<!-- #1
<dependency>
<groupId>org.jdbi</groupId>
<artifactId>jdbi3-jackson2</artifactId>
<version>3.12.0</version>
</dependency>
-->
<dependency>
<groupId>org.apache.kafka</groupId>
<artifactId>kafka_2.12</artifactId>
<version>2.4.0</version>
<scope>compile</scope>
</dependency>
<!-- #2
<dependency>
<groupId>org.jdbi</groupId>
<artifactId>jdbi3-jackson2</artifactId>
<version>3.12.0</version>
</dependency>
-->
</dependencies>
<!-- #3
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.jdbi</groupId>
<artifactId>jdbi3-bom</artifactId>
<type>pom</type>
<version>3.12.0</version>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
-->
<properties>
<maven.compiler.target>11</maven.compiler.target>
<maven.compiler.source>11</maven.compiler.source>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>
</project>
If you run mvn dependency:tree | grep databind you should see:
[INFO] +- com.fasterxml.jackson.core:jackson-databind:jar:2.10.0:compile
This is the baseline and establishes kafka_2.12 uses jackson-databind:2.10.0
If you uncomment only comment #1 and re-run, then you should see:
[INFO] | +- com.fasterxml.jackson.core:jackson-databind:jar:2.9.9.3:compile
This makes sense to me and tells me jdbi3-jackson2 uses jackson-databind:2.9.9.3 and this version is used because it appears before kafka_2.12
If you uncomment only comment #2 and re-run, then you should see:
[INFO] | +- com.fasterxml.jackson.core:jackson-databind:jar:2.10.0:compile
This also makes sense to me because jdbi3-jackson2 now appears after kafka_2.12
If you uncomment only comment #3 and re-run, then you should see:
[INFO] +- com.fasterxml.jackson.core:jackson-databind:jar:2.9.9.3:compile
I expected 2.10.0 because I am not using anything from the bom (specifically jdbi3-jackson2)
Based on almost everything everyone says about boms, I would have thought that their version information would only be used when applying a dependency in the bom
Further, if I add the following anywhere in dependencyManagement then it goes back to 2.10.0:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.10.0</version>
</dependency>
how do I detect this issue (I only found this out because kafka will fail and tell you it requires a specific jackson). My thought is to write a script/plugin that compares dependency:tree against a 'golden' copy and fail if they differ to at least make people double check their changes when modifying dependencyManagement
how do I exclude a dependency from dependencyManagement? I have done it with normal dependencies and the same exclusions tag exists for dependencyManagement, but nothing I try works. I would assume the excludes takes effect when you actually use the dependency, but I also thought the version would only take effect when you actually use the dependency as well but that assumption appears to be wrong.
because I cannot exclude it, I can force the version via the method above, but why does it work irrespective of the order when it is in dependencyManagement unlike where order matters in the normal dependencies tag?
For #1. I recommend to use maven-enforcer-plugin
For #2. You can only exclude direct transitive dependencies.
For #3. The algorithm decides based on the nearest definition which means the nearer the dependency is to your project it will be selected.
First of all, BOMs override transitive dependencies. If a dependency somewhere appear in your dependency tree and the BOM specifies a version for it, that version wins, unless:
You defined the dependency yourself with a different version.
You added a dependencyManagement entry yourself overriding the value in the BOM.
Also, of course, if BOMs overlap, only one can win.
So if you have jackson-databind as a transitive dependency and you have a BOM that includes it, you get the version from the BOM. Unless you make a dependencyManagement entry yourself that overrides the BOM.
I have a following problem - I am trying to use apache commons-lang version 2.6 in my project (which is defined in the pom.xml) but due to transitive dependency maven always add version 3.2.1 which breaks my build.
Here is relevant part of pom.xml
<properties>
<commons-lang.version>2.6</commons-lang.version>
</properties>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>${commons-lang.version}</version>
</dependency>
and when I try to run mvn dependency:tree I can see the reason is transitive dependency of
+- org.seleniumhq.selenium:selenium-api:jar:2.26.0:compile (version managed from 2.26.0)
+- net.sourceforge.htmlunit:htmlunit:jar:2.10:compile
+- org.apache.commons:commons-lang3:jar:3.1:compile
So I can see the problem but I have really no idea how to fix it. Thanks for any suggestions:-)
Look into using an exclusion tag inside the dependency that's causing the problem. An exclusion tag tells maven that you don't want maven to bring in an indirect dependency and is used in just this situation.
For example, if one of my dependencies A brings in a version 1.0 of B but I want to use version 2.0 of B instead, I could do this:
<dependency>
<groupId>org.mycorp</groupId>
<artifactID>A</artifactID>
<version>4.0</version>
<exclusions>
<exclusion>
<groupId>org.mycorp</groupId>
<artifactId>B</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.mycorp</groupId>
<artifactID>B</artifactID>
<version>2.0</version>
</dependency>
The exclusion tag says to not bring in the indirect dependency (B 1.0) in this case. Note that you don't have to give the version. Once you've told maven not to automatically bring in that version of B, you follow with an explicit dependency that defines which version of B (version 2.0, in this case) you do want.
This particular dependency should not break your build, because Commons Lang 3 uses different package naming than Lang 2. Your code should use the classes from Lang2, while HTMLUnit will use the classes from Lang3, and both JARs can co-exist.
Perhaps you should describe how you think this breaks your build, with relevant extracts from the build output.
My collegue forgot to declare version in dependencyManagement in parent pom so that was it. Thank you for your suggestions!