Issue
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?
Solution
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.
Answered By - ctrueden
Answer Checked By - Clifford M. (JavaFixing Volunteer)