Detecting dependency conflicts with Maven

11,355

Solution 1

You can setup a dependencyConvergence enforcer rule in Maven. This rule requires that dependency version numbers converge.

If a project has two dependencies, A and B, both depending on the same artifact, C, this rule will fail the build if A depends on a different version of C than the version of C depended on by B.

The rule can be added like this.

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

More details can be found here.

Solution 2

To detect all the transitive dependencies you can use the maven-dependency-plugin:

mvn dependency:tree -Dverbose

It will show the direct and transitive dependencies of your project. The -Dverbose option shows the conflicts.

[INFO] [dependency:tree]
[INFO] org.apache.maven.plugins:maven-dependency-plugin:maven-plugin:2.0-alpha-5-SNAPSHOT
[INFO] +- org.apache.maven.reporting:maven-reporting-impl:jar:2.0.4:compile
[INFO] |  \- commons-validator:commons-validator:jar:1.2.0:compile
[INFO] |     \- commons-digester:commons-digester:jar:1.6:compile
[INFO] |        \- (commons-collections:commons-collections:jar:2.1:compile - omitted for conflict with 2.0)
[INFO] \- org.apache.maven.doxia:doxia-site-renderer:jar:1.0-alpha-8:compile
[INFO]    \- org.codehaus.plexus:plexus-velocity:jar:1.1.3:compile
[INFO]       \- commons-collections:commons-collections:jar:2.0:compile

For the selection of the same library with different versions:

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. For example, if 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. You could explicitly add a dependency to D 2.0 in A to force the use of D 2.0.

So, if one of your libraries does not work with the other versions of guava, that means that your dependencies are not compatible. That should be updated to work with the newer version.

Share:
11,355
Mike W
Author by

Mike W

Updated on June 09, 2022

Comments

  • Mike W
    Mike W about 2 years

    I have a maven-built Java application, which pulls in a number of libraries. The application is in one git repo (with its own maven build), and each library is in its own git repo (with its own maven build). Also, both the application and some of the libraries depend on guava.

    The application's pom.xml specifies guava version 19.0:

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

    The application also imports another library, called library1. library1 also depends on guava. But library1's pom.xml specifies a later version of guava:

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

    When the application was built, maven chose the guava version that was specified at the application level. But that caused library1 to fail, because it was expecting a later version of guava.

    If we had been using grade and tried to specify this combination of guava versions, I believe gradle would have caused the build to fail, which is probably the right thing to do.

    Given that we may have pom.xml files with such a version discrepancy, is there a way to have set up maven so that it would have noticed the discrepancy and either failed the build or displayed a really prominent warning about the problem?

  • Nic
    Nic almost 3 years
    [INFO] Verbose not supported since maven-dependency-plugin 3.0