How to debug artifact replacement in Maven

I have a parent project containing a dozen child projects, one of the child projects uses org.apache.httpcomponents:httpclient:jar:4.3.5 , which depends on org.apache.httpcomponents:httpcore:jar:4.3.2 .

However, the version of the httpcore result httpcore allowed instead of 4.2.2 instead of 4.2.2.

The following is the extraction of output when starting the dependency:tree with the debug option noted in Eclipse:

 ... [DEBUG] Using mirror nexus (http://192.168.0.111:8081/nexus/content/groups/public) for apache.snapshots (http://repository.apache.org/snapshots). [DEBUG] testArtifact: artifact=org.apache.httpcomponents:httpclient:jar:4.3.5:compile [DEBUG] includeArtifact: artifact=org.apache.httpcomponents:httpclient:jar:4.3.5:compile [DEBUG] startProcessChildren: artifact=org.apache.httpcomponents:httpclient:jar:4.3.5:compile [DEBUG] manageArtifactVersion: artifact=org.apache.httpcomponents:httpcore:jar:4.3.2:compile, replacement=org.apache.httpcomponents:httpcore:jar:4.2.1 [DEBUG] Using mirror nexus (http://192.168.0.111:8081/nexus/content/groups/public) for apache.snapshots (http://repository.apache.org/snapshots). ... 

It just shows replacement=org.apache.httpcomponents:httpcore:jar:4.2.1 , but it says nothing about the reason for the replacement. The parent project pom.xml uses quite a few dependencies, and although I could try to remove these dependencies one by one and check the result, it will take a lot of time. Is there a more efficient way to debug artifact replacement?


Here is an almost complete log of the dependency:tree parameter from Eclipse with the debug option.

+1
maven transitive-dependency
source share
1 answer

From your log you can find the lines:

 [DEBUG] com.company.xyz:xyz-integration-lib:jar:0.0.1-SNAPSHOT [DEBUG] com.company.xyz:xyz-utils:jar:0.0.1-SNAPSHOT:compile [DEBUG] commons-codec:commons-codec:jar:1.8:compile [DEBUG] javax.mail:mail:jar:1.4:provided [DEBUG] javax.activation:activation:jar:1.1.1:provided (version managed from 1.1 by org.jboss.spec:jboss-javaee-6.0:3.0.2.Final) [DEBUG] org.apache.commons:commons-lang3:jar:3.3.2:compile [DEBUG] junit:junit:jar:4.8.2:test [DEBUG] com.thoughtworks.xstream:xstream:jar:1.4.7:compile [DEBUG] xmlpull:xmlpull:jar:1.1.3.1:compile [DEBUG] xpp3:xpp3_min:jar:1.1.4c:compile [DEBUG] joda-time:joda-time:jar:2.4:compile [DEBUG] org.assertj:assertj-joda-time:jar:1.1.0:test [DEBUG] org.assertj:assertj-core:jar:1.3.0:test [DEBUG] org.apache.httpcomponents:httpclient:jar:4.3.5:compile [DEBUG] org.apache.httpcomponents:httpcore:jar:4.2.1:compile (version managed from 4.3.2 by org.jboss.as:jboss-as-parent:7.2.0.Final) [DEBUG] commons-logging:commons-logging:jar:1.1.3:compile [DEBUG] org.slf4j:slf4j-api:jar:1.7.7:compile [DEBUG] org.slf4j:slf4j-log4j12:jar:1.7.7:compile [DEBUG] log4j:log4j:jar:1.2.17:compile [DEBUG] org.mockito:mockito-all:jar:1.9.5:test [DEBUG] org.powermock:powermock-module-junit4:jar:1.5.5:test [DEBUG] org.powermock:powermock-module-junit4-common:jar:1.5.5:test [DEBUG] org.powermock:powermock-core:jar:1.5.5:test [DEBUG] org.javassist:javassist:jar:3.18.1-GA:test (version managed from 3.18.2-GA by org.springframework.boot:spring-boot-dependencies:1.1.4.RELEASE) [DEBUG] org.powermock:powermock-reflect:jar:1.5.5:test [DEBUG] org.objenesis:objenesis:jar:2.1:test [DEBUG] org.powermock:powermock-api-mockito:jar:1.5.5:test [DEBUG] org.powermock:powermock-api-support:jar:1.5.5:test 

Where you can see that the javassist and httpcore dropped by certain transitive dependencies, and the javax.activation version is one.

This happens when more than one of the dependencies of your project depends on the same library and certain dependencies on different versions of this library. This can be annoying since you usually cannot change how the parent POM or its dependencies affect the versions of your transitive dependencies.

The mediation rules from Maven docs are as follows:

Dependency matching - this determines which version of the dependency will be used when multiple versions of the artifact are encountered. Currently, Maven 2.0 only supports “nearest definition”, which means that it will use the version of the closest dependency on your project in the dependency tree. You can always guarantee by declaring it explicitly in your POM project. Note that if two versions of the dependencies are at the same depth in the dependency tree until Maven 2.0.8 decides which one to win, but since Maven 2.0.9 this is the order in the declaration that counts: the first ad wins .

“nearest definition” means that the version used will be closest to your project in the dependency tree, for example. if the 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 in constructing A, because the path from A to D via E is shorter. You can explicitly add a dependency on D 2.0 to A to force D 2.0

However, you can manage the dependency versions yourself. This is called dependency management and as indicated in the same docs:

Dependency Management - this allows project authors to directly specify the version of artifacts that will be used when they appear in transitive dependencies or in dependencies where no version has been specified. In the example in the previous section, a dependency was directly added to A, even if it is not used directly by A. Instead, A can include D as a dependency depending on the control section and directly control which version of D is used when, or, it is always mentioned.

So you can simply add:

 <dependencyManagement> <dependencies> <dependency> <groupId>bar</groupId> <artifactId>foo</artifactId> <version>1.2.3</version> </dependency> </dependencies> </dependencyManagement> 

into your own POM, and this will always override any version specific to your transitive dependencies through dependency mediation.

+4
source share

All Articles