Johnny
Johnny

Reputation: 7351

How do I resolve a dependency conflict in Maven?

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.

Upvotes: 1

Views: 2640

Answers (1)

Tobb
Tobb

Reputation: 12225

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).

Upvotes: 3

Related Questions