How can I depend on a library with transitive dependencies which are adjusted by Maven dependency management, at the same versions as adjusted?

Viewed 225

Consider the following project POM for a Java library:

<?xml version="1.0" encoding="UTF-8"?>
<?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>

  <groupId>foo</groupId>
  <artifactId>lib</artifactId>
  <version>1</version>

  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>commons-codec</groupId>
        <artifactId>commons-codec</artifactId>
        <version>1.10</version>
      </dependency>
    </dependencies>
  </dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>org.apache.httpcomponents</groupId>
      <artifactId>httpclient</artifactId>
      <version>4.5.3</version>
    </dependency>
  </dependencies>
</project>

As desired, this project depends on commons-codec version 1.10:

$ mvn dependency:list | grep commons-codec
[INFO]    commons-codec:commons-codec:jar:1.10:compile

However, if this library is used as a dependency in a downstream project, the version of commons-codec inherited transitively will be 1.9, because org.apache.httpcomponents:httpclient:4.5.3 depends on 1.9, not 1.10.

Here is an application POM which illustrates the issue:

<?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>

  <groupId>foo</groupId>
  <artifactId>app</artifactId>
  <version>1</version>

  <dependencies>
    <dependency>
      <groupId>foo</groupId>
      <artifactId>lib</artifactId>
      <version>1</version>
    </dependency>
  </dependencies>
</project>

And the resolved dependencies:

mvn dependency:list | grep commons-codec
[INFO]    commons-codec:commons-codec:jar:1.9:compile

Is this a bug in Maven? Or intended behavior?

If intended, is there a way—without hardcoding transitive dependencies in either POM—to inherit the versions as they are resolved during the build of the library component?

1 Answers

One solution is to inherit the dependency management of the library, like so:

<?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>

  <groupId>foo</groupId>
  <artifactId>app</artifactId>
  <version>1</version>

  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>foo</groupId>
        <artifactId>lib</artifactId>
        <version>1</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>foo</groupId>
      <artifactId>lib</artifactId>
      <version>1</version>
    </dependency>
  </dependencies>
</project>

And then it works:

mvn dependency:list | grep commons-codec
[INFO]    commons-codec:commons-codec:jar:1.10:compile

But is this the best/only solution? It seems unfortunate/unintended if one must always do this with every dependency to ensure that transitive versions actually match.

I have also posted this code as a gist.

Related