Course – Black Friday 2025 – NPI EA (cat= Baeldung)
announcement - icon

Yes, we're now running our Black Friday Sale. All Access and Pro are 33% off until 2nd December, 2025:

>> EXPLORE ACCESS NOW

Partner – Orkes – NPI EA (cat=Spring)
announcement - icon

Modern software architecture is often broken. Slow delivery leads to missed opportunities, innovation is stalled due to architectural complexities, and engineering resources are exceedingly expensive.

Orkes is the leading workflow orchestration platform built to enable teams to transform the way they develop, connect, and deploy applications, microservices, AI agents, and more.

With Orkes Conductor managed through Orkes Cloud, developers can focus on building mission critical applications without worrying about infrastructure maintenance to meet goals and, simply put, taking new products live faster and reducing total cost of ownership.

Try a 14-Day Free Trial of Orkes Conductor today.

Partner – Orkes – NPI EA (tag=Microservices)
announcement - icon

Modern software architecture is often broken. Slow delivery leads to missed opportunities, innovation is stalled due to architectural complexities, and engineering resources are exceedingly expensive.

Orkes is the leading workflow orchestration platform built to enable teams to transform the way they develop, connect, and deploy applications, microservices, AI agents, and more.

With Orkes Conductor managed through Orkes Cloud, developers can focus on building mission critical applications without worrying about infrastructure maintenance to meet goals and, simply put, taking new products live faster and reducing total cost of ownership.

Try a 14-Day Free Trial of Orkes Conductor today.

eBook – Guide Spring Cloud – NPI EA (cat=Spring Cloud)
announcement - icon

Let's get started with a Microservice Architecture with Spring Cloud:

>> Join Pro and download the eBook

eBook – Mockito – NPI EA (tag = Mockito)
announcement - icon

Mocking is an essential part of unit testing, and the Mockito library makes it easy to write clean and intuitive unit tests for your Java code.

Get started with mocking and improve your application tests using our Mockito guide:

Download the eBook

eBook – Reactive – NPI EA (cat=Reactive)
announcement - icon

Spring 5 added support for reactive programming with the Spring WebFlux module, which has been improved upon ever since. Get started with the Reactor project basics and reactive programming in Spring Boot:

>> Join Pro and download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Jackson – NPI EA (cat=Jackson)
announcement - icon

Do JSON right with Jackson

Download the E-book

eBook – HTTP Client – NPI EA (cat=Http Client-Side)
announcement - icon

Get the most out of the Apache HTTP Client

Download the E-book

eBook – Maven – NPI EA (cat = Maven)
announcement - icon

Get Started with Apache Maven:

Download the E-book

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

eBook – RwS – NPI EA (cat=Spring MVC)
announcement - icon

Building a REST API with Spring?

Download the E-book

Course – LS – NPI EA (cat=Jackson)
announcement - icon

Get started with Spring and Spring Boot, through the Learn Spring course:

>> LEARN SPRING
Course – RWSB – NPI EA (cat=REST)
announcement - icon

Explore Spring Boot 3 and Spring 6 in-depth through building a full REST API with the framework:

>> The New “REST With Spring Boot”

Course – LSS – NPI EA (cat=Spring Security)
announcement - icon

Yes, Spring Security can be complex, from the more advanced functionality within the Core to the deep OAuth support in the framework.

I built the security material as two full courses - Core and OAuth, to get practical with these more complex scenarios. We explore when and how to use each feature and code through it on the backing project.

You can explore the course here:

>> Learn Spring Security

Partner – Orkes – NPI EA (cat=Java)
announcement - icon

Modern software architecture is often broken. Slow delivery leads to missed opportunities, innovation is stalled due to architectural complexities, and engineering resources are exceedingly expensive.

Orkes is the leading workflow orchestration platform built to enable teams to transform the way they develop, connect, and deploy applications, microservices, AI agents, and more.

With Orkes Conductor managed through Orkes Cloud, developers can focus on building mission critical applications without worrying about infrastructure maintenance to meet goals and, simply put, taking new products live faster and reducing total cost of ownership.

Try a 14-Day Free Trial of Orkes Conductor today.

Course – LSD – NPI EA (tag=Spring Data JPA)
announcement - icon

Spring Data JPA is a great way to handle the complexity of JPA with the powerful simplicity of Spring Boot.

Get started with Spring Data JPA through the guided reference course:

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (cat=Spring Boot)
announcement - icon

Refactor Java code safely — and automatically — with OpenRewrite.

Refactoring big codebases by hand is slow, risky, and easy to put off. That’s where OpenRewrite comes in. The open-source framework for large-scale, automated code transformations helps teams modernize safely and consistently.

Each month, the creators and maintainers of OpenRewrite at Moderne run live, hands-on training sessions — one for newcomers and one for experienced users. You’ll see how recipes work, how to apply them across projects, and how to modernize code with confidence.

Join the next session, bring your questions, and learn how to automate the kind of work that usually eats your sprint time.

Course – Black Friday 2025 – NPI (cat=Baeldung)
announcement - icon

Yes, we're now running our Black Friday Sale. All Access and Pro are 33% off until 2nd December, 2025:

>> EXPLORE ACCESS NOW

1. Overview

Multi-module Maven projects can have complex dependency graphs. These can have unusual results, the more the modules import from each other.

In this tutorial, we’ll see how to resolve version collision of artifacts in Maven.

We’ll start with a multi-module project where we’ve deliberately used different versions of the same artifact. Then, we’ll see how to prevent getting the wrong version of an artifact with either exclusion or dependency management.

Finally, we’ll try using the maven-enforcer-plugin to make things easier to control, by banning the use of transitive dependencies.

2. Version Collision of Artifacts

Each dependency that we include in our project might link to other artifacts. Maven can automatically bring in these artifacts, also called transitive dependencies. Version collision happens when multiple dependencies link to the same artifact, but use different versions.

As a result, there may be errors in our applications both in the compilation phase and also at runtime.

2.1. Project Structure

Let’s define a multi-module project structure to experiment with. Our project consists of a version-collision parent and three children modules:

version-collision
    project-a
    project-b
    project-collision

The pom.xml for project-a and project-b are almost identical. The only difference is the version of the com.google.guava artifact that they depend on. In particular, project-a uses version 22.0:

<dependencies>
    <dependency>
        <groupId>com.google.guava</groupId>
        <artifactId>guava</artifactId>
        <version>22.0</version>
    </dependency>
</dependencies>

But, project-b uses the newer version, 29.0-jre:

<dependencies>
    <dependency>
        <groupId>com.google.guava</groupId>
        <artifactId>guava</artifactId>
        <version>29.0-jre</version>
    </dependency>
</dependencies>

The third module, project-collision, depends on the other two:

<dependencies>
    <dependency>
        <groupId>com.baeldung</groupId>
        <artifactId>project-a</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </dependency>
    <dependency>
        <groupId>com.baeldung</groupId>
        <artifactId>project-b</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </dependency>
</dependencies>

So, which version of guava will be available to project-collision?

2.2. Using Features from Specific Dependency Version

We can find out which dependency is used by creating a simple test in the project-collision module that uses the Futures.immediateVoidFuture method from guava:

@Test
public void whenVersionCollisionDoesNotExist_thenShouldCompile() {
    assertThat(Futures.immediateVoidFuture(), notNullValue());
}

This method is only available from the 29.0-jre version. We’ve inherited this from one of the other modules, but we can only compile our code if we got the transitive dependency from project-b.

2.3. Compilation Error Caused by Version Collision

Depending on the order of dependencies in the project-collision module, in certain combinations Maven returns a compilation error:

[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:testCompile (default-testCompile) on project project-collision: Compilation failure
[ERROR] /tutorials/maven-all/version-collision/project-collision/src/test/java/com/baeldung/version/collision/VersionCollisionUnitTest.java:[12,27] cannot find symbol
[ERROR]   symbol:   method immediateVoidFuture()
[ERROR]   location: class com.google.common.util.concurrent.Futures

That’s the result of the version collision of the com.google.guava artifact. By default, for dependencies at the same level in a dependency tree, Maven chooses the first library it finds. In our case, both com.google.guava dependencies are at the same height and the older version is chosen.

2.4. Using maven-dependency-plugin

The maven-dependency-plugin is a very helpful tool to present all dependencies and their versions:

% mvn dependency:tree -Dverbose

[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ project-collision ---
[INFO] com.baeldung:project-collision:jar:0.0.1-SNAPSHOT
[INFO] +- com.baeldung:project-a:jar:0.0.1-SNAPSHOT:compile
[INFO] |  \- com.google.guava:guava:jar:22.0:compile
[INFO] \- com.baeldung:project-b:jar:0.0.1-SNAPSHOT:compile
[INFO]    \- (com.google.guava:guava:jar:29.0-jre:compile - omitted for conflict with 22.0)

The -Dverbose flag displays conflicting artifacts. In fact, we have a com.google.guava dependency in two versions: 22.0 and 29.0-jre. The latter is the one we would like to use in the project-collision module.

3. Excluding a Transitive Dependency From an Artifact

One way to resolve a version collision is by removing a conflicting transitive dependency from specific artifacts. In our example, we don’t want to have the com.google.guava library transitively added from the project-a artifact.

Therefore, we can exclude it in the project-collision pom:

<dependencies>
    <dependency>
        <groupId>com.baeldung</groupId>
        <artifactId>project-a</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <exclusions>
            <exclusion>
                <groupId>com.google.guava</groupId>
                <artifactId>guava</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>com.baeldung</groupId>
        <artifactId>project-b</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </dependency>
</dependencies>

Now, when we run the dependency:tree command, we can see that it’s not there anymore:

% mvn dependency:tree -Dverbose

[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ project-collision ---
[INFO] com.baeldung:project-collision:jar:0.0.1-SNAPSHOT
[INFO] \- com.baeldung:project-b:jar:0.0.1-SNAPSHOT:compile
[INFO]    \- com.google.guava:guava:jar:29.0-jre:compile

As a result, the compilation phase ends without an error and we can use the classes and methods from version 29.0-jre.

4. Using the dependencyManagement Section

Maven’s dependencyManagement section is a mechanism for centralizing dependency information. One of its most useful features is to control versions of artifacts used as transitive dependencies.

With that in mind, let’s create a dependencyManagement configuration in our parent pom:

<dependencyManagement>
   <dependencies>
      <dependency>
         <groupId>com.google.guava</groupId>
         <artifactId>guava</artifactId>
         <version>29.0-jre</version>
      </dependency>
   </dependencies>
</dependencyManagement>

As a result, Maven will make sure to use version 29.0-jre of com.google.guava artifact in all child modules:

% mvn dependency:tree -Dverbose

[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ project-collision ---
[INFO] com.baeldung:project-collision:jar:0.0.1-SNAPSHOT
[INFO] +- com.baeldung:project-a:jar:0.0.1-SNAPSHOT:compile
[INFO] |  \- com.google.guava:guava:jar:29.0-jre:compile (version managed from 22.0)
[INFO] \- com.baeldung:project-b:jar:0.0.1-SNAPSHOT:compile
[INFO]    \- (com.google.guava:guava:jar:29.0-jre:compile - version managed from 22.0; omitted for duplicate)

5. Prevent Accidental Transitive Dependencies

The maven-enforcer-plugin provides many built-in rules that simplify the management of a multi-module project. One of them bans the use of classes and methods from transitive dependencies.

Explicit dependency declaration removes the possibility of version collision of artifacts. Let’s add the maven-enforcer-plugin with that rule to our parent pom:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-enforcer-plugin</artifactId>
    <version>3.0.0-M3</version>
    <executions>
        <execution>
            <id>enforce-banned-dependencies</id>
            <goals>
                <goal>enforce</goal>
            </goals>
            <configuration>
                <rules>
                    <banTransitiveDependencies/>
                </rules>
            </configuration>
        </execution>
    </executions>
</plugin>

As a consequence, we must now explicitly declare the com.google.guava artifact in our project-collision module if we want to use it ourselves. We must either specify the version to use, or set up dependencyManagement in the parent pom.xml. This makes our project more mistake proof, but requires us to be more explicit in our pom.xml files.

6. Dependency Convergence

The Apache Maven Enforcer plugin supports dependencyConvergence as a built-in rule. When we enable this rule, the enforcer plugin ensures that dependency version numbers must converge. Let’s explore this rule in detail.

6.1. Understanding the Default Behavior

Let’s start by adding the dependencyConvergence rule to maven-enforcer-plugin within the project’s pom.xml:

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-enforcer-plugin</artifactId>
            <version>3.3.0</version>
            <executions>
                <execution>
                    <id>enforce</id>
                    <configuration>
                        <rules>
                            <dependencyConvergence/>
                        </rules>
                    </configuration>
                    <goals>
                        <goal>enforce</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

We must note that we have specified the rule using the <dependencyConvergence/> tag with no child tags. This triggers the default behavior of the dependencyConvergence rule while building the project.

Next, let’s comment out the dependencyManagement section in the pom.xml file and compile the project:

$ mvn compile
# build output is trimmed
...
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  1.055 s
[INFO] Finished at: 2023-04-11T18:39:41+05:30
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-enforcer-plugin:3.3.0:enforce (enforce) on project project-collision: 
[ERROR] Rule 0: org.apache.maven.enforcer.rules.dependency.DependencyConvergence failed with message:
[ERROR] Failed while enforcing releasability.
[ERROR] 
[ERROR] Dependency convergence error for com.google.guava:guava:jar:22.0 paths to dependency are:
[ERROR] +-com.baeldung:project-collision:jar:0.0.1-SNAPSHOT
[ERROR]   +-com.baeldung:version-collision-project-a:jar:0.0.1-SNAPSHOT:compile
[ERROR]     +-com.google.guava:guava:jar:22.0:compile
[ERROR] and
[ERROR] +-com.baeldung:project-collision:jar:0.0.1-SNAPSHOT
[ERROR]   +-com.baeldung:version-collision-project-b:jar:0.0.1-SNAPSHOT:compile
[ERROR]     +-com.google.guava:guava:jar:29.0-jre:compile
[ERROR] 
...

Unfortunately, since the dependency version number for the com.google.guava:guava artifact couldn’t converge, so the compilation step failed. That’s the expected default behavior of the dependencyConvergence rule, where the build fails for even a single dependency convergence error.

Furthermore, let’s remember that dependency version management through the dependencyManagement section is taken into account before execution of the dependencyConvergence rule. So, we need to comment it out in our project to study the dependencyConvergence rule independently.

6.2. Excluding Artifacts for Dependency Convergence

If we’re sure our project will run fine with any of the two dependency version numbers, we can exclude such an artifact from the dependencyConvergence rule.

Let’s go ahead and exclude the com.google.guava:guava artifact from the rule:

...
<dependencyConvergence>
    <excludes>
        <exclude>com.google.guava:guava</exclude>
    </excludes>
</dependencyConvergence>
...

Now, let’s try to compile the project:

$ mvn compile
# build output trimmed
...
[INFO] version-collision .................................. SUCCESS [  0.560 s]
[INFO] version-collision-project-a ........................ SUCCESS [  0.265 s]
[INFO] version-collision-project-b ........................ SUCCESS [  0.043 s]
[INFO] project-collision .................................. SUCCESS [  0.093 s]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
...

Great! It looks like we’ve got this case covered.

6.3. Including Artifacts for Dependency Convergence

By default, the dependencyConvergence rule will apply to all the artifacts. We can relax the rule enforcement to a specific list of artifacts by including them within the <includes></includes> section.

Let’s include the com.google.guava:guava artifact in the dependencyConvergence rule:

...
<dependencyConvergence>
    <includes>
        <include>com.google.guava:guava</include>
    </includes>
</dependencyConvergence>
...

Moving on, let’s compile the project and verify that the dependency convergence error causes the build to fail:

$ mvn compile
# build fails with the same error as earlier

7. Conclusion

In this article, we’ve seen how to resolve a version collision of artifacts in Maven.

First, we explored an example of a version collision in a multi-module project.

Then, we showed how to exclude transitive dependencies in the pom.xml. We looked at how to control dependencies versions with the dependencyManagement section in the parent pom.xml.

Finally, we tried the maven-enforcer-plugin to ban the use of transitive dependencies in order to force each module to take control of its own.

The code backing this article is available on GitHub. Once you're logged in as a Baeldung Pro Member, start learning and coding on the project.
Course – Black Friday 2025 – NPI EA (cat= Baeldung)
announcement - icon

Yes, we're now running our Black Friday Sale. All Access and Pro are 33% off until 2nd December, 2025:

>> EXPLORE ACCESS NOW

Partner – Orkes – NPI EA (cat = Spring)
announcement - icon

Modern software architecture is often broken. Slow delivery leads to missed opportunities, innovation is stalled due to architectural complexities, and engineering resources are exceedingly expensive.

Orkes is the leading workflow orchestration platform built to enable teams to transform the way they develop, connect, and deploy applications, microservices, AI agents, and more.

With Orkes Conductor managed through Orkes Cloud, developers can focus on building mission critical applications without worrying about infrastructure maintenance to meet goals and, simply put, taking new products live faster and reducing total cost of ownership.

Try a 14-Day Free Trial of Orkes Conductor today.

Partner – Orkes – NPI EA (tag = Microservices)
announcement - icon

Modern software architecture is often broken. Slow delivery leads to missed opportunities, innovation is stalled due to architectural complexities, and engineering resources are exceedingly expensive.

Orkes is the leading workflow orchestration platform built to enable teams to transform the way they develop, connect, and deploy applications, microservices, AI agents, and more.

With Orkes Conductor managed through Orkes Cloud, developers can focus on building mission critical applications without worrying about infrastructure maintenance to meet goals and, simply put, taking new products live faster and reducing total cost of ownership.

Try a 14-Day Free Trial of Orkes Conductor today.

eBook – HTTP Client – NPI EA (cat=HTTP Client-Side)
announcement - icon

The Apache HTTP Client is a very robust library, suitable for both simple and advanced use cases when testing HTTP endpoints. Check out our guide covering basic request and response handling, as well as security, cookies, timeouts, and more:

>> Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

Course – LS – NPI EA (cat=REST)

announcement - icon

Get started with Spring Boot and with core Spring, through the Learn Spring course:

>> CHECK OUT THE COURSE

Partner – Moderne – NPI EA (tag=Refactoring)
announcement - icon

Modern Java teams move fast — but codebases don’t always keep up. Frameworks change, dependencies drift, and tech debt builds until it starts to drag on delivery. OpenRewrite was built to fix that: an open-source refactoring engine that automates repetitive code changes while keeping developer intent intact.

The monthly training series, led by the creators and maintainers of OpenRewrite at Moderne, walks through real-world migrations and modernization patterns. Whether you’re new to recipes or ready to write your own, you’ll learn practical ways to refactor safely and at scale.

If you’ve ever wished refactoring felt as natural — and as fast — as writing code, this is a good place to start.

Course – Black Friday 2025 – NPI (All)
announcement - icon

Yes, we're now running our Black Friday Sale. All Access and Pro are 33% off until 2nd December, 2025:

>> EXPLORE ACCESS NOW

eBook Jackson – NPI EA – 3 (cat = Jackson)