How do I resolve a dependency conflict in Maven? - java

I have a fairly large legacy project that I'm adding a component to. This component uses HtmlUnit. I can compile it ok with Maven but when I run it I get:
java.lang.NoSuchMethodError:
org.apache.http.conn.ssl.SSLConnectionSocketFactory.<init>
(Ljavax/net/ssl/SSLContext;[Ljava/lang/String;[Ljava/lang/String;Ljavax/net/ssl/HostnameVerifier;)
So it's missing the correct constructor. I think this is almost certainly a version conflict in httpclient but I'm not sure how to resolve it. Here's the relevant part of my pom.xml (note all the games I've been trying to play with exclusions and dependency management):
<dependencies>
<dependency>
<groupId>com.mycompany.mine</groupId>
<artifactId>my-base-project</artifactId>
<version>${project.version}</version>
<exclusions>
<exclusion>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.mycompany</groupId>
<artifactId>base-project</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
<exclusions>
<exclusion>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.2</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.2</version>
</dependency>
</dependencies>
</dependencyManagement>
Any ideas?
Edit: it's been suggested that this question is a duplicate of this one, but it's not since the dependency type in this case is not war.

In order to identify conflicting dependecies, use mvn dependency:tree. I like to pipe it to a text file for ease of use:
mvn dependency:tree > tree.txt
Then, use your favorite text editor to look for multiple versions of a depedency.
Alternatively, if you are looking for a specific groupId or artifactId, use the -Dincludes flag:
mvn dependency:tree -Dincludes=<groupId>:<artifactId>:<version>:<packaging>
mvn dependency:tree -Dincludes=org.springframework <<< get all dependencies with by groupId
mvn dependency:tree -Dincludes=:spring-web <<< get all dependencies by artifactId
You might also want to add the -Dverbose flag here.
To resolve dependency conflicts, there are two ways:
1) Exclude the one you don't want
<depdency>
<groupId>some.stuff</groupId>
<artifactId>with.transitive.depdency</artifactId>
<exclusions>
<exclusion>
<groupId>something</groupId>
<artifactId>unwanted</artifactId>
<exclusion>
<exclusions>
<depdency>
With this way, you will have to exclude on every dependency that brings in a transitive one. For this reason I like the other one better.
2) Explicitly add the version you want
<dependency>
<groupId>something</groupId>
<artifactId>with.version.conflict</artifactId>
<version>what I want</version>
</dependency>
This will make sure that any transitive dependency will be swapped with this exact version. This might also lead to errors though, if some framework actually needs an older version. For using this strategy safely, your dependencies will need to be fairly close to the newest available version (or versions released at the same time).

Related

How to remediate vulnerable dependency used by another library which I used in my project?

I am using Apache Maven 3.6.3 & Spring boot 1.5 without micro service Architecture. I am working on a task to remediate vulnerable dependencies currently present in the dependency tree of our project. logback-classic is one of those dependencies. I can change the version of top-level dependencies (in top level pom) but I am not able to upgrade its version from 1.11.1 to 1.2.3 for logback-dependency present in spring-boot-starter-web starter used in one of child POM.
I am able to exclude such versions as-
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.2.0.RELEASE</version>
<exclusions>
<exclusion>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</exclusion>
</exclusions>
</dependency>
However, I am not able to update the version of same dependency present in dependency tree of spring-boot-starter-web starter of one of JAR in project. I tried to provide update of version using < dependencyManagement > tag as-
<project>
......
<dependencyManagement>
<dependencies>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.2.0.RELEASE</version>
<exclusions>
<exclusion>
<groupId>ch.quos.logback</groupId>
<artifactId>logback-classic</artifactId>
</exclusion>
</exclusions>
</dependency>
........
</dependencies>
......
<project>
Note- In < dependencyManagement >, initially I tried without < type > & < scope > tags as well but anyhow I am only able to exclude vulnerable logback-classic dependency but I can't update this to 1.2.3 inside spring-boot-starter-web present in that particular child pom.
The Library You Mentioned (Logback-classic) Has Many Compatability Problems Reported
As You Can See Here In The Related Issue On Its Repository
I Recommend That You Try Different Version Of Spring (Newer Ones) And Check The Result
Search Around In The Github Issues For Versions And Updates You Might Find Something

Maven: how to override dependency

My situation is a bit strange:
Dependency with artifact id: yyy in the pom (see below) has dependency:
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>2.5</version>
</dependency>
So the problem is I need to use the 3.1.0 version in the current module because it has extra functionality:
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>
I have tried the exclusions tag and dependencymanagement tag explained in the example on the page: Maven: how to override the dependency added by a library
It does not work. I have also read and tried the 3 examples in this article: https://spring.io/blog/2016/04/13/overriding-dependency-versions-with-spring-boot
It also did not work. So what I did was to re-order my pom dependencies so that the 3.1.0 goes before the one with artifact yyy and I was happy it worked I built successfully a clean install. My happiness was short lived because after a clean install the pom re-ordered itself and the 3.1.0 was automatically re-ordered back below the yyy. Which means the next build will use 2.5 again and fail.
My pom structure snippet is as below:
<dependencies>
<dependency>
<groupId>xxxx.xxx.xxxx</groupId>
<artifactId>yyy</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>
<dependencies>
My happiness was short lived because after a clean install the pom
re-ordered itself and the 3.1.0 was automatically re-ordered back
below the yyy. Which means the next build will use 2.5 again and fail.
Note that the javax.servlet:javax.servlet-api has to be included in a WAR but only in a standalone JAR that includes and bootstraps a servlet container.
If you build a standard WAR you have to use the dependency provided by the server. So the dependency should be declared with the provided scope.
I have tried the exclusions tag and dependencymanagement tag explained
in the example on the page: Maven: how to override the dependency
added by a library
dependencyManagement will be helpless here as the issue is related to a dependency you include outside the dependencyManagement element.
But using the exclusions option in the dependency declaration is the right way. It should exclude the 2.5 version of the javax.servlet-api artifact if used in this way :
<dependencies>
<dependency>
<groupId>xxxx.xxx.xxxx</groupId>
<artifactId>yyy</artifactId>
<version>1.0.0</version>
<exclusions>
<exclusion>
<artifactId>javax.servlet</artifactId>
<groupId>javax.servlet-api</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>
</dependencies>
If the problem persists it means that the dependency is probably pulled by another dependency.
Some hints that generally help to discover that :
check that you don't use WAR overlay feature. But not likely here as you retrieve only 1 version of the dependency
use mvn dependency:tree on the WAR project to inspect all pulled dependencies.
To ease the readable you can also filter in this way :
mvn dependency:tree -Dincludes=javax.javax.servlet-api
The solution below has ignored the version 2.5 and so it is working. However i don't know what it means. Does it remove other dependencies? Please interpret what the asterix in groupId and artifactId mean in simple english. I want to know the risks because i am using a multi module system where there to many nested dependencies in other dependencies. I will continue to research as of now but if anyone can explain please do. Thanks
<dependencies>
<dependency>
<groupId>xxxx.xxx.xxxx</groupId>
<artifactId>yyy</artifactId>
<version>1.0.0</version>
<exclusions>
<exclusion>
<groupId>javax.servlet</groupId> // this works or
<groupId>*</groupId> // this works
<artifactId>*</artifactId> // this part was a mandatory *
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>
</dependencies>

NoSuchMethodError: com.google.common.base.Preconditions.checkArgument(ZLjava/lang/String;J)V

What Google Maven dependency could fix this error:
java.lang.NoSuchMethodError: com.google.common.base.Preconditions.checkArgument(ZLjava/lang/String;J)V
at com.google.cloud.storage.spi.v1.HttpStorageRpc.read(HttpStorageRpc.java:487)
at com.google.cloud.storage.BlobReadChannel$1.call(BlobReadChannel.java:127)
at com.google.cloud.storage.BlobReadChannel$1.call(BlobReadChannel.java:124)
at com.google.api.gax.retrying.DirectRetryingExecutor.submit(DirectRetryingExecutor.java:94)
at com.google.cloud.RetryHelper.runWithRetries(RetryHelper.java:54)
at com.google.cloud.storage.BlobReadChannel.read(BlobReadChannel.java:124)
at sun.nio.ch.ChannelInputStream.read(ChannelInputStream.java:65)
at sun.nio.ch.ChannelInputStream.read(ChannelInputStream.java:109)
at sun.nio.ch.ChannelInputStream.read(ChannelInputStream.java:103)
at java.io.InputStream.read(InputStream.java:101)
Code:
Blob blob = storage.get(blobId);
if(blob.exists()) {
return true;
}
Your Google guava version is either too old (< 20.0) or mismatched (multiple jars versions). Make sure you don't have several versions in your dependency tree.
Use
mvn dependency:tree | less
to look for the guava versions.
Please add following dependencies to your project's POM:
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>23.6-jre</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
<version>4.4.8</version>
</dependency>
In my case, I happened to include both
<dependency>
<groupId>com.google.collections</groupId>
<artifactId>google-collections</artifactId>
<version>1.0</version>
</dependency>
and
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>28.0-jre</version>
</dependency>
As it turns out, I cannot use both of these libraries. Removing google-collections fixed the issue for me.
Try inserting a dependency containing a newer version of guava at the top of your dependencies in your pom.xml containing your project.
E.g.
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>24.1.1-jre</version>
</dependency>
For anybody encountering anything like this, i had the following pom:
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-client</artifactId>
<version>3.2.1</version>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20190722</version>
</dependency>
<dependency>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.2</version>
</dependency>
And commenting out the maven-shade plugin fixed it for me...
I had the same issue in my Java/Kotlin application. When the app was ran via IntelliJ there were no issues. However, when the .Jar was ran the error message above was thrown.
I could not find a direct action item to take with the Guava issue defined by #Laurent Perez above so I did the following which resolved the issue with my .Jar file running:
Removed .Jar IntelliJ configurations and file from IntelliJ. Then re-added the .Jar following Step 3 from this deploy guide.
Other actions to try if the above does not work:
Rebuild project.
Invalidate IntelliJ cache and restart.
Restart computer.
It happens when you're missing guava library from your dependency. Add it using following in your pom.xml
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>24.0-jre</version>
</dependency>
Another reason could be there are multiple versions of google guava/collection library, you can't have both as mentioned by #sabbir in his comment, you ought to remove one of them.
Lastly it could be that some other dependency is dependent on the previous version of google guava/collections. Go to Dependency Hierarchy and search for google and see what all dependencies are dependent on the previous versions. In my case it was by version-maven-plugin, version 2.7
Here version-maven-plugin, version 2.7 uses google collections 1.0, and I require guava 24.0 Both can't work simuntaneously.
I excluded it in my pom.xml like this and then added a new dependency of guava
<dependency>
<groupId>org.codehaus.mojo</groupId>
<artifactId>versions-maven-plugin</artifactId>
<version>2.7</version>
<exclusions>
<exclusion>
<groupId>com.google.collections</groupId>
<artifactId>google-collections</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>24.0-jre</version>
</dependency>
Resultant: Now google-collections is gone.

Maven cannot load dependency from another dependency in repository

I am new to Maven, I try to load tranquility using the following in pom.xml:
<dependency>
<groupId>io.druid</groupId>
<artifactId>tranquility-core_2.11</artifactId>
<version>0.7.0</version>
</dependency>
Then I get an error: Failure to find com.fasterxml.jackson-module-scala_2.11:jar:2.4.6.
I tried to search in search.maven.org, and find out that, inside the io.druid tranquility-core module, the dependency is:
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-scala_2.11</artifactId>
<version>2.4.6</version>
</dependency>
However, when I try to search Jackson-module-scala_2.11 in the central repository, there's no 2.4.6 version there, there's only 2.4.5 and 2.5.0. See the following link: http://search.maven.org/#search|gav|1|g%3A%22com.fasterxml.jackson.module%22%20AND%20a%3A%22jackson-module-scala_2.11%22
So is there a way for me to build it successfully even the module in central repository (in this case the tranquility module) makes mistake in referencing another module?
Thanks.
you can exclude the dependency in the io.druid tranquility, and dependency it by yourself with the exist version like this:
<dependency>
<groupId>io.druid</groupId>
<artifactId>tranquility-core_2.11</artifactId>
<version>0.7.0</version>
<exclusions>
<exclusion>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-scala_2.11</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-scala_2.11</artifactId>
<version>2.5.0</version>
</dependency>

How to exclude cyclic deprecated dependencies in maven without killing the dependencies completely?

I have a case that I have the following cyclic dependencies in maven:
JAR A version 1.1 depends on JAR B version 1.0
JAR B version 1.1 depends on JAR A version 1.0
For some reason that I don't know, Maven brings all the 4 JARs: A 1.0, A 1.1, B 1.0 and B 1.1, which results in a classpath conflict.
This really sucks. I already ask the developers of both JARs to fix this, however I can't simply sit and wait for the day that they decide to fix this.
I tried this:
<dependency>
<groupId>groupA</groupId>
<artifactId>artifactA</artifactId>
<version>1.1</version>
<type>pom</type>
<scope>compile</scope>
<exclusions>
<exclusion>
<groupId>groupB</groupId>
<artifactId>artifactB</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>groupB</groupId>
<artifactId>artifactB</artifactId>
<version>1.1</version>
<type>pom</type>
<scope>compile</scope>
<exclusions>
<exclusion>
<groupId>groupA</groupId>
<artifactId>artifactA</artifactId>
</exclusion>
</exclusions>
</dependency>
The result is that maven excludes all of the JARs as if none dependency were added, and the project does not compiles because there are missing classes.
So, other than just asking both JARs developers to solve this, what can I do? How can I import both the new dependencies while leaving out both the old ones?
Pragmatic solution would be to redeclare the unwanted dependencies as provided, for example:
<dependency>
<groupId>groupA</groupId>
<artifactId>artifactA</artifactId>
<version>1.0</version>
<scope>provided</scope>
</dependency>
I'm not particularly fond of using provided in such manner, since it leaves the dependency in the compile time and could lead to unwanted compile dependencies, but I see no other way in your case ;(.

Categories