java.lang.NoSuchMethodError: org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequestBuilder.setSource - elasticsearch

I am trying to run the spring boot parent project which uses child project, which in turn uses project(ES project) which has elasticsearch dependencies and elasticsearch config bean for transport client.
The child project uses Spring Data ES repositories, which are enabled by a respective annotation in a project.
These are config annotations used in the child:
#Configuration
#ComponentScan("package")
#EntityScan("package3")
#EnableJpaRepositories("package2")
// enables only es repos for current project, ESProject has this annotation for its packages respectively
#EnableElasticsearchRepositories("package1")
The parent project has the only #SPringBootApplication on all packages of ES project and child one.
Parent pom:
<dependencies>
<dependency>
<groupId>org.groupid</groupId>
<artifactId>ChildProject</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>transport</artifactId>
</dependency>
<!-- ... -->
</dependencies>
Child pom:
<dependencies>
<dependency>
<groupId>org.groupid</groupId>
<artifactId>ESProject </artifactId>
<version>1.1-SNAPSHOT</version>
<exclusions>
<exclusion>
<!-- exclusions -->
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>transport</artifactId>
</dependency>
</dependencies>
ESProject Pom:
<dependencies>
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>6.4.1</version>
</dependency>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>transport</artifactId>
<version>6.4.1</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-elasticsearch</artifactId>
<version>3.1.1.RELEASE</version>
</dependency>
</dependencies>
The parent project is a module of pom, which uses Spring Boot 2.0.5.RELEASE.
When I run a parent project I am getting this. Clearly there are some dependencies conflicts but I can't quite figure out them.
nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.data.elasticsearch.repository.support.NumberKeyedRepository]: Constructor threw exception;
nested exception is java.lang.NoSuchMethodError: org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequestBuilder.setSource(Ljava/lang/String;)Lorg/elasticsearch/action/admin/indices/mapping/put/PutMappingRequestBuilder;
Also, it's worth noting if I use ESProject in other projects I don't get this exception but I don't have Spring Data ES Repos in those projects.

You have a pretty mix-up of Spring Data Elasticsearch and Elasticsearch library versions in your setup. Let me try to visualize what we got:
Spring Boot 2.0.5
+- Elasticsearch 5.6.11
+- Data Kay.SR10
+- Spring Data Elasticsearch 3.0.10
+- Elasticsearch 5.5.0
Boot 2.0.5 pulls in ES 5.6.11 but at the same time via the Spring Data Kay releasetrain version 5.5.0 of ES and 3.0.10 of SDES (which is not nice but should work).
Spring Data Elasticsearch 3.1.1
+- Elasticsearch 6.2.2
you define SDES 3.1.1 which relies on ES 6.2.2
Elasticsearch 6.4.1
finally you define the ES version to be 6.4.1
As for the error you see: The code that your application uses expects the following function to be available in the ES client libraries (using fully qualified names for the types):
org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequestBuilder org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequestBuilder.setSource(java.lang.String)
This method existed in ES 5.5, but was already deprecated there (excerpt from the code):
/**
* The mapping source definition.
* #deprecated use {#link #setSource(String, XContentType)}
*/
#Deprecated
public PutMappingRequestBuilder setSource(String mappingSource) {
request.source(mappingSource);
return this;
}
in ES6 this method was removed and only the one with the additional XContentType parameter exists - which is used by SDES for this version.
So your application loads SDES 3.0 in combination with ES 6 libraries which cannot work.
So you should update your dependencies to a consistent version either using Boot 2.1 or 2.2 check the version matrix here

Related

No operations defined in spec! error on swagger UI

I am working on to migrate the version of spring boot. I am using spring boot with jersey. After upgrade the version of spring boot and other dependencies, swagger is not working for me. I did not modified any configuration.
Dependencies in pom:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.10</version>
</parent>
<dependencyManagement>
<dependencies>
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId>
<version>Finchley.SR1</version> <type>pom</type> <scope>import</scope> </dependency> -->
<!-- Jersey -->
<dependency>
<groupId>org.glassfish.jersey</groupId>
<artifactId>jersey-bom</artifactId>
<version>${jersey.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jersey</artifactId>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-jersey2-jaxrs</artifactId>
<version>1.6.6</version>
</dependency>
Swagger configuration:
private void configureSwagger() {
register(SwaggerSerializers.class);
register(ApiListingResource.class);
BeanConfig beanConfig = new BeanConfig();
beanConfig.setTitle("API documentation");
beanConfig.setVersion(api.name());
beanConfig.setSchemes(new String[] {
"https", "http"
});
beanConfig.setBasePath("/api" + api.getPath());
// ConfigId and ScannerId must also be set as init parameters
// during servlet configuration
beanConfig.setConfigId(api.name());
beanConfig.setScannerId(api.name());
beanConfig.setUsePathBasedConfig(true);
beanConfig.setResourcePackage("com.api.v1.priv.resources");
beanConfig.setPrettyPrint(true);
beanConfig.setScan(true);
}
Changes in migration:
Spring boot version upgraded from 2.0.5.RELEASE => 2.6.10
swagger-jersey2-jaxrs upgraded from 1.5.18 => 1.6.6
Note - Swagger configuration was already existing. No changes has been done.
I am able to run the project successfully after migration. All api end points are working fine. But unfortunately swagger stopped working.
Swagger error:
I have gone through the lot of tutorials/blogs but not able to find the solution. Thanks everyone in advance.
In my case, it was due to conflict of org.reflections library. switched from 0.10 back to 0.9.12 fixed the issue.
Recommendation for migration:
Actually the problem was in technique of migration. We should not jump to latest version directly. We should continue version by version by considering the release notes. If you want to switch from spring 2.0.0 to 2.7.0, don't directly jump into it. Just move first 2.1.0..2.2.0.. etc. Clean and Build the project on each and every step of the migration.
Thanks!!!

Determine compatible Versions of Spring Modules and other libraries

Which is the best way to determine the versions for my Spring modules and other libraries in a Spring Boot project?
Versions for Spring Modules
Versions for Third Party libraries
There are a lot of question when you search for "Compatible versions in Spring".
But all these questions are regarding specific libraries.
I would like to have general rules of how to determine compatible versions for my project.
You may checkout my post on this A comprehensive list of dependencies managed by latest Spring-Boot 2.3.2.RELEASE (as a custom parent)
That's is just a reference for how it should be, but you may discard the version in as they will be managed indirectly by spring itself.
Ok so, this is something almost every spring developer stumble upon. Let me try to explain this how was I able to resolve all the managed and third party libraries.
Let's suppose you want to build spring-boot microservices with a centralized configuration server.
So we can take it as following modules:
A company project starter: acts as a parent, managing the dependency
A config-server
A config-client
and let's suppose you chose spring-boot 2.3.2 version, which I used and find more stable. You would expect all the managed ones are using this spring-boot 2.3.2 version directly or indirectly.
I would highly recommend using https://mvnrepository.com
artifact: my_company-boot-starter-parent
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.2.RELEASE</version>
</parent>
<groupId>com.my_company</groupId>
<artifactId>my_company-boot-starter-parent</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<name>my_company starter-parent</name>
<dependencyManagement>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- ... -->
<!-- ... -->
<!-- other dependencies -->
<!-- ... -->
<!-- ... -->
</dependencyManagement>
If you got to Spring Boot Starter Parent ยป 2.3.2.RELEASE, under Managed Dependencies you can see the comprehensive list of all the dependencies with default version that would be referenced implicitly with boot version 2.3.2, see column Version.
The Updates column indicate that these managed dependencies are having their newest updates as this, but you are not required to override the dependency version of managed ones. If you intent to use more recent version, you have to chose more recent version of spring-boot-starter-parent. So let the spring download all the managed one itself.
With spring-boot-starter-parent 2.3.2 , they do not mention which spring-cloud-dependencies verion you should use, and this is where we get stuck and we need to figure it out.
Let us got to spring-cloud-dependencies . Hee you can see numerous version but which one to chose, it's like verifying which latest version uses spring-boot 2.3.2 indirectly.
You need to follow the managed dependency and go along with it until you find your parent version.
For example If you go for :
Hoxton.SR6
Spring Cloud Dependencies(Hoxton.SR6) -> Spring Cloud Config Dependencies( 2.2.3.RELEASE) -> Spring Cloud Starter Config(2.2.3.RELEASE) -> Spring Cloud Starter(2.2.3.RELEASE) -> Spring Boot Starter(2.3.0.RELEASE)
Here you can see, we end up using Spring Boot Starter(2.3.0.RELEASE) which is not what we expected it to be.
Hoxton.SR7
Spring Cloud Dependencies(Hoxton.SR7) -> Spring Cloud Config Dependencies(2.2.4.RELEASE) -> Spring Cloud Starter Config(2.2.4.RELEASE) -> Spring Cloud Starter(2.2.4.RELEASE) -> Spring Boot Starter(2.3.2.RELEASE)
Here we end up using same boot version 2.3.2. So in your parent pom.xml, you can set the spring cloud version as :
<properties>
<java.version>15</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<lombok.version>1.18.20</lombok.version>
<spring-cloud.version>Hoxton.SR7</spring-cloud.version>
</properties>
And in child poms (jars), you can just use the dependencies justby mentioning the group and artifact, skipping the version.
sample:
<parent>
<groupId>com.my_company</groupId>
<artifactId>my_company-boot-starter-parent</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>com.google.googlejavaformat</groupId>
<artifactId>google-java-format</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</dependency>
</dependencies>
See, we have not provided the any version here, so spring-cloud-config-server version would be auto managed and it would be 2.2.4.RELEASE which again uses spring-boot-starter-web and spring-boot-starter both of 2.3.2 version.
Third party libraries
This is somewhat based on language version. You might want to use the latest third-party libs which is most recent till your language version supports it.
Like lombok: 1.18.20
Hope this might have helped you and others and provides an approach towards version compatibility.
Tips: Never forget to check the Managed Dependency Coordinates in Aappendix of all the spring boot release page as they keep their managed dependencies & version there. Like this one Appendix F: Dependency versions
1. Use Spring Initializr
Select all Spring modules you need in spring initializr and generate your code: https://start.spring.io/
You do not need to use the full generated code. But you should copy the library versions out of the generated pom.xml.
2. Watch out for dependency pom.xml
If available, import dependency pom.xml in your dependencyManagement.
Use the versions provided by these dependency poms.
E.g.
<dependencyManagement>
<dependencies>
<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>
Spring Dependency Version Documentation
You can also check the Spring Dependency Version Documentation. But I prefer the initilizr, because it's easier to handle.

Spring Data MongoDB 1.10.13 and Mongo 3.4

I'm trying to upgrade from Mongo 3.2 to Mongo 3.4. I updated my POM to use the latest Spring Data MongoDB (1.10.13) and while doing so, I noticed Spring Data MongoDB is still being compiled/depended on the old MongoDB Java driver (2.14.3). Since my project is dependent on the Spring Data MongoDB and MongoDB 3.4 driver, I ended up having 2 MongoDB drivers in my libs, which seems to have caused problems.
I ended up adding an exclusion in my POM. Is this the right way to go? How should I override the old MongoDB driver which originates from Spring Data MongoDB 1.10?
This is what my POM looks like:
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongo-java-driver</artifactId>
<version>3.4.3</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb</artifactId>
<version>1.10.13.RELEASE</version>
<exclusions>
<exclusion>
<groupId>org.mongodb</groupId>
<artifactId>mongo-java-driver</artifactId>
</exclusion>
</exclusions>
</dependency>

Overriding managed versions in maven

I have this dependency in my pom.xml
<!-- Spring Security -->
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity4</artifactId>
<version>3.0.2.RELEASE</version>
</dependency>
and this warning in the file: Overriding managed version 2.1.3.RELEASE for thymeleaf-extras-springsecurity4
I wonder is it is better to remove the version number
Generally you shouldn't override the parent versions of spring dependencies.
https://spring.io/blog/2016/04/13/overriding-dependency-versions-with-spring-boot

spring.io hibernate config

I'm using the Spring IO 1.0.1 BOM to manage my dependencies for my project. I've imported it in my super-pom's dependency management section like this -
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.spring.platform</groupId>
<artifactId>platform-bom</artifactId>
<version>1.0.1.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
...
Now, in a submodule POM of my project, I've declared these dependencies
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate.javax.persistence</groupId>
<artifactId>hibernate-jpa-2.0-api</artifactId>
</dependency>
And my final packaged war includes both hibernate-jpa-2.0 and hibernate-jpa-2.1. Since the entity manager depends on 2.1 and the api is 2.0. These are causing conflicts within my deployed app.
I cannot find a declaration of 2.1 in the platform bom so I'm confused about how to proceed. The documentation lists both of these as libraries provided by the platform, but the BOM doesn't provide any resolution between their conflicting versions. What is the recommended approach? Should I manually exclude 2.0 and explicitly declare 2.1 even if its not in the parent BOM? Should I force hibernate-entitymanager to use the 2.0 APIs?
I was hoping that the IO platform BOM would help me with these kinds of collisions.

Resources