Scenario
In a spring-boot application that uses spring-boot-dependencies instead of spring-boot-starter-parent and a third party library that depends on elasticsearch version that is not comparable with version 6.x, elasticsearch dependency version get mixed up creating class loading issue.
Steps to reproduce
Create a spring-boot project and include spring-boot-dependencies in the dependency management section of the maven pom.xml
<properties> <spring.boot.version>2.1.6.RELEASE</spring.boot.version> <spring.cloud.version>Greenwich.RELEASE</spring.cloud.version> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>${spring.boot.version}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring.cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
Later, in the dependencies section include a third party library that depends on elastic search version 5.6.8
<dependnecies> <dependency> <groupId>com.netflix.conductor</groupId> <artifactId>conductor-es5-persistence</artifactId> <version>2.8.1</version> </dependency> </dependnecies>
Note that conductor-es5-persistence depends on elasticsearch version 5.6.8
The try to run mvn dependency:tree
on your project and observe the following:
[INFO] +- com.netflix.conductor:conductor-es5-persistence:jar:2.8.1:compile [INFO] | +- org.elasticsearch:elasticsearch:jar:6.4.3:compile [INFO] | | +- org.elasticsearch:elasticsearch-core:jar:6.4.3:compile
Where 6.4.3 is coming from?
Diagnostic
Turns out mvn dependency:tree
shows the issue, but it does not say where org.elasticsearch:elasticsearch:jar:6.4.3:compile
is comming from. The best command for the job is:
mvn -Dverbose=true help:effective-pom
This command outputs effective POM that can be redirected to a file mvn -Dverbose=true help:effective-pom > ~/pom.xml
and analysed. The effective pom will look something like this
... <dependency> <groupId>org.elasticsearch</groupId> <!-- org.springframework.boot:spring-boot-dependencies:2.1.6.RELEASE, line 1965 --> <artifactId>elasticsearch</artifactId> <!-- org.springframework.boot:spring-boot-dependencies:2.1.6.RELEASE, line 1966 --> <version>6.4.3</version> <!-- org.springframework.boot:spring-boot-dependencies:2.1.6.RELEASE, line 1967 --> </dependency> ...
Magic! now we can see exactly where the problem is:
<!-- org.springframework.boot:spring-boot-dependencies:2.1.6.RELEASE, line 1967 -->
Solution
Lets look at this import dependency:
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>${spring.boot.version}</version> <type>pom</type> <scope>import</scope> </dependency>
spring-boot-dependencies is imported, so there is no easy way to exclude elasticsearch dependency that it pulls into our project. A simple maven <exclude>
will not work here. The only way to solve the issue is to bring elasticsearch dependencies into your project dependency management block like this:
<properties> <spring.boot.version>2.1.6.RELEASE</spring.boot.version> <spring.cloud.version>Greenwich.RELEASE</spring.cloud.version> <elasticsearch.version>5.6.8</elasticsearch.version> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-dependencies</artifactId> <version>${spring.boot.version}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring.cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> <!-- Elasticsearch --> <dependency> <groupId>org.elasticsearch</groupId> <artifactId>elasticsearch</artifactId> <version>${elasticsearch.version}</version> </dependency> <dependency> <groupId>org.elasticsearch.client</groupId> <artifactId>transport</artifactId> <version>${elasticsearch.version}</version> </dependency> <dependency> <groupId>org.elasticsearch.distribution.integ-test-zip</groupId> <artifactId>elasticsearch</artifactId> <version>${elasticsearch.version}</version> <type>zip</type> </dependency> <dependency> <groupId>org.elasticsearch.plugin</groupId> <artifactId>transport-netty4-client</artifactId> <version>${elasticsearch.version}</version> </dependency> </dependencies> </dependencyManagement>
Now run mvn -Dverbose=true help:effective-pom
and confirm that the problem is fixed.