-1

I am new on ElasticSearch, and I would like to have a Spring Boot Application that connects to a database ElasticSearch 8.6, in order to do CRUD operations over an index. I was trying to do a CRUD application using Spring Boot with ElasticSearch database.

Entity:

@Document(createIndex = true, indexName = "client")
public class ClientEntity {

  public ClientEntity() {
    super();
  }

  @Id
  private String id;

  @Field(type = FieldType.Text, name = "name")
  private String name;

  @Field(type = FieldType.Long, name = "phoneNumber")
  private Long phone;

The repository interface from spring data is:

    import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
    import org.springframework.stereotype.Repository;

    @Repository
    public interface ClientRepository extends ElasticsearchRepository<ClientEntity, String> {
    
    }

Elastic search config:

    import org.apache.http.HttpHost;
    import org.apache.http.auth.AuthScope;
    import org.apache.http.auth.UsernamePasswordCredentials;
    import org.apache.http.client.CredentialsProvider;
    import org.apache.http.impl.client.BasicCredentialsProvider;
    import org.apache.http.impl.nio.client.HttpAsyncClientBuilder;
    import org.elasticsearch.client.RestClient;
    import org.elasticsearch.client.RestClientBuilder.HttpClientConfigCallback;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.data.elasticsearch.client.ClientConfiguration;
    import org.springframework.data.elasticsearch.client.elc.ElasticsearchConfiguration;
    import     org.springframework.data.elasticsearch.repository.config.EnableElasticsearchRepositories;
    
    import co.elastic.clients.elasticsearch.ElasticsearchClient;
    import co.elastic.clients.json.jackson.JacksonJsonpMapper;
    import co.elastic.clients.transport.ElasticsearchTransport;
    import co.elastic.clients.transport.rest_client.RestClientTransport;
    
    @Configuration
    public class ConfigElasticSearch extends ElasticsearchConfiguration {
      @Bean
      public ElasticsearchTransport getElasticsearchTransport() {
        return new RestClientTransport(getRestClient(), new JacksonJsonpMapper());
      }

      @Bean
      public ElasticsearchClient getElasticsearchClient() {
        ElasticsearchClient client = new ElasticsearchClient(getElasticsearchTransport());
        return client;
      }

      @Override
      public ClientConfiguration clientConfiguration() {
        return ClientConfiguration.builder().connectedTo("localhost:9200")
         .withBasicAuth("user", "my-password").build();
      }

pom.xml:

    <parent>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-parent</artifactId>
      <version>2.7.12</version>
    </parent>

    <properties>
      <java.version>17</java.version>
      <spring-cloud.version>2021.0.5</spring-cloud.version>
      <json-web-token.version>0.9.1</json-web-token.version>   
      <org-modelmapper.version>3.1.1</org-modelmapper.version>
    </properties>
    <dependencies>
          <dependency>
            <groupId>org.modelmapper</groupId>
            <artifactId>modelmapper</artifactId>
            <version>${org-modelmapper.version}</version>
          </dependency>
          <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
           </dependency>
    
    <!-- ES -->
           <dependency>
              <groupId>org.springframework.boot</groupId>
              <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
          </dependency>
         <dependency>
            <groupId>jakarta.json</groupId>
            <artifactId>jakarta.json-api</artifactId>
         </dependency>
        <dependency>
           <groupId>com.fasterxml.jackson.core</groupId>
           <artifactId>jackson-databind</artifactId>
        </dependency>    

The service that uses the Spring Data repository is the following:


    @Service("clientPersistence")
    public class ClientPersistenceElasticSearchDb {

      @Autowired
      private ClientRepository clientRepository;

      public Stream\<ClientEntity\> findAll() {
       return StreamSupport.stream(this.clientRepository.findAll().spliterator(), false);
      }

      public Optional\<ClientEntity\> findById(String id) {
        return clientRepository.findById(id);
      }
    }

The main configuration for my microservice is:


    @SpringBootApplication
    public class ClientMicroserviceApplication {

      public static void main(String[] args) {
        SpringApplication.run(EmpleadosMicroservicioApplication.class, args);
      }

    }

If I start my microservice, I get the following when starting (and then, the microservice hangs):

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'clientPersistencia': Unsatisfied dependency expressed through field 'clientRepository'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'clientRepository' defined in es.clientmicroservice.dao.clientRepository defined in @EnableElasticsearchRepositories declared on ConfigElasticSearch : Cannot resolve reference to bean 'elasticsearchTemplate' while setting bean property 'elasticsearchOperations'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'elasticsearchOperations' defined in class path resource [es/clientmicroservice/config/ConfigElasticSearch .class]: Unsatisfied dependency expressed through method 'elasticsearchOperations' parameter 1; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'elasticsearchClient' defined in class path resource [es/clientmicroservice/config/ConfigElasticSearch .class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [co.elastic.clients.elasticsearch.ElasticsearchClient]: Factory method 'elasticsearchClient' threw exception; nested exception is java.lang.NoClassDefFoundError: jakarta/json/spi/JsonProvider

I don't know why my class clientPersistence is not build because missing JsonProvider dependency.

Any one could help me?

Thank you in advance!!

Gastón Schabas
  • 2,153
  • 1
  • 10
  • 17

2 Answers2

0

Looking at the Spring Boot version, you are using Spring Data Elasticsearch 4.4.x (which now is out of maintenance). You are using the configuration for the new Elasticsearch Client (org.springframework.data.elasticsearch.client.elc.ElasticsearchConfiguration). The use of the then new client was introduced in 4.4 as a still new and potentially unstable feature.

I am not seeing that you set the jakarta-json.version (see the documentation about configuration of the new client.

Do you special reasons why you override and provide getElasticsearchTransport() and getElasticsearchClient()? These beans are alrea provided by the base class, the only method you need to provide is the one providing the configuration.

Remember that when using that version and connecting to Elasticsearch 8 you need to set the compatibility headers on each request, see the documentation about that.

I'd recommend you use an up to date version of Spring Data Elasticsearch.

P.J.Meisch
  • 18,013
  • 6
  • 50
  • 66
0

You are using spring-boot-starter-parent:2.7.12, which means you are using spring-boot-starter-data-elasticsearch:2.7.12. If you look at the dependencies, the last one has a dependency on spring-data-elasticsearch:4.4.12. The migration guide for 4.4.x says that you need to manually add some dependencies. I'm not seeing any of those dependencies in the pom.xml you showed in the question.

Gastón Schabas
  • 2,153
  • 1
  • 10
  • 17