Compare commits

..

No commits in common. "main" and "5.4.0" have entirely different histories.
main ... 5.4.0

673 changed files with 2587 additions and 5665 deletions

1
.gitignore vendored
View File

@ -33,4 +33,3 @@ node
package-lock.json package-lock.json
.mvn/.develocity .mvn/.develocity
/src/test/resources/testcontainers-local.properties

View File

@ -3,6 +3,6 @@
<extension> <extension>
<groupId>io.spring.develocity.conventions</groupId> <groupId>io.spring.develocity.conventions</groupId>
<artifactId>develocity-conventions-maven-extension</artifactId> <artifactId>develocity-conventions-maven-extension</artifactId>
<version>0.0.22</version> <version>0.0.19</version>
</extension> </extension>
</extensions> </extensions>

View File

@ -1,14 +0,0 @@
--add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED
--add-exports jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED
--add-exports jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED
--add-exports jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED
--add-exports jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED
--add-exports jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED
--add-exports jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED
--add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED
--add-opens jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED
--add-opens jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED
--add-opens=java.base/java.util=ALL-UNNAMED
--add-opens=java.base/java.lang.reflect=ALL-UNNAMED
--add-opens=java.base/java.text=ALL-UNNAMED
--add-opens=java.desktop/java.awt.font=ALL-UNNAMED

View File

@ -62,7 +62,7 @@ public class MyService {
=== Using the RestClient === Using the RestClient
Please check the https://docs.spring.io/spring-data/elasticsearch/docs/current/reference/html/#elasticsearch.clients.configuration[official documentation]. Please check the [official documentation](https://docs.spring.io/spring-data/elasticsearch/docs/current/reference/html/#elasticsearch.clients.configuration).
=== Maven configuration === Maven configuration
@ -168,7 +168,7 @@ Building the documentation builds also the project without running tests.
$ ./mvnw clean install -Pantora $ ./mvnw clean install -Pantora
---- ----
The generated documentation is available from `target/site/index.html`. The generated documentation is available from `target/antora/site/index.html`.
== Examples == Examples

View File

@ -1,20 +1,25 @@
# Java versions # Java versions
java.main.tag=24.0.1_9-jdk-noble java.main.tag=17.0.13_11-jdk-focal
java.next.tag=24.0.1_9-jdk-noble java.next.tag=23.0.1_11-jdk-noble
# Docker container images - standard # Docker container images - standard
docker.java.main.image=library/eclipse-temurin:${java.main.tag} docker.java.main.image=library/eclipse-temurin:${java.main.tag}
docker.java.next.image=library/eclipse-temurin:${java.next.tag} docker.java.next.image=library/eclipse-temurin:${java.next.tag}
# Supported versions of MongoDB # Supported versions of MongoDB
docker.mongodb.6.0.version=6.0.23 docker.mongodb.4.4.version=4.4.25
docker.mongodb.7.0.version=7.0.20 docker.mongodb.5.0.version=5.0.21
docker.mongodb.8.0.version=8.0.9 docker.mongodb.6.0.version=6.0.10
docker.mongodb.7.0.version=7.0.2
docker.mongodb.8.0.version=8.0.0
# Supported versions of Redis # Supported versions of Redis
docker.redis.6.version=6.2.13 docker.redis.6.version=6.2.13
docker.redis.7.version=7.2.4 docker.redis.7.version=7.2.4
# Supported versions of Cassandra
docker.cassandra.3.version=3.11.16
# Docker environment settings # Docker environment settings
docker.java.inside.basic=-v $HOME:/tmp/jenkins-home docker.java.inside.basic=-v $HOME:/tmp/jenkins-home
docker.java.inside.docker=-u root -v /var/run/docker.sock:/var/run/docker.sock -v /usr/bin/docker:/usr/bin/docker -v $HOME:/tmp/jenkins-home docker.java.inside.docker=-u root -v /var/run/docker.sock:/var/run/docker.sock -v /usr/bin/docker:/usr/bin/docker -v $HOME:/tmp/jenkins-home

45
pom.xml
View File

@ -5,12 +5,12 @@
<groupId>org.springframework.data</groupId> <groupId>org.springframework.data</groupId>
<artifactId>spring-data-elasticsearch</artifactId> <artifactId>spring-data-elasticsearch</artifactId>
<version>6.0.0-SNAPSHOT</version> <version>5.4.0</version>
<parent> <parent>
<groupId>org.springframework.data.build</groupId> <groupId>org.springframework.data.build</groupId>
<artifactId>spring-data-parent</artifactId> <artifactId>spring-data-parent</artifactId>
<version>4.0.0-SNAPSHOT</version> <version>3.4.0</version>
</parent> </parent>
<name>Spring Data Elasticsearch</name> <name>Spring Data Elasticsearch</name>
@ -18,10 +18,10 @@
<url>https://github.com/spring-projects/spring-data-elasticsearch</url> <url>https://github.com/spring-projects/spring-data-elasticsearch</url>
<properties> <properties>
<springdata.commons>4.0.0-SNAPSHOT</springdata.commons> <springdata.commons>3.4.0</springdata.commons>
<!-- version of the ElasticsearchClient --> <!-- version of the ElasticsearchClient -->
<elasticsearch-java>9.0.3</elasticsearch-java> <elasticsearch-java>8.15.3</elasticsearch-java>
<hoverfly>0.19.0</hoverfly> <hoverfly>0.19.0</hoverfly>
<log4j>2.23.1</log4j> <log4j>2.23.1</log4j>
@ -132,27 +132,6 @@
</exclusions> </exclusions>
</dependency> </dependency>
<!-- the old RestCLient is an optional dependency for user that still want to use it-->
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-client</artifactId>
<version>${elasticsearch-java}</version>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-core</artifactId>
<version>${querydsl}</version>
<optional>true</optional>
</dependency>
<!-- Jackson JSON Mapper --> <!-- Jackson JSON Mapper -->
<dependency> <dependency>
<groupId>com.fasterxml.jackson.core</groupId> <groupId>com.fasterxml.jackson.core</groupId>
@ -471,20 +450,8 @@
</profiles> </profiles>
<repositories> <repositories>
<repository>
<id>spring-snapshot</id>
<url>https://repo.spring.io/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
<releases>
<enabled>false</enabled>
</releases>
</repository>
<repository>
<id>spring-milestone</id>
<url>https://repo.spring.io/milestone</url>
</repository>
</repositories> </repositories>
</project> </project>

View File

@ -17,7 +17,7 @@ content:
- url: https://github.com/spring-projects/spring-data-commons - url: https://github.com/spring-projects/spring-data-commons
# Refname matching: # Refname matching:
# https://docs.antora.org/antora/latest/playbook/content-refname-matching/ # https://docs.antora.org/antora/latest/playbook/content-refname-matching/
branches: [ main, 3.4.x, 3.3.x ] branches: [ main, 3.2.x ]
start_path: src/main/antora start_path: src/main/antora
asciidoc: asciidoc:
attributes: attributes:

View File

@ -11,8 +11,6 @@
*** xref:migration-guides/migration-guide-5.1-5.2.adoc[] *** xref:migration-guides/migration-guide-5.1-5.2.adoc[]
*** xref:migration-guides/migration-guide-5.2-5.3.adoc[] *** xref:migration-guides/migration-guide-5.2-5.3.adoc[]
*** xref:migration-guides/migration-guide-5.3-5.4.adoc[] *** xref:migration-guides/migration-guide-5.3-5.4.adoc[]
*** xref:migration-guides/migration-guide-5.4-5.5.adoc[]
*** xref:migration-guides/migration-guide-5.5-6.0.adoc[]
* xref:elasticsearch.adoc[] * xref:elasticsearch.adoc[]

View File

@ -10,7 +10,7 @@ In order for the auditing code to be able to decide whether an entity instance i
---- ----
package org.springframework.data.domain; package org.springframework.data.domain;
import org.jspecify.annotations.Nullable; import org.springframework.lang.Nullable;
public interface Persistable<ID> { public interface Persistable<ID> {
@Nullable @Nullable

View File

@ -6,10 +6,10 @@ This chapter illustrates configuration and usage of supported Elasticsearch clie
Spring Data Elasticsearch operates upon an Elasticsearch client (provided by Elasticsearch client libraries) that is connected to a single Elasticsearch node or a cluster. Spring Data Elasticsearch operates upon an Elasticsearch client (provided by Elasticsearch client libraries) that is connected to a single Elasticsearch node or a cluster.
Although the Elasticsearch Client can be used directly to work with the cluster, applications using Spring Data Elasticsearch normally use the higher level abstractions of xref:elasticsearch/template.adoc[Elasticsearch Operations] and xref:elasticsearch/repositories/elasticsearch-repositories.adoc[Elasticsearch Repositories]. Although the Elasticsearch Client can be used directly to work with the cluster, applications using Spring Data Elasticsearch normally use the higher level abstractions of xref:elasticsearch/template.adoc[Elasticsearch Operations] and xref:elasticsearch/repositories/elasticsearch-repositories.adoc[Elasticsearch Repositories].
[[elasticsearch.clients.rest5client]] [[elasticsearch.clients.restclient]]
== Imperative Rest5Client == Imperative Rest Client
To use the imperative (non-reactive) Rest5Client, a configuration bean must be configured like this: To use the imperative (non-reactive) client, a configuration bean must be configured like this:
==== ====
[source,java] [source,java]
@ -31,81 +31,7 @@ public class MyClientConfig extends ElasticsearchConfiguration {
<.> for a detailed description of the builder methods see xref:elasticsearch/clients.adoc#elasticsearch.clients.configuration[Client Configuration] <.> for a detailed description of the builder methods see xref:elasticsearch/clients.adoc#elasticsearch.clients.configuration[Client Configuration]
==== ====
The javadoc:org.springframework.data.elasticsearch.client.elc.ElasticsearchConfiguration[] class allows further configuration by overriding for example the `jsonpMapper()` or `transportOptions()` methods. The javadoc:org.springframework.data.elasticsearch.client.elc.ElasticsearchConfiguration[]] class allows further configuration by overriding for example the `jsonpMapper()` or `transportOptions()` methods.
The following beans can then be injected in other Spring components:
====
[source,java]
----
import org.springframework.beans.factory.annotation.Autowired;@Autowired
ElasticsearchOperations operations; <.>
@Autowired
ElasticsearchClient elasticsearchClient; <.>
@Autowired
Rest5Client rest5Client; <.>
@Autowired
JsonpMapper jsonpMapper; <.>
----
<.> an implementation of javadoc:org.springframework.data.elasticsearch.core.ElasticsearchOperations[]
<.> the `co.elastic.clients.elasticsearch.ElasticsearchClient` that is used.
<.> the low level `Rest5Client` from the Elasticsearch libraries
<.> the `JsonpMapper` user by the Elasticsearch `Transport`
====
Basically one should just use the javadoc:org.springframework.data.elasticsearch.core.ElasticsearchOperations[] to interact with the Elasticsearch cluster.
When using repositories, this instance is used under the hood as well.
[[elasticsearch.clients.restclient]]
== Deprecated Imperative RestClient
To use the imperative (non-reactive) RestClient - deprecated since version 6 - , the following dependency needs to be added, adapt the correct version. The exclusion is needed in a Spring Boot application:
====
[source,xml]
----
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-client</artifactId>
<version>${elasticsearch-client.version}</version>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
----
====
The configuration bean must be configured like this:
====
[source,java]
----
import org.springframework.data.elasticsearch.client.elc.ElasticsearchLegacyRestClientConfiguration;
@Configuration
public class MyClientConfig extends ElasticsearchLegacyRestClientConfiguration {
@Override
public ClientConfiguration clientConfiguration() {
return ClientConfiguration.builder() <.>
.connectedTo("localhost:9200")
.build();
}
}
----
<.> for a detailed description of the builder methods see xref:elasticsearch/clients.adoc#elasticsearch.clients.configuration[Client Configuration]
====
The javadoc:org.springframework.data.elasticsearch.client.elc.ElasticsearchConfiguration[] class allows further configuration by overriding for example the `jsonpMapper()` or `transportOptions()` methods.
The following beans can then be injected in other Spring components: The following beans can then be injected in other Spring components:
@ -135,8 +61,8 @@ JsonpMapper jsonpMapper; <.>
Basically one should just use the javadoc:org.springframework.data.elasticsearch.core.ElasticsearchOperations[] to interact with the Elasticsearch cluster. Basically one should just use the javadoc:org.springframework.data.elasticsearch.core.ElasticsearchOperations[] to interact with the Elasticsearch cluster.
When using repositories, this instance is used under the hood as well. When using repositories, this instance is used under the hood as well.
[[elasticsearch.clients.reactiverest5client]] [[elasticsearch.clients.reactiverestclient]]
== Reactive Rest5Client == Reactive Rest Client
When working with the reactive stack, the configuration must be derived from a different class: When working with the reactive stack, the configuration must be derived from a different class:
@ -173,65 +99,6 @@ ReactiveElasticsearchOperations operations; <.>
@Autowired @Autowired
ReactiveElasticsearchClient elasticsearchClient; <.> ReactiveElasticsearchClient elasticsearchClient; <.>
@Autowired
Rest5Client rest5Client; <.>
@Autowired
JsonpMapper jsonpMapper; <.>
----
the following can be injected:
<.> an implementation of javadoc:org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperations[]
<.> the `org.springframework.data.elasticsearch.client.elc.ReactiveElasticsearchClient` that is used.
This is a reactive implementation based on the Elasticsearch client implementation.
<.> the low level `RestClient` from the Elasticsearch libraries
<.> the `JsonpMapper` user by the Elasticsearch `Transport`
====
Basically one should just use the javadoc:org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperations[] to interact with the Elasticsearch cluster.
When using repositories, this instance is used under the hood as well.
[[elasticsearch.clients.reactiverestclient]]
== Deprecated Reactive RestClient
See the section above for the imperative code to use the deprecated RestClient for the necessary dependencies to include.
When working with the reactive stack, the configuration must be derived from a different class:
====
[source,java]
----
import org.springframework.data.elasticsearch.client.elc.ReactiveElasticsearchLegacyRestClientConfiguration;
@Configuration
public class MyClientConfig extends ReactiveElasticsearchLegacyRestClientConfiguration {
@Override
public ClientConfiguration clientConfiguration() {
return ClientConfiguration.builder() <.>
.connectedTo("localhost:9200")
.build();
}
}
----
<.> for a detailed description of the builder methods see xref:elasticsearch/clients.adoc#elasticsearch.clients.configuration[Client Configuration]
====
The javadoc:org.springframework.data.elasticsearch.client.elc.ReactiveElasticsearchConfiguration[] class allows further configuration by overriding for example the `jsonpMapper()` or `transportOptions()` methods.
The following beans can then be injected in other Spring components:
====
[source,java]
----
@Autowired
ReactiveElasticsearchOperations operations; <.>
@Autowired
ReactiveElasticsearchClient elasticsearchClient; <.>
@Autowired @Autowired
RestClient restClient; <.> RestClient restClient; <.>
@ -316,25 +183,8 @@ In the case this is not enough, the user can add callback functions by using the
The following callbacks are provided: The following callbacks are provided:
[[elasticsearch.clients.configuration.callbacks.rest5]]
==== Configuration of the low level Elasticsearch `Rest5Client`:
This callback provides a `org.elasticsearch.client.RestClientBuilder` that can be used to configure the Elasticsearch
`RestClient`:
====
[source,java]
----
ClientConfiguration.builder()
.connectedTo("localhost:9200", "localhost:9291")
.withClientConfigurer(Rest5Clients.ElasticsearchRest5ClientConfigurationCallback.from(restClientBuilder -> {
// configure the Elasticsearch Rest5Client
return restClientBuilder;
}))
.build();
----
====
[[elasticsearch.clients.configuration.callbacks.rest]] [[elasticsearch.clients.configuration.callbacks.rest]]
==== Configuration of the deprecated low level Elasticsearch `RestClient`: ==== Configuration of the low level Elasticsearch `RestClient`:
This callback provides a `org.elasticsearch.client.RestClientBuilder` that can be used to configure the Elasticsearch This callback provides a `org.elasticsearch.client.RestClientBuilder` that can be used to configure the Elasticsearch
`RestClient`: `RestClient`:
@ -343,7 +193,7 @@ This callback provides a `org.elasticsearch.client.RestClientBuilder` that can b
---- ----
ClientConfiguration.builder() ClientConfiguration.builder()
.connectedTo("localhost:9200", "localhost:9291") .connectedTo("localhost:9200", "localhost:9291")
.withClientConfigurer(RestClients.ElasticsearchRestClientConfigurationCallback.from(restClientBuilder -> { .withClientConfigurer(ElasticsearchClients.ElasticsearchRestClientConfigurationCallback.from(restClientBuilder -> {
// configure the Elasticsearch RestClient // configure the Elasticsearch RestClient
return restClientBuilder; return restClientBuilder;
})) }))
@ -351,29 +201,10 @@ ClientConfiguration.builder()
---- ----
==== ====
[[elasticsearch.clients.configurationcallbacks.httpasync5]]
==== Configuration of the HttpAsyncClient used by the low level Elasticsearch `Rest5Client`:
This callback provides a `org.apache.hc.client5.http.impl.async.HttpAsyncClientBuilder` to configure the HttpClient that is
used by the `Rest5Client`.
====
[source,java]
----
ClientConfiguration.builder()
.connectedTo("localhost:9200", "localhost:9291")
.withClientConfigurer(Rest5Clients.ElasticsearchHttpClientConfigurationCallback.from(httpAsyncClientBuilder -> {
// configure the HttpAsyncClient
return httpAsyncClientBuilder;
}))
.build();
----
====
[[elasticsearch.clients.configurationcallbacks.httpasync]] [[elasticsearch.clients.configurationcallbacks.httpasync]]
==== Configuration of the HttpAsyncClient used by the deprecated low level Elasticsearch `RestClient`: ==== Configuration of the HttpAsyncClient used by the low level Elasticsearch `RestClient`:
This callback provides a `org.apache.http.impl.nio.client.HttpAsyncClientBuilder` to configure the HttpClient that is This callback provides a `org.apache.http.impl.nio.client.HttpAsyncClientBuilder` to configure the HttpCLient that is
used by the `RestClient`. used by the `RestClient`.
==== ====
@ -381,7 +212,7 @@ used by the `RestClient`.
---- ----
ClientConfiguration.builder() ClientConfiguration.builder()
.connectedTo("localhost:9200", "localhost:9291") .connectedTo("localhost:9200", "localhost:9291")
.withClientConfigurer(RestClients.ElasticsearchHttpClientConfigurationCallback.from(httpAsyncClientBuilder -> { .withClientConfigurer(ElasticsearchClients.ElasticsearchHttpClientConfigurationCallback.from(httpAsyncClientBuilder -> {
// configure the HttpAsyncClient // configure the HttpAsyncClient
return httpAsyncClientBuilder; return httpAsyncClientBuilder;
})) }))

View File

@ -1,22 +1,6 @@
[[new-features]] [[new-features]]
= What's new = What's new
[[new-features.6-0-0]]
== New in Spring Data Elasticsearch 6.0
* Upgarde to Spring 7
* Switch to jspecify nullability annotations
* Upgrade to Elasticsearch 9.0.3
* Use the new Elasticsearch Rest5Client as default
[[new-features.5-5-0]]
== New in Spring Data Elasticsearch 5.5
* Upgrade to Elasticsearch 8.18.1.
* Add support for the `@SearchTemplateQuery` annotation on repository methods.
* Scripted field properties of type collection can be populated from scripts returning arrays.
[[new-features.5-4-0]] [[new-features.5-4-0]]
== New in Spring Data Elasticsearch 5.4 == New in Spring Data Elasticsearch 5.4

View File

@ -365,8 +365,6 @@ operations.putScript( <.>
To use a search template in a search query, Spring Data Elasticsearch provides the `SearchTemplateQuery`, an implementation of the `org.springframework.data.elasticsearch.core.query.Query` interface. To use a search template in a search query, Spring Data Elasticsearch provides the `SearchTemplateQuery`, an implementation of the `org.springframework.data.elasticsearch.core.query.Query` interface.
NOTE: Although `SearchTemplateQuery` is an implementation of the `Query` interface, not all of the functionality provided by the base class is available for a `SearchTemplateQuery` like setting a `Pageable` or a `Sort`. Values for this functionality must be added to the stored script like shown in the following example for paging parameters. If these values are set on the `Query` object, they will be ignored.
In the following code, we will add a call using a search template query to a custom repository implementation (see In the following code, we will add a call using a search template query to a custom repository implementation (see
xref:repositories/custom-implementations.adoc[]) as an example how this can be integrated into a repository call. xref:repositories/custom-implementations.adoc[]) as an example how this can be integrated into a repository call.
@ -451,3 +449,4 @@ var query = Query.findAll().addSort(Sort.by(order));
About the filter query: It is not possible to use a `CriteriaQuery` here, as this query would be converted into a Elasticsearch nested query which does not work in the filter context. So only `StringQuery` or `NativeQuery` can be used here. When using one of these, like the term query above, the Elasticsearch field names must be used, so take care, when these are redefined with the `@Field(name="...")` definition. About the filter query: It is not possible to use a `CriteriaQuery` here, as this query would be converted into a Elasticsearch nested query which does not work in the filter context. So only `StringQuery` or `NativeQuery` can be used here. When using one of these, like the term query above, the Elasticsearch field names must be used, so take care, when these are redefined with the `@Field(name="...")` definition.
For the definition of the order path and the nested paths, the Java entity property names should be used. For the definition of the order path and the nested paths, the Java entity property names should be used.

View File

@ -10,9 +10,7 @@ The Elasticsearch module supports all basic query building feature as string que
=== Declared queries === Declared queries
Deriving the query from the method name is not always sufficient and/or may result in unreadable method names. Deriving the query from the method name is not always sufficient and/or may result in unreadable method names.
In this case one might make use of the `@Query` annotation (see xref:elasticsearch/repositories/elasticsearch-repository-queries.adoc#elasticsearch.query-methods.at-query[Using the @Query Annotation] ). In this case one might make use of the `@Query` annotation (see xref:elasticsearch/repositories/elasticsearch-repository-queries.adoc#elasticsearch.query-methods.at-query[Using @Query Annotation] ).
Another possibility is the use of a search-template, (see xref:elasticsearch/repositories/elasticsearch-repository-queries.adoc#elasticsearch.query-methods.at-searchtemplate-query[Using the @SearchTemplateQuery Annotation] ).
[[elasticsearch.query-methods.criterions]] [[elasticsearch.query-methods.criterions]]
== Query creation == Query creation
@ -314,13 +312,11 @@ Repository methods can be defined to have the following return types for returni
* `SearchPage<T>` * `SearchPage<T>`
[[elasticsearch.query-methods.at-query]] [[elasticsearch.query-methods.at-query]]
== Using the @Query Annotation == Using @Query Annotation
.Declare query on the method using the `@Query` annotation. .Declare query on the method using the `@Query` annotation.
==== ====
The arguments passed to the method can be inserted into placeholders in the query string. The arguments passed to the method can be inserted into placeholders in the query string. The placeholders are of the form `?0`, `?1`, `?2` etc. for the first, second, third parameter and so on.
The placeholders are of the form `?0`, `?1`, `?2` etc. for the first, second, third parameter and so on.
[source,java] [source,java]
---- ----
interface BookRepository extends ElasticsearchRepository<Book, String> { interface BookRepository extends ElasticsearchRepository<Book, String> {
@ -345,20 +341,15 @@ It will be sent to Easticsearch as value of the query element; if for example th
} }
---- ----
==== ====
.`@Query` annotation on a method taking a Collection argument .`@Query` annotation on a method taking a Collection argument
==== ====
A repository method such as A repository method such as
[source,java] [source,java]
---- ----
@Query("{\"ids\": {\"values\": ?0 }}") @Query("{\"ids\": {\"values\": ?0 }}")
List<SampleEntity> getByIds(Collection<String> ids); List<SampleEntity> getByIds(Collection<String> ids);
---- ----
would make an https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-ids-query.html[IDs query] to return all the matching documents. So calling the method with a `List` of `["id1", "id2", "id3"]` would produce the query body
would make an https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-ids-query.html[IDs query] to return all the matching documents.
So calling the method with a `List` of `["id1", "id2", "id3"]` would produce the query body
[source,json] [source,json]
---- ----
{ {
@ -378,6 +369,7 @@ So calling the method with a `List` of `["id1", "id2", "id3"]` would produce the
==== ====
https://docs.spring.io/spring-framework/reference/core/expressions.html[SpEL expression] is also supported when defining query in `@Query`. https://docs.spring.io/spring-framework/reference/core/expressions.html[SpEL expression] is also supported when defining query in `@Query`.
[source,java] [source,java]
---- ----
interface BookRepository extends ElasticsearchRepository<Book, String> { interface BookRepository extends ElasticsearchRepository<Book, String> {
@ -419,7 +411,6 @@ If for example the function is called with the parameter _John_, it would produc
.accessing parameter property. .accessing parameter property.
==== ====
Supposing that we have the following class as query parameter type: Supposing that we have the following class as query parameter type:
[source,java] [source,java]
---- ----
public record QueryParameter(String value) { public record QueryParameter(String value) {
@ -453,9 +444,7 @@ We can pass `new QueryParameter("John")` as the parameter now, and it will produ
.accessing bean property. .accessing bean property.
==== ====
https://docs.spring.io/spring-framework/reference/core/expressions/language-ref/bean-references.html[Bean property] is also supported to access. https://docs.spring.io/spring-framework/reference/core/expressions/language-ref/bean-references.html[Bean property] is also supported to access. Given that there is a bean named `queryParameter` of type `QueryParameter`, we can access the bean with symbol `@` rather than `#`, and there is no need to declare a parameter of type `QueryParameter` in the query method:
Given that there is a bean named `queryParameter` of type `QueryParameter`, we can access the bean with symbol `@` rather than `#`, and there is no need to declare a parameter of type `QueryParameter` in the query method:
[source,java] [source,java]
---- ----
interface BookRepository extends ElasticsearchRepository<Book, String> { interface BookRepository extends ElasticsearchRepository<Book, String> {
@ -504,7 +493,6 @@ interface BookRepository extends ElasticsearchRepository<Book, String> {
NOTE: collection values should not be quoted when declaring the elasticsearch json query. NOTE: collection values should not be quoted when declaring the elasticsearch json query.
A collection of `names` like `List.of("name1", "name2")` will produce the following terms query: A collection of `names` like `List.of("name1", "name2")` will produce the following terms query:
[source,json] [source,json]
---- ----
{ {
@ -544,7 +532,6 @@ interface BookRepository extends ElasticsearchRepository<Book, String> {
Page<Book> findByName(Collection<QueryParameter> parameters, Pageable pageable); Page<Book> findByName(Collection<QueryParameter> parameters, Pageable pageable);
} }
---- ----
This will extract all the `value` property values as a new `Collection` from `QueryParameter` collection, thus takes the same effect as above. This will extract all the `value` property values as a new `Collection` from `QueryParameter` collection, thus takes the same effect as above.
==== ====
@ -573,20 +560,3 @@ interface BookRepository extends ElasticsearchRepository<Book, String> {
---- ----
==== ====
[[elasticsearch.query-methods.at-searchtemplate-query]]
== Using the @SearchTemplateQuery Annotation
When using Elasticsearch search templates - (see xref:elasticsearch/misc.adoc#elasticsearch.misc.searchtemplates [Search Template support]) it is possible to specify that a repository method should use a template by adding the `@SearchTemplateQuery` annotation to that method.
Let's assume that there is a search template stored with the name "book-by-title" and this template need a parameter named "title", then a repository method using that search template can be defined like this:
[source,java]
----
interface BookRepository extends ElasticsearchRepository<Book, String> {
@SearchTemplateQuery(id = "book-by-title")
SearchHits<Book> findByTitle(String title);
}
----
The parameters of the repository method are sent to the seacrh template as key/value pairs where the key is the parameter name and the value is taken from the actual value when the method is invoked.

View File

@ -20,12 +20,12 @@ Whereas the birthdate is fix, the age depends on the time when a query is issued
==== ====
[source,java] [source,java]
---- ----
import org.jspecify.annotations.Nullable;
import org.springframework.data.annotation.Id; import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.DateFormat; import org.springframework.data.elasticsearch.annotations.DateFormat;
import org.springframework.data.elasticsearch.annotations.Document; import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field; import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.ScriptedField; import org.springframework.data.elasticsearch.annotations.ScriptedField;
import org.springframework.lang.Nullable;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;

View File

@ -6,13 +6,11 @@ The following table shows the Elasticsearch and Spring versions that are used by
[cols="^,^,^,^",options="header"] [cols="^,^,^,^",options="header"]
|=== |===
| Spring Data Release Train | Spring Data Elasticsearch | Elasticsearch | Spring Framework | Spring Data Release Train | Spring Data Elasticsearch | Elasticsearch | Spring Framework
| 2025.1 (in development) | 6.0.x | 9.0.3 | 7.0.x | 2024.1 (in development) | 5.3.x | 8.15.3 | 6.1.x
| 2025.0 | 5.5.x | 8.18.1 | 6.2.x | 2024.0 | 5.3.1 | 8.13.4 | 6.1.x
| 2024.1 | 5.4.x | 8.15.5 | 6.1.x | 2023.1 (Vaughan) | 5.2.x | 8.11.1 | 6.1.x
| 2024.0 | 5.3.xfootnote:oom[Out of maintenance] | 8.13.4 | 6.1.x | 2023.0 (Ullmann) | 5.1.x | 8.7.1 | 6.0.x
| 2023.1 (Vaughan) | 5.2.xfootnote:oom[] | 8.11.1 | 6.1.x | 2022.0 (Turing) | 5.0.xfootnote:oom[Out of maintenance] | 8.5.3 | 6.0.x
| 2023.0 (Ullmann) | 5.1.xfootnote:oom[] | 8.7.1 | 6.0.x
| 2022.0 (Turing) | 5.0.xfootnote:oom[] | 8.5.3 | 6.0.x
| 2021.2 (Raj) | 4.4.xfootnote:oom[] | 7.17.3 | 5.3.x | 2021.2 (Raj) | 4.4.xfootnote:oom[] | 7.17.3 | 5.3.x
| 2021.1 (Q) | 4.3.xfootnote:oom[] | 7.15.2 | 5.3.x | 2021.1 (Q) | 4.3.xfootnote:oom[] | 7.15.2 | 5.3.x
| 2021.0 (Pascal) | 4.2.xfootnote:oom[] | 7.12.0 | 5.3.x | 2021.0 (Pascal) | 4.2.xfootnote:oom[] | 7.12.0 | 5.3.x

View File

@ -1,30 +0,0 @@
[[elasticsearch-migration-guide-5.4-5.5]]
= Upgrading from 5.4.x to 5.5.x
This section describes breaking changes from version 5.4.x to 5.5.x and how removed features can be replaced by new introduced features.
[[elasticsearch-migration-guide-5.4-5.5.breaking-changes]]
== Breaking Changes
[[elasticsearch-migration-guide-5.4-5.5.deprecations]]
== Deprecations
Some classes that probably are not used by a library user have been renamed, the classes with the old names are still there, but are deprecated:
|===
|old name|new name
|ElasticsearchPartQuery|RepositoryPartQuery
|ElasticsearchStringQuery|RepositoryStringQuery
|ReactiveElasticsearchStringQuery|ReactiveRepositoryStringQuery
|===
=== Removals
The following methods that had been deprecated since release 5.3 have been removed:
```
DocumentOperations.delete(Query, Class<?>)
DocumentOperations.delete(Query, Class<?>, IndexCoordinates)
ReactiveDocumentOperations.delete(Query, Class<?>)
ReactiveDocumentOperations.delete(Query, Class<?>, IndexCoordinates)
```

View File

@ -1,25 +0,0 @@
[[elasticsearch-migration-guide-5.5-6.0]]
= Upgrading from 5.5.x to 6.0.x
This section describes breaking changes from version 5.5.x to 6.0.x and how removed features can be replaced by new introduced features.
[[elasticsearch-migration-guide-5.5-6.0.breaking-changes]]
== Breaking Changes
From version 6.0 on, Spring Data Elasticsearch uses the Elasticsearch 9 libraries and as default the new `Rest5Client` provided by these libraries. It is still possible to use the old `RestClient`, check xref:elasticsearch/clients.adoc[Elasticsearch clients] for information. The configuration callbacks for this `RestClient` have been moved from `org.springframework.data.elasticsearch.client.elc.ElasticsearchClients` to the `org.springframework.data.elasticsearch.client.elc.rest_client.RestClients` class.
[[elasticsearch-migration-guide-5.5-6.0.deprecations]]
== Deprecations
All the code using the old `RestClient` has been moved to the `org.springframework.data.elasticsearch.client.elc.rest_client` package and has been deprecated. Users should switch to the classes from the `org.springframework.data.elasticsearch.client.elc.rest5_client` package.
=== Removals
The `org.springframework.data.elasticsearch.core.query.ScriptType` enum has been removed. To distinguish between an inline and a stored script set the appropriate values in the `org.springframework.data.elasticsearch.core.query.ScriptData` record.
These methods have been removed because the Elasticsearch Client 9 does not support them anymore:
```
org.springframework.data.elasticsearch.client.elc.ReactiveElasticsearchIndicesClient.unfreeze(UnfreezeRequest)
org.springframework.data.elasticsearch.client.elc.ReactiveElasticsearchIndicesClient.unfreeze(Function<UnfreezeRequest.Builder, ObjectBuilder<UnfreezeRequest>>)
```

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2020-2025 the original author or authors. * Copyright 2020-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2022-2025 the original author or authors. * Copyright 2022-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -15,9 +15,9 @@
*/ */
package org.springframework.data.elasticsearch; package org.springframework.data.elasticsearch;
import java.util.List; import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable; import java.util.List;
/** /**
* Object describing an Elasticsearch error * Object describing an Elasticsearch error
@ -26,7 +26,8 @@ import org.jspecify.annotations.Nullable;
* @since 4.4 * @since 4.4
*/ */
public class ElasticsearchErrorCause { public class ElasticsearchErrorCause {
@Nullable private final String type; @Nullable
private final String type;
private final String reason; private final String reason;

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2025 the original author or authors. * Copyright 2019-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2021-2025 the original author or authors. * Copyright 2021-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2022-2025 the original author or authors. * Copyright 2022-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2021-2025 the original author or authors. * Copyright 2021-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2020-2025 the original author or authors. * Copyright 2020-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -15,8 +15,8 @@
*/ */
package org.springframework.data.elasticsearch; package org.springframework.data.elasticsearch;
import org.jspecify.annotations.Nullable;
import org.springframework.dao.UncategorizedDataAccessException; import org.springframework.dao.UncategorizedDataAccessException;
import org.springframework.lang.Nullable;
/** /**
* @author Peter-Josef Meisch * @author Peter-Josef Meisch

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2023-2025 the original author or authors. * Copyright 2023-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2024-2025 the original author or authors. * Copyright 2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2024-2025 the original author or authors. * Copyright 2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2025 the original author or authors. * Copyright 2019-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2013-2025 the original author or authors. * Copyright 2013-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2021-2025 the original author or authors. * Copyright 2021-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2014-2025 the original author or authors. * Copyright 2014-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2013-2025 the original author or authors. * Copyright 2013-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2021-2025 the original author or authors. * Copyright 2021-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2013-2025 the original author or authors. * Copyright 2013-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2024-2025 the original author or authors. * Copyright 2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2013-2025 the original author or authors. * Copyright 2013-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2024-2025 the original author or authors. * Copyright 2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2013-2025 the original author or authors. * Copyright 2013-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2017-2025 the original author or authors. * Copyright 2017-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2020-2025 the original author or authors. * Copyright 2020-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2020-2025 the original author or authors. * Copyright 2020-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2020-2025 the original author or authors. * Copyright 2020-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2025 the original author or authors. * Copyright 2019-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2025 the original author or authors. * Copyright 2019-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2023-2025 the original author or authors. * Copyright 2023-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2014-2025 the original author or authors. * Copyright 2014-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2020-2025 the original author or authors. * Copyright 2020-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2020-2025 the original author or authors. * Copyright 2020-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2024-2025 the original author or authors. * Copyright 2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2024-2025 the original author or authors. * Copyright 2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2024-2025 the original author or authors. * Copyright 2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2014-2025 the original author or authors. * Copyright 2014-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2024-2025 the original author or authors. * Copyright 2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2014-2025 the original author or authors. * Copyright 2014-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2020-2025 the original author or authors. * Copyright 2020-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2013-2025 the original author or authors. * Copyright 2013-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,42 +0,0 @@
/*
* Copyright 2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.elasticsearch.annotations;
import org.springframework.data.annotation.QueryAnnotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Annotation to mark a repository method as a search template method. The annotation defines the search template id,
* the parameters for the search template are taken from the method's arguments.
*
* @author P.J. Meisch (pj.meisch@sothawo.com)
* @since 5.5
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE })
@Documented
@QueryAnnotation
public @interface SearchTemplateQuery {
/**
* The id of the search template. Must not be empt or null.
*/
String id();
}

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2014-2025 the original author or authors. * Copyright 2014-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2025 the original author or authors. * Copyright 2019-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2022-2025 the original author or authors. * Copyright 2022-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2025 the original author or authors. * Copyright 2019-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2021-2025 the original author or authors. * Copyright 2021-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2022-2025 the original author or authors. * Copyright 2022-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2021-2025 the original author or authors. * Copyright 2021-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,2 +1,3 @@
@org.jspecify.annotations.NullMarked @org.springframework.lang.NonNullApi
@org.springframework.lang.NonNullFields
package org.springframework.data.elasticsearch.annotations; package org.springframework.data.elasticsearch.annotations;

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2023-2025 the original author or authors. * Copyright 2023-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2023-2025 the original author or authors. * Copyright 2023-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -19,7 +19,6 @@ import static org.springframework.data.elasticsearch.aot.ElasticsearchAotPredica
import java.util.Arrays; import java.util.Arrays;
import org.jspecify.annotations.Nullable;
import org.springframework.aot.hint.MemberCategory; import org.springframework.aot.hint.MemberCategory;
import org.springframework.aot.hint.RuntimeHints; import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar; import org.springframework.aot.hint.RuntimeHintsRegistrar;
@ -33,6 +32,7 @@ import org.springframework.data.elasticsearch.core.event.ReactiveAfterConvertCal
import org.springframework.data.elasticsearch.core.event.ReactiveAfterLoadCallback; import org.springframework.data.elasticsearch.core.event.ReactiveAfterLoadCallback;
import org.springframework.data.elasticsearch.core.event.ReactiveAfterSaveCallback; import org.springframework.data.elasticsearch.core.event.ReactiveAfterSaveCallback;
import org.springframework.data.elasticsearch.core.event.ReactiveBeforeConvertCallback; import org.springframework.data.elasticsearch.core.event.ReactiveBeforeConvertCallback;
import org.springframework.lang.Nullable;
/** /**
* @author Peter-Josef Meisch * @author Peter-Josef Meisch

View File

@ -1,2 +1,3 @@
@org.jspecify.annotations.NullMarked @org.springframework.lang.NonNullApi
@org.springframework.lang.NonNullFields
package org.springframework.data.elasticsearch.aot; package org.springframework.data.elasticsearch.aot;

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2018-2025 the original author or authors. * Copyright 2018-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -25,8 +25,8 @@ import java.util.function.Supplier;
import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext; import javax.net.ssl.SSLContext;
import org.jspecify.annotations.Nullable;
import org.springframework.data.elasticsearch.support.HttpHeaders; import org.springframework.data.elasticsearch.support.HttpHeaders;
import org.springframework.lang.Nullable;
/** /**
* Configuration interface exposing common client configuration properties for Elasticsearch clients. * Configuration interface exposing common client configuration properties for Elasticsearch clients.
@ -127,16 +127,10 @@ public interface ClientConfiguration {
Optional<String> getCaFingerprint(); Optional<String> getCaFingerprint();
/** /**
* Returns the {@link HostnameVerifier} to use. Must be {@link Optional#empty()} if not configured. * Returns the {@link HostnameVerifier} to use. Can be {@link Optional#empty()} if not configured.
* Cannot be used with the Rest5Client used from Elasticsearch 9 on as the underlying Apache http components 5 does not offer a way
* to set this. Users that need a hostname verifier must integrate this in a SSLContext.
* Returning a value here is ignored in this case
* *
* @return the {@link HostnameVerifier} to use. Can be {@link Optional#empty()} if not configured. * @return the {@link HostnameVerifier} to use. Can be {@link Optional#empty()} if not configured.
* @deprecated since 6.0
*/ */
// todo #3117 document this
@Deprecated(since = "6.0", forRemoval=true)
Optional<HostnameVerifier> getHostNameVerifier(); Optional<HostnameVerifier> getHostNameVerifier();
/** /**

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2018-2025 the original author or authors. * Copyright 2018-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -25,11 +25,11 @@ import java.util.function.Supplier;
import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext; import javax.net.ssl.SSLContext;
import org.jspecify.annotations.Nullable;
import org.springframework.data.elasticsearch.client.ClientConfiguration.ClientConfigurationBuilderWithRequiredEndpoint; import org.springframework.data.elasticsearch.client.ClientConfiguration.ClientConfigurationBuilderWithRequiredEndpoint;
import org.springframework.data.elasticsearch.client.ClientConfiguration.MaybeSecureClientConfigurationBuilder; import org.springframework.data.elasticsearch.client.ClientConfiguration.MaybeSecureClientConfigurationBuilder;
import org.springframework.data.elasticsearch.client.ClientConfiguration.TerminalClientConfigurationBuilder; import org.springframework.data.elasticsearch.client.ClientConfiguration.TerminalClientConfigurationBuilder;
import org.springframework.data.elasticsearch.support.HttpHeaders; import org.springframework.data.elasticsearch.support.HttpHeaders;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert; import org.springframework.util.Assert;
/** /**

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2018-2025 the original author or authors. * Copyright 2018-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -24,8 +24,9 @@ import java.util.function.Supplier;
import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext; import javax.net.ssl.SSLContext;
import org.jspecify.annotations.Nullable; import org.elasticsearch.client.RestClientBuilder.HttpClientConfigCallback;
import org.springframework.data.elasticsearch.support.HttpHeaders; import org.springframework.data.elasticsearch.support.HttpHeaders;
import org.springframework.lang.Nullable;
/** /**
* Default {@link ClientConfiguration} implementation. * Default {@link ClientConfiguration} implementation.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2018-2025 the original author or authors. * Copyright 2018-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2018-2025 the original author or authors. * Copyright 2018-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2018-2025 the original author or authors. * Copyright 2018-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2022-2025 the original author or authors. * Copyright 2022-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2022-2025 the original author or authors. * Copyright 2022-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2024-2025 the original author or authors. * Copyright 2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -17,10 +17,10 @@ package org.springframework.data.elasticsearch.client.elc;
import java.util.function.Consumer; import java.util.function.Consumer;
import org.jspecify.annotations.Nullable;
import org.springframework.data.elasticsearch.core.query.CriteriaQuery; import org.springframework.data.elasticsearch.core.query.CriteriaQuery;
import org.springframework.data.elasticsearch.core.query.Query; import org.springframework.data.elasticsearch.core.query.Query;
import org.springframework.data.elasticsearch.core.query.StringQuery; import org.springframework.data.elasticsearch.core.query.StringQuery;
import org.springframework.lang.Nullable;
/** /**
* An abstract class that serves as a base for query processors. It provides a common interface and basic functionality * An abstract class that serves as a base for query processors. It provides a common interface and basic functionality
@ -38,8 +38,8 @@ public abstract class AbstractQueryProcessor {
* @param queryConverter correct mapped field names and the values to the converted values. * @param queryConverter correct mapped field names and the values to the converted values.
* @return an Elasticsearch {@literal query}. * @return an Elasticsearch {@literal query}.
*/ */
@Nullable
static co.elastic.clients.elasticsearch._types.query_dsl.@Nullable Query getEsQuery(@Nullable Query query, static co.elastic.clients.elasticsearch._types.query_dsl.Query getEsQuery(@Nullable Query query,
@Nullable Consumer<Query> queryConverter) { @Nullable Consumer<Query> queryConverter) {
if (query == null) { if (query == null) {
return null; return null;

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2022-2025 the original author or authors. * Copyright 2022-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2021-2025 the original author or authors. * Copyright 2021-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -18,8 +18,6 @@ package org.springframework.data.elasticsearch.client.elc;
import co.elastic.clients.elasticsearch.ElasticsearchClient; import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.transport.ElasticsearchTransport; import co.elastic.clients.transport.ElasticsearchTransport;
import java.io.IOException;
import org.elasticsearch.client.RestClient; import org.elasticsearch.client.RestClient;
import org.springframework.util.Assert; import org.springframework.util.Assert;
@ -38,10 +36,7 @@ public class AutoCloseableElasticsearchClient extends ElasticsearchClient implem
} }
@Override @Override
public void close() throws IOException { public void close() throws Exception {
// since Elasticsearch 8.16 the ElasticsearchClient implements (through ApiClient) the Closeable interface and transport.close();
// handles closing of the underlying transport. We now just call the base class, but keep this as we
// have been implementing AutoCloseable since 4.4 and won't change that to a mere Closeable
super.close();
} }
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2021-2025 the original author or authors. * Copyright 2021-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2021-2025 the original author or authors. * Copyright 2021-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2021-2025 the original author or authors. * Copyright 2021-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2021-2025 the original author or authors. * Copyright 2021-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2021-2025 the original author or authors. * Copyright 2021-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -31,13 +31,13 @@ import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import org.jspecify.annotations.Nullable;
import org.springframework.data.elasticsearch.annotations.FieldType; import org.springframework.data.elasticsearch.annotations.FieldType;
import org.springframework.data.elasticsearch.core.query.Criteria; import org.springframework.data.elasticsearch.core.query.Criteria;
import org.springframework.data.elasticsearch.core.query.Field; import org.springframework.data.elasticsearch.core.query.Field;
import org.springframework.data.elasticsearch.core.query.HasChildQuery; import org.springframework.data.elasticsearch.core.query.HasChildQuery;
import org.springframework.data.elasticsearch.core.query.HasParentQuery; import org.springframework.data.elasticsearch.core.query.HasParentQuery;
import org.springframework.data.elasticsearch.core.query.InnerHitsQuery; import org.springframework.data.elasticsearch.core.query.InnerHitsQuery;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert; import org.springframework.util.Assert;
/** /**

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2021-2025 the original author or authors. * Copyright 2021-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -24,17 +24,6 @@ import co.elastic.clients.elasticsearch.core.search.Hit;
import co.elastic.clients.elasticsearch.core.search.NestedIdentity; import co.elastic.clients.elasticsearch.core.search.NestedIdentity;
import co.elastic.clients.json.JsonData; import co.elastic.clients.json.JsonData;
import co.elastic.clients.json.JsonpMapper; import co.elastic.clients.json.JsonpMapper;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jspecify.annotations.Nullable;
import org.springframework.data.elasticsearch.core.MultiGetItem;
import org.springframework.data.elasticsearch.core.document.Document;
import org.springframework.data.elasticsearch.core.document.Explanation;
import org.springframework.data.elasticsearch.core.document.NestedMetaData;
import org.springframework.data.elasticsearch.core.document.SearchDocument;
import org.springframework.data.elasticsearch.core.document.SearchDocumentAdapter;
import org.springframework.data.elasticsearch.core.document.SearchDocumentResponse;
import org.springframework.util.Assert;
import java.util.Collections; import java.util.Collections;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
@ -43,6 +32,18 @@ import java.util.Map;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.data.elasticsearch.core.MultiGetItem;
import org.springframework.data.elasticsearch.core.document.Document;
import org.springframework.data.elasticsearch.core.document.Explanation;
import org.springframework.data.elasticsearch.core.document.NestedMetaData;
import org.springframework.data.elasticsearch.core.document.SearchDocument;
import org.springframework.data.elasticsearch.core.document.SearchDocumentAdapter;
import org.springframework.data.elasticsearch.core.document.SearchDocumentResponse;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/** /**
* Utility class to adapt different Elasticsearch responses to a * Utility class to adapt different Elasticsearch responses to a
* {@link org.springframework.data.elasticsearch.core.document.Document} * {@link org.springframework.data.elasticsearch.core.document.Document}
@ -56,8 +57,7 @@ final class DocumentAdapters {
private static final Log LOGGER = LogFactory.getLog(DocumentAdapters.class); private static final Log LOGGER = LogFactory.getLog(DocumentAdapters.class);
private DocumentAdapters() { private DocumentAdapters() {}
}
/** /**
* Creates a {@link SearchDocument} from a {@link Hit} returned by the Elasticsearch client. * Creates a {@link SearchDocument} from a {@link Hit} returned by the Elasticsearch client.
@ -83,7 +83,7 @@ final class DocumentAdapters {
Explanation explanation = from(hit.explanation()); Explanation explanation = from(hit.explanation());
Map<String, Double> matchedQueries = hit.matchedQueries(); List<String> matchedQueries = hit.matchedQueries();
Function<Map<String, JsonData>, EntityAsMap> fromFields = fields -> { Function<Map<String, JsonData>, EntityAsMap> fromFields = fields -> {
StringBuilder sb = new StringBuilder("{"); StringBuilder sb = new StringBuilder("{");
@ -160,7 +160,7 @@ final class DocumentAdapters {
} }
@Nullable @Nullable
private static Explanation from(co.elastic.clients.elasticsearch.core.explain.@Nullable Explanation explanation) { private static Explanation from(@Nullable co.elastic.clients.elasticsearch.core.explain.Explanation explanation) {
if (explanation == null) { if (explanation == null) {
return null; return null;

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2022-2025 the original author or authors. * Copyright 2022-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2021-2025 the original author or authors. * Copyright 2021-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -22,8 +22,8 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.jspecify.annotations.Nullable;
import org.springframework.data.elasticsearch.core.AggregationsContainer; import org.springframework.data.elasticsearch.core.AggregationsContainer;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert; import org.springframework.util.Assert;
/** /**

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2022-2025 the original author or authors. * Copyright 2022-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2022-2025 the original author or authors. * Copyright 2022-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -19,12 +19,12 @@ import co.elastic.clients.elasticsearch.ElasticsearchClient;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.jspecify.annotations.Nullable;
import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.FactoryBeanNotInitializedException; import org.springframework.beans.factory.FactoryBeanNotInitializedException;
import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.InitializingBean;
import org.springframework.data.elasticsearch.client.ClientConfiguration; import org.springframework.data.elasticsearch.client.ClientConfiguration;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert; import org.springframework.util.Assert;
/** /**

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2021-2025 the original author or authors. * Copyright 2021-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -15,38 +15,44 @@
*/ */
package org.springframework.data.elasticsearch.client.elc; package org.springframework.data.elasticsearch.client.elc;
import static org.springframework.data.elasticsearch.client.elc.rest5_client.Rest5Clients.*;
import static org.springframework.data.elasticsearch.client.elc.rest_client.RestClients.*;
import co.elastic.clients.elasticsearch.ElasticsearchClient; import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.json.JsonpMapper; import co.elastic.clients.json.JsonpMapper;
import co.elastic.clients.json.jackson.JacksonJsonpMapper; import co.elastic.clients.json.jackson.JacksonJsonpMapper;
import co.elastic.clients.transport.ElasticsearchTransport; import co.elastic.clients.transport.ElasticsearchTransport;
import co.elastic.clients.transport.TransportOptions; import co.elastic.clients.transport.TransportOptions;
import co.elastic.clients.transport.TransportUtils;
import co.elastic.clients.transport.Version; import co.elastic.clients.transport.Version;
import co.elastic.clients.transport.rest5_client.Rest5ClientOptions;
import co.elastic.clients.transport.rest5_client.Rest5ClientTransport;
import co.elastic.clients.transport.rest5_client.low_level.RequestOptions;
import co.elastic.clients.transport.rest5_client.low_level.Rest5Client;
import co.elastic.clients.transport.rest_client.RestClientOptions; import co.elastic.clients.transport.rest_client.RestClientOptions;
import co.elastic.clients.transport.rest_client.RestClientTransport; import co.elastic.clients.transport.rest_client.RestClientTransport;
import java.net.InetSocketAddress;
import java.time.Duration;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Function; import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.HttpRequestInterceptor;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.entity.ContentType; import org.apache.http.entity.ContentType;
import org.apache.http.impl.nio.client.HttpAsyncClientBuilder; import org.apache.http.impl.nio.client.HttpAsyncClientBuilder;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicNameValuePair; import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HttpContext;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient; import org.elasticsearch.client.RestClient;
import org.jspecify.annotations.Nullable; import org.elasticsearch.client.RestClientBuilder;
import org.springframework.data.elasticsearch.client.ClientConfiguration; import org.springframework.data.elasticsearch.client.ClientConfiguration;
import org.springframework.data.elasticsearch.support.VersionInfo; import org.springframework.data.elasticsearch.support.HttpHeaders;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert; import org.springframework.util.Assert;
/** /**
* Utility class to create the different Elasticsearch clients. The RestClient class is the one used in Elasticsearch * Utility class to create the different Elasticsearch clients
* until version 9, it is still available, but it's use is deprecated. The Rest5Client class is the one that should be
* used from Elasticsearch 9 on.
* *
* @author Peter-Josef Meisch * @author Peter-Josef Meisch
* @since 4.4 * @since 4.4
@ -113,32 +119,18 @@ public final class ElasticsearchClients {
* *
* @param restClient the underlying {@link RestClient} * @param restClient the underlying {@link RestClient}
* @return the {@link ReactiveElasticsearchClient} * @return the {@link ReactiveElasticsearchClient}
* @deprecated since 6.0, use the version with a Rest5Client.
*/ */
@Deprecated(since = "6.0", forRemoval = true)
public static ReactiveElasticsearchClient createReactive(RestClient restClient) { public static ReactiveElasticsearchClient createReactive(RestClient restClient) {
return createReactive(restClient, null, DEFAULT_JSONP_MAPPER); return createReactive(restClient, null, DEFAULT_JSONP_MAPPER);
} }
/**
* Creates a new {@link ReactiveElasticsearchClient}.
*
* @param rest5Client the underlying {@link RestClient}
* @return the {@link ReactiveElasticsearchClient}
*/
public static ReactiveElasticsearchClient createReactive(Rest5Client rest5Client) {
return createReactive(rest5Client, null, DEFAULT_JSONP_MAPPER);
}
/** /**
* Creates a new {@link ReactiveElasticsearchClient}. * Creates a new {@link ReactiveElasticsearchClient}.
* *
* @param restClient the underlying {@link RestClient} * @param restClient the underlying {@link RestClient}
* @param transportOptions options to be added to each request. * @param transportOptions options to be added to each request.
* @return the {@link ReactiveElasticsearchClient} * @return the {@link ReactiveElasticsearchClient}
* @deprecated since 6.0, use the version with a Rest5Client.
*/ */
@Deprecated(since = "6.0", forRemoval = true)
public static ReactiveElasticsearchClient createReactive(RestClient restClient, public static ReactiveElasticsearchClient createReactive(RestClient restClient,
@Nullable TransportOptions transportOptions, JsonpMapper jsonpMapper) { @Nullable TransportOptions transportOptions, JsonpMapper jsonpMapper) {
@ -147,21 +139,6 @@ public final class ElasticsearchClients {
var transport = getElasticsearchTransport(restClient, REACTIVE_CLIENT, transportOptions, jsonpMapper); var transport = getElasticsearchTransport(restClient, REACTIVE_CLIENT, transportOptions, jsonpMapper);
return createReactive(transport); return createReactive(transport);
} }
/**
* Creates a new {@link ReactiveElasticsearchClient}.
*
* @param rest5Client the underlying {@link RestClient}
* @param transportOptions options to be added to each request.
* @return the {@link ReactiveElasticsearchClient}
*/
public static ReactiveElasticsearchClient createReactive(Rest5Client rest5Client,
@Nullable TransportOptions transportOptions, JsonpMapper jsonpMapper) {
Assert.notNull(rest5Client, "restClient must not be null");
var transport = getElasticsearchTransport(rest5Client, REACTIVE_CLIENT, transportOptions, jsonpMapper);
return createReactive(transport);
}
/** /**
* Creates a new {@link ReactiveElasticsearchClient} that uses the given {@link ElasticsearchTransport}. * Creates a new {@link ReactiveElasticsearchClient} that uses the given {@link ElasticsearchTransport}.
@ -179,21 +156,17 @@ public final class ElasticsearchClients {
// region imperative client // region imperative client
/** /**
* Creates a new imperative {@link ElasticsearchClient}. This uses a RestClient, if the old RestClient is needed, this * Creates a new imperative {@link ElasticsearchClient}
* must be created with the {@link org.springframework.data.elasticsearch.client.elc.rest_client.RestClients} class
* and passed in as parameter.
* *
* @param clientConfiguration configuration options, must not be {@literal null}. * @param clientConfiguration configuration options, must not be {@literal null}.
* @return the {@link ElasticsearchClient} * @return the {@link ElasticsearchClient}
*/ */
public static ElasticsearchClient createImperative(ClientConfiguration clientConfiguration) { public static ElasticsearchClient createImperative(ClientConfiguration clientConfiguration) {
return createImperative(getRest5Client(clientConfiguration), null, DEFAULT_JSONP_MAPPER); return createImperative(getRestClient(clientConfiguration), null, DEFAULT_JSONP_MAPPER);
} }
/** /**
* Creates a new imperative {@link ElasticsearchClient}. This uses a RestClient, if the old RestClient is needed, this * Creates a new imperative {@link ElasticsearchClient}
* must be created with the {@link org.springframework.data.elasticsearch.client.elc.rest_client.RestClients} class
* and passed in as parameter.
* *
* @param clientConfiguration configuration options, must not be {@literal null}. * @param clientConfiguration configuration options, must not be {@literal null}.
* @param transportOptions options to be added to each request. * @param transportOptions options to be added to each request.
@ -201,7 +174,7 @@ public final class ElasticsearchClients {
*/ */
public static ElasticsearchClient createImperative(ClientConfiguration clientConfiguration, public static ElasticsearchClient createImperative(ClientConfiguration clientConfiguration,
TransportOptions transportOptions) { TransportOptions transportOptions) {
return createImperative(getRest5Client(clientConfiguration), transportOptions, DEFAULT_JSONP_MAPPER); return createImperative(getRestClient(clientConfiguration), transportOptions, DEFAULT_JSONP_MAPPER);
} }
/** /**
@ -209,23 +182,11 @@ public final class ElasticsearchClients {
* *
* @param restClient the RestClient to use * @param restClient the RestClient to use
* @return the {@link ElasticsearchClient} * @return the {@link ElasticsearchClient}
* @deprecated since 6.0, use the version with a Rest5Client.
*/ */
@Deprecated(since = "6.0", forRemoval = true)
public static ElasticsearchClient createImperative(RestClient restClient) { public static ElasticsearchClient createImperative(RestClient restClient) {
return createImperative(restClient, null, DEFAULT_JSONP_MAPPER); return createImperative(restClient, null, DEFAULT_JSONP_MAPPER);
} }
/**
* Creates a new imperative {@link ElasticsearchClient}
*
* @param rest5Client the Rest5Client to use
* @return the {@link ElasticsearchClient}
*/
public static ElasticsearchClient createImperative(Rest5Client rest5Client) {
return createImperative(rest5Client, null, DEFAULT_JSONP_MAPPER);
}
/** /**
* Creates a new imperative {@link ElasticsearchClient} * Creates a new imperative {@link ElasticsearchClient}
* *
@ -233,9 +194,7 @@ public final class ElasticsearchClients {
* @param transportOptions options to be added to each request. * @param transportOptions options to be added to each request.
* @param jsonpMapper the mapper for the transport to use * @param jsonpMapper the mapper for the transport to use
* @return the {@link ElasticsearchClient} * @return the {@link ElasticsearchClient}
* @deprecated since 6.0, use the version with a Rest5Client.
*/ */
@Deprecated(since = "6.0", forRemoval = true)
public static ElasticsearchClient createImperative(RestClient restClient, @Nullable TransportOptions transportOptions, public static ElasticsearchClient createImperative(RestClient restClient, @Nullable TransportOptions transportOptions,
JsonpMapper jsonpMapper) { JsonpMapper jsonpMapper) {
@ -247,27 +206,6 @@ public final class ElasticsearchClients {
return createImperative(transport); return createImperative(transport);
} }
/**
* Creates a new imperative {@link ElasticsearchClient}
*
* @param rest5Client the Rest5Client to use
* @param transportOptions options to be added to each request.
* @param jsonpMapper the mapper for the transport to use
* @return the {@link ElasticsearchClient}
* @since 6.0
*/
public static ElasticsearchClient createImperative(Rest5Client rest5Client,
@Nullable TransportOptions transportOptions,
JsonpMapper jsonpMapper) {
Assert.notNull(rest5Client, "restClient must not be null");
ElasticsearchTransport transport = getElasticsearchTransport(rest5Client, IMPERATIVE_CLIENT, transportOptions,
jsonpMapper);
return createImperative(transport);
}
/** /**
* Creates a new {@link ElasticsearchClient} that uses the given {@link ElasticsearchTransport}. * Creates a new {@link ElasticsearchClient} that uses the given {@link ElasticsearchTransport}.
* *
@ -282,6 +220,96 @@ public final class ElasticsearchClients {
} }
// endregion // endregion
// region low level RestClient
private static RestClientOptions.Builder getRestClientOptionsBuilder(@Nullable TransportOptions transportOptions) {
if (transportOptions instanceof RestClientOptions restClientOptions) {
return restClientOptions.toBuilder();
}
var builder = new RestClientOptions.Builder(RequestOptions.DEFAULT.toBuilder());
if (transportOptions != null) {
transportOptions.headers().forEach(header -> builder.addHeader(header.getKey(), header.getValue()));
transportOptions.queryParameters().forEach(builder::setParameter);
builder.onWarnings(transportOptions.onWarnings());
}
return builder;
}
/**
* Creates a low level {@link RestClient} for the given configuration.
*
* @param clientConfiguration must not be {@literal null}
* @return the {@link RestClient}
*/
public static RestClient getRestClient(ClientConfiguration clientConfiguration) {
return getRestClientBuilder(clientConfiguration).build();
}
private static RestClientBuilder getRestClientBuilder(ClientConfiguration clientConfiguration) {
HttpHost[] httpHosts = formattedHosts(clientConfiguration.getEndpoints(), clientConfiguration.useSsl()).stream()
.map(HttpHost::create).toArray(HttpHost[]::new);
RestClientBuilder builder = RestClient.builder(httpHosts);
if (clientConfiguration.getPathPrefix() != null) {
builder.setPathPrefix(clientConfiguration.getPathPrefix());
}
HttpHeaders headers = clientConfiguration.getDefaultHeaders();
if (!headers.isEmpty()) {
builder.setDefaultHeaders(toHeaderArray(headers));
}
builder.setHttpClientConfigCallback(clientBuilder -> {
if (clientConfiguration.getCaFingerprint().isPresent()) {
clientBuilder
.setSSLContext(TransportUtils.sslContextFromCaFingerprint(clientConfiguration.getCaFingerprint().get()));
}
clientConfiguration.getSslContext().ifPresent(clientBuilder::setSSLContext);
clientConfiguration.getHostNameVerifier().ifPresent(clientBuilder::setSSLHostnameVerifier);
clientBuilder.addInterceptorLast(new CustomHeaderInjector(clientConfiguration.getHeadersSupplier()));
RequestConfig.Builder requestConfigBuilder = RequestConfig.custom();
Duration connectTimeout = clientConfiguration.getConnectTimeout();
if (!connectTimeout.isNegative()) {
requestConfigBuilder.setConnectTimeout(Math.toIntExact(connectTimeout.toMillis()));
}
Duration socketTimeout = clientConfiguration.getSocketTimeout();
if (!socketTimeout.isNegative()) {
requestConfigBuilder.setSocketTimeout(Math.toIntExact(socketTimeout.toMillis()));
requestConfigBuilder.setConnectionRequestTimeout(Math.toIntExact(socketTimeout.toMillis()));
}
clientBuilder.setDefaultRequestConfig(requestConfigBuilder.build());
clientConfiguration.getProxy().map(HttpHost::create).ifPresent(clientBuilder::setProxy);
for (ClientConfiguration.ClientConfigurationCallback<?> clientConfigurer : clientConfiguration
.getClientConfigurers()) {
if (clientConfigurer instanceof ElasticsearchHttpClientConfigurationCallback restClientConfigurationCallback) {
clientBuilder = restClientConfigurationCallback.configure(clientBuilder);
}
}
return clientBuilder;
});
for (ClientConfiguration.ClientConfigurationCallback<?> clientConfigurationCallback : clientConfiguration
.getClientConfigurers()) {
if (clientConfigurationCallback instanceof ElasticsearchRestClientConfigurationCallback configurationCallback) {
builder = configurationCallback.configure(builder);
}
}
return builder;
}
// endregion
// region Elasticsearch transport // region Elasticsearch transport
/** /**
* Creates an {@link ElasticsearchTransport} that will use the given client that additionally is customized with a * Creates an {@link ElasticsearchTransport} that will use the given client that additionally is customized with a
@ -292,9 +320,7 @@ public final class ElasticsearchClients {
* @param transportOptions options for the transport * @param transportOptions options for the transport
* @param jsonpMapper mapper for the transport * @param jsonpMapper mapper for the transport
* @return ElasticsearchTransport * @return ElasticsearchTransport
* @deprecated since 6.0, use the version taking a Rest5Client
*/ */
@Deprecated(since = "6.0", forRemoval = true)
public static ElasticsearchTransport getElasticsearchTransport(RestClient restClient, String clientType, public static ElasticsearchTransport getElasticsearchTransport(RestClient restClient, String clientType,
@Nullable TransportOptions transportOptions, JsonpMapper jsonpMapper) { @Nullable TransportOptions transportOptions, JsonpMapper jsonpMapper) {
@ -303,7 +329,7 @@ public final class ElasticsearchClients {
Assert.notNull(jsonpMapper, "jsonpMapper must not be null"); Assert.notNull(jsonpMapper, "jsonpMapper must not be null");
TransportOptions.Builder transportOptionsBuilder = transportOptions != null ? transportOptions.toBuilder() TransportOptions.Builder transportOptionsBuilder = transportOptions != null ? transportOptions.toBuilder()
: new RestClientOptions(org.elasticsearch.client.RequestOptions.DEFAULT, false).toBuilder(); : new RestClientOptions(RequestOptions.DEFAULT).toBuilder();
RestClientOptions.Builder restClientOptionsBuilder = getRestClientOptionsBuilder(transportOptions); RestClientOptions.Builder restClientOptionsBuilder = getRestClientOptionsBuilder(transportOptions);
@ -327,35 +353,70 @@ public final class ElasticsearchClients {
return new RestClientTransport(restClient, jsonpMapper, restClientOptionsBuilder.build()); return new RestClientTransport(restClient, jsonpMapper, restClientOptionsBuilder.build());
} }
/**
* Creates an {@link ElasticsearchTransport} that will use the given client that additionally is customized with a
* header to contain the clientType
*
* @param rest5Client the client to use
* @param clientType the client type to pass in each request as header
* @param transportOptions options for the transport
* @param jsonpMapper mapper for the transport
* @return ElasticsearchTransport
*/
public static ElasticsearchTransport getElasticsearchTransport(Rest5Client rest5Client, String clientType,
@Nullable TransportOptions transportOptions, JsonpMapper jsonpMapper) {
Assert.notNull(rest5Client, "restClient must not be null");
Assert.notNull(clientType, "clientType must not be null");
Assert.notNull(jsonpMapper, "jsonpMapper must not be null");
TransportOptions.Builder transportOptionsBuilder = transportOptions != null ? transportOptions.toBuilder()
: new Rest5ClientOptions(RequestOptions.DEFAULT, false).toBuilder();
Rest5ClientOptions.Builder rest5ClientOptionsBuilder = getRest5ClientOptionsBuilder(transportOptions);
rest5ClientOptionsBuilder.addHeader(X_SPRING_DATA_ELASTICSEARCH_CLIENT,
VersionInfo.clientVersions() + " / " + clientType);
return new Rest5ClientTransport(rest5Client, jsonpMapper, rest5ClientOptionsBuilder.build());
}
// endregion // endregion
// todo #3117 remove and document that ElasticsearchHttpClientConfigurationCallback has been move to RestClients. private static List<String> formattedHosts(List<InetSocketAddress> hosts, boolean useSsl) {
return hosts.stream().map(it -> (useSsl ? "https" : "http") + "://" + it.getHostString() + ':' + it.getPort())
.collect(Collectors.toList());
}
private static org.apache.http.Header[] toHeaderArray(HttpHeaders headers) {
return headers.entrySet().stream() //
.flatMap(entry -> entry.getValue().stream() //
.map(value -> new BasicHeader(entry.getKey(), value))) //
.toArray(org.apache.http.Header[]::new);
}
/**
* Interceptor to inject custom supplied headers.
*
* @since 4.4
*/
private record CustomHeaderInjector(Supplier<HttpHeaders> headersSupplier) implements HttpRequestInterceptor {
@Override
public void process(HttpRequest request, HttpContext context) {
HttpHeaders httpHeaders = headersSupplier.get();
if (httpHeaders != null && !httpHeaders.isEmpty()) {
Arrays.stream(toHeaderArray(httpHeaders)).forEach(request::addHeader);
}
}
}
/**
* {@link org.springframework.data.elasticsearch.client.ClientConfiguration.ClientConfigurationCallback} to configure
* the Elasticsearch RestClient's Http client with a {@link HttpAsyncClientBuilder}
*
* @since 4.4
*/
public interface ElasticsearchHttpClientConfigurationCallback
extends ClientConfiguration.ClientConfigurationCallback<HttpAsyncClientBuilder> {
static ElasticsearchHttpClientConfigurationCallback from(
Function<HttpAsyncClientBuilder, HttpAsyncClientBuilder> httpClientBuilderCallback) {
Assert.notNull(httpClientBuilderCallback, "httpClientBuilderCallback must not be null");
return httpClientBuilderCallback::apply;
}
}
/**
* {@link org.springframework.data.elasticsearch.client.ClientConfiguration.ClientConfigurationCallback} to configure
* the RestClient client with a {@link RestClientBuilder}
*
* @since 5.0
*/
public interface ElasticsearchRestClientConfigurationCallback
extends ClientConfiguration.ClientConfigurationCallback<RestClientBuilder> {
static ElasticsearchRestClientConfigurationCallback from(
Function<RestClientBuilder, RestClientBuilder> restClientBuilderCallback) {
Assert.notNull(restClientBuilderCallback, "restClientBuilderCallback must not be null");
return restClientBuilderCallback::apply;
}
}
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2021-2025 the original author or authors. * Copyright 2021-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -20,13 +20,12 @@ import co.elastic.clients.json.JsonpMapper;
import co.elastic.clients.json.jackson.JacksonJsonpMapper; import co.elastic.clients.json.jackson.JacksonJsonpMapper;
import co.elastic.clients.transport.ElasticsearchTransport; import co.elastic.clients.transport.ElasticsearchTransport;
import co.elastic.clients.transport.TransportOptions; import co.elastic.clients.transport.TransportOptions;
import co.elastic.clients.transport.rest5_client.Rest5ClientOptions; import co.elastic.clients.transport.rest_client.RestClientOptions;
import co.elastic.clients.transport.rest5_client.low_level.RequestOptions;
import co.elastic.clients.transport.rest5_client.low_level.Rest5Client;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.data.elasticsearch.client.ClientConfiguration; import org.springframework.data.elasticsearch.client.ClientConfiguration;
import org.springframework.data.elasticsearch.client.elc.rest5_client.Rest5Clients;
import org.springframework.data.elasticsearch.config.ElasticsearchConfigurationSupport; import org.springframework.data.elasticsearch.config.ElasticsearchConfigurationSupport;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations; import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter; import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
@ -39,9 +38,7 @@ import com.fasterxml.jackson.databind.SerializationFeature;
/** /**
* Base class for a @{@link org.springframework.context.annotation.Configuration} class to set up the Elasticsearch * Base class for a @{@link org.springframework.context.annotation.Configuration} class to set up the Elasticsearch
* connection using the Elasticsearch Client. This class exposes different parts of the setup as Spring beans. Deriving * connection using the Elasticsearch Client. This class exposes different parts of the setup as Spring beans. Deriving
* classes must provide the {@link ClientConfiguration} to use. From Version 6.0 on, this class uses the new Rest5Client * classes must provide the {@link ClientConfiguration} to use.
* from Elasticsearch 9. The old implementation using the RestClient is still available under the name
* {@link ElasticsearchLegacyRestClientConfiguration}.
* *
* @author Peter-Josef Meisch * @author Peter-Josef Meisch
* @since 4.4 * @since 4.4
@ -63,27 +60,27 @@ public abstract class ElasticsearchConfiguration extends ElasticsearchConfigurat
* @return RestClient * @return RestClient
*/ */
@Bean @Bean
public Rest5Client elasticsearchRest5Client(ClientConfiguration clientConfiguration) { public RestClient elasticsearchRestClient(ClientConfiguration clientConfiguration) {
Assert.notNull(clientConfiguration, "clientConfiguration must not be null"); Assert.notNull(clientConfiguration, "clientConfiguration must not be null");
return Rest5Clients.getRest5Client(clientConfiguration); return ElasticsearchClients.getRestClient(clientConfiguration);
} }
/** /**
* Provides the Elasticsearch transport to be used. The default implementation uses the {@link Rest5Client} bean and * Provides the Elasticsearch transport to be used. The default implementation uses the {@link RestClient} bean and
* the {@link JsonpMapper} bean provided in this class. * the {@link JsonpMapper} bean provided in this class.
* *
* @return the {@link ElasticsearchTransport} * @return the {@link ElasticsearchTransport}
* @since 5.2 * @since 5.2
*/ */
@Bean @Bean
public ElasticsearchTransport elasticsearchTransport(Rest5Client rest5Client, JsonpMapper jsonpMapper) { public ElasticsearchTransport elasticsearchTransport(RestClient restClient, JsonpMapper jsonpMapper) {
Assert.notNull(rest5Client, "restClient must not be null"); Assert.notNull(restClient, "restClient must not be null");
Assert.notNull(jsonpMapper, "jsonpMapper must not be null"); Assert.notNull(jsonpMapper, "jsonpMapper must not be null");
return ElasticsearchClients.getElasticsearchTransport(rest5Client, ElasticsearchClients.IMPERATIVE_CLIENT, return ElasticsearchClients.getElasticsearchTransport(restClient, ElasticsearchClients.IMPERATIVE_CLIENT,
transportOptions(), jsonpMapper); transportOptions(), jsonpMapper);
} }
@ -118,7 +115,7 @@ public abstract class ElasticsearchConfiguration extends ElasticsearchConfigurat
} }
/** /**
* Provides the JsonpMapper bean that is used in the {@link #elasticsearchTransport(Rest5Client, JsonpMapper)} method. * Provides the JsonpMapper bean that is used in the {@link #elasticsearchTransport(RestClient, JsonpMapper)} method.
* *
* @return the {@link JsonpMapper} to use * @return the {@link JsonpMapper} to use
* @since 5.2 * @since 5.2
@ -138,6 +135,6 @@ public abstract class ElasticsearchConfiguration extends ElasticsearchConfigurat
* @return the options that should be added to every request. Must not be {@literal null} * @return the options that should be added to every request. Must not be {@literal null}
*/ */
public TransportOptions transportOptions() { public TransportOptions transportOptions() {
return new Rest5ClientOptions(RequestOptions.DEFAULT, false); return new RestClientOptions(RequestOptions.DEFAULT);
} }
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2021-2025 the original author or authors. * Copyright 2021-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -119,19 +119,14 @@ public class ElasticsearchExceptionTranslator implements PersistenceExceptionTra
String message = null; String message = null;
if (exception instanceof ResponseException responseException) { if (exception instanceof ResponseException responseException) {
// this code is for the old RestClient
status = responseException.getResponse().getStatusLine().getStatusCode(); status = responseException.getResponse().getStatusLine().getStatusCode();
message = responseException.getMessage(); message = responseException.getMessage();
} else if (exception instanceof ElasticsearchException elasticsearchException) {
// using the RestClient throws this
status = elasticsearchException.status();
message = elasticsearchException.getMessage();
} else if (exception.getCause() != null) { } else if (exception.getCause() != null) {
checkForConflictException(exception.getCause()); checkForConflictException(exception.getCause());
} }
if (status != null && message != null) { if (status != null && message != null) {
if (status == 409 && message.contains("version_conflict_engine_exception")) if (status == 409 && message.contains("type\":\"version_conflict_engine_exception"))
if (message.contains("version conflict, required seqNo")) { if (message.contains("version conflict, required seqNo")) {
throw new OptimisticLockingFailureException("Cannot index a document due to seq_no+primary_term conflict", throw new OptimisticLockingFailureException("Cannot index a document due to seq_no+primary_term conflict",
exception); exception);

View File

@ -1,144 +0,0 @@
/*
* Copyright 2021-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.elasticsearch.client.elc;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.json.JsonpMapper;
import co.elastic.clients.json.jackson.JacksonJsonpMapper;
import co.elastic.clients.transport.ElasticsearchTransport;
import co.elastic.clients.transport.TransportOptions;
import co.elastic.clients.transport.rest_client.RestClientOptions;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.springframework.context.annotation.Bean;
import org.springframework.data.elasticsearch.client.ClientConfiguration;
import org.springframework.data.elasticsearch.client.elc.rest_client.RestClients;
import org.springframework.data.elasticsearch.config.ElasticsearchConfigurationSupport;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
import org.springframework.util.Assert;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
/**
* Base class for a @{@link org.springframework.context.annotation.Configuration} class to set up the Elasticsearch
* connection using the Elasticsearch Client. This class exposes different parts of the setup as Spring beans. Deriving
* classes must provide the {@link ClientConfiguration} to use. <br/>
* This class uses the Elasticsearch RestClient which was replaced by the Rest5Client in Elasticsearch 9. It is still
* available here but deprecated.
*
* @author Peter-Josef Meisch
* @since 4.4
* @deprecated since 6.0, use {@link ElasticsearchConfiguration}
*/
@Deprecated(since = "6.0", forRemoval=true)
public abstract class ElasticsearchLegacyRestClientConfiguration extends ElasticsearchConfigurationSupport {
/**
* Must be implemented by deriving classes to provide the {@link ClientConfiguration}.
*
* @return configuration, must not be {@literal null}
*/
@Bean(name = "elasticsearchClientConfiguration")
public abstract ClientConfiguration clientConfiguration();
/**
* Provides the underlying low level Elasticsearch RestClient.
*
* @param clientConfiguration configuration for the client, must not be {@literal null}
* @return RestClient
*/
@Bean
public RestClient elasticsearchRestClient(ClientConfiguration clientConfiguration) {
Assert.notNull(clientConfiguration, "clientConfiguration must not be null");
return RestClients.getRestClient(clientConfiguration);
}
/**
* Provides the Elasticsearch transport to be used. The default implementation uses the {@link RestClient} bean and
* the {@link JsonpMapper} bean provided in this class.
*
* @return the {@link ElasticsearchTransport}
* @since 5.2
*/
@Bean
public ElasticsearchTransport elasticsearchTransport(RestClient restClient, JsonpMapper jsonpMapper) {
Assert.notNull(restClient, "restClient must not be null");
Assert.notNull(jsonpMapper, "jsonpMapper must not be null");
return ElasticsearchClients.getElasticsearchTransport(restClient, ElasticsearchClients.IMPERATIVE_CLIENT,
transportOptions(), jsonpMapper);
}
/**
* Provides the {@link ElasticsearchClient} to be used.
*
* @param transport the {@link ElasticsearchTransport} to use
* @return ElasticsearchClient instance
*/
@Bean
public ElasticsearchClient elasticsearchClient(ElasticsearchTransport transport) {
Assert.notNull(transport, "transport must not be null");
return ElasticsearchClients.createImperative(transport);
}
/**
* Creates a {@link ElasticsearchOperations} implementation using an {@link ElasticsearchClient}.
*
* @return never {@literal null}.
*/
@Bean(name = { "elasticsearchOperations", "elasticsearchTemplate" })
public ElasticsearchOperations elasticsearchOperations(ElasticsearchConverter elasticsearchConverter,
ElasticsearchClient elasticsearchClient) {
ElasticsearchTemplate template = new ElasticsearchTemplate(elasticsearchClient, elasticsearchConverter);
template.setRefreshPolicy(refreshPolicy());
return template;
}
/**
* Provides the JsonpMapper bean that is used in the {@link #elasticsearchTransport(RestClient, JsonpMapper)} method.
*
* @return the {@link JsonpMapper} to use
* @since 5.2
*/
@Bean
public JsonpMapper jsonpMapper() {
// we need to create our own objectMapper that keeps null values in order to provide the storeNullValue
// functionality. The one Elasticsearch would provide removes the nulls. We remove unwanted nulls before they get
// into this mapper, so we can safely keep them here.
var objectMapper = (new ObjectMapper())
.configure(SerializationFeature.INDENT_OUTPUT, false)
.setSerializationInclusion(JsonInclude.Include.ALWAYS);
return new JacksonJsonpMapper(objectMapper);
}
/**
* @return the options that should be added to every request. Must not be {@literal null}
*/
public TransportOptions transportOptions() {
return new RestClientOptions(RequestOptions.DEFAULT, false);
}
}

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2021-2025 the original author or authors. * Copyright 2021-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -40,7 +40,6 @@ import java.util.stream.Collectors;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.jspecify.annotations.Nullable;
import org.springframework.data.elasticsearch.BulkFailureException; import org.springframework.data.elasticsearch.BulkFailureException;
import org.springframework.data.elasticsearch.client.UnsupportedBackendOperation; import org.springframework.data.elasticsearch.client.UnsupportedBackendOperation;
import org.springframework.data.elasticsearch.core.AbstractElasticsearchTemplate; import org.springframework.data.elasticsearch.core.AbstractElasticsearchTemplate;
@ -60,6 +59,7 @@ import org.springframework.data.elasticsearch.core.reindex.ReindexRequest;
import org.springframework.data.elasticsearch.core.reindex.ReindexResponse; import org.springframework.data.elasticsearch.core.reindex.ReindexResponse;
import org.springframework.data.elasticsearch.core.script.Script; import org.springframework.data.elasticsearch.core.script.Script;
import org.springframework.data.elasticsearch.core.sql.SqlResponse; import org.springframework.data.elasticsearch.core.sql.SqlResponse;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert; import org.springframework.util.Assert;
/** /**
@ -181,6 +181,19 @@ public class ElasticsearchTemplate extends AbstractElasticsearchTemplate {
return delete(query, clazz, getIndexCoordinatesFor(clazz)); return delete(query, clazz, getIndexCoordinatesFor(clazz));
} }
@Override
public ByQueryResponse delete(Query query, Class<?> clazz, IndexCoordinates index) {
Assert.notNull(query, "query must not be null");
DeleteByQueryRequest request = requestConverter.documentDeleteByQueryRequest(query, routingResolver.getRouting(),
clazz, index, getRefreshPolicy());
DeleteByQueryResponse response = execute(client -> client.deleteByQuery(request));
return responseConverter.byQueryResponse(response);
}
@Override @Override
public ByQueryResponse delete(DeleteQuery query, Class<?> clazz, IndexCoordinates index) { public ByQueryResponse delete(DeleteQuery query, Class<?> clazz, IndexCoordinates index) {
Assert.notNull(query, "query must not be null"); Assert.notNull(query, "query must not be null");

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2021-2025 the original author or authors. * Copyright 2021-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2022-2025 the original author or authors. * Copyright 2022-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -20,7 +20,6 @@ import static org.springframework.data.elasticsearch.client.elc.TypeUtils.*;
import java.util.Arrays; import java.util.Arrays;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.jspecify.annotations.Nullable;
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity; import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity;
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty; import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty;
import org.springframework.data.elasticsearch.core.query.highlight.Highlight; import org.springframework.data.elasticsearch.core.query.highlight.Highlight;
@ -28,6 +27,7 @@ import org.springframework.data.elasticsearch.core.query.highlight.HighlightFiel
import org.springframework.data.elasticsearch.core.query.highlight.HighlightFieldParameters; import org.springframework.data.elasticsearch.core.query.highlight.HighlightFieldParameters;
import org.springframework.data.elasticsearch.core.query.highlight.HighlightParameters; import org.springframework.data.elasticsearch.core.query.highlight.HighlightParameters;
import org.springframework.data.mapping.context.MappingContext; import org.springframework.data.mapping.context.MappingContext;
import org.springframework.lang.Nullable;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
/** /**
@ -43,8 +43,7 @@ class HighlightQueryBuilder {
private final RequestConverter requestConverter; private final RequestConverter requestConverter;
HighlightQueryBuilder( HighlightQueryBuilder(
MappingContext<? extends ElasticsearchPersistentEntity<?>, ElasticsearchPersistentProperty> mappingContext, MappingContext<? extends ElasticsearchPersistentEntity<?>, ElasticsearchPersistentProperty> mappingContext, RequestConverter requestConverter) {
RequestConverter requestConverter) {
this.mappingContext = mappingContext; this.mappingContext = mappingContext;
this.requestConverter = requestConverter; this.requestConverter = requestConverter;
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2021-2025 the original author or authors. * Copyright 2021-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -27,7 +27,6 @@ import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.Set;
import org.jspecify.annotations.Nullable;
import org.springframework.core.annotation.AnnotatedElementUtils; import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.elasticsearch.UncategorizedElasticsearchException; import org.springframework.data.elasticsearch.UncategorizedElasticsearchException;
@ -50,6 +49,7 @@ import org.springframework.data.elasticsearch.core.mapping.Alias;
import org.springframework.data.elasticsearch.core.mapping.CreateIndexSettings; import org.springframework.data.elasticsearch.core.mapping.CreateIndexSettings;
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity; import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates; import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert; import org.springframework.util.Assert;
/** /**

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2021-2025 the original author or authors. * Copyright 2021-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -23,7 +23,7 @@ import java.nio.charset.StandardCharsets;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.jspecify.annotations.Nullable; import org.springframework.lang.Nullable;
/** /**
* @author Peter-Josef Meisch * @author Peter-Josef Meisch
@ -48,7 +48,7 @@ final class JsonUtils {
} }
@Nullable @Nullable
public static String queryToJson(co.elastic.clients.elasticsearch._types.query_dsl.@Nullable Query query, public static String queryToJson(@Nullable co.elastic.clients.elasticsearch._types.query_dsl.Query query,
JsonpMapper mapper) { JsonpMapper mapper) {
if (query == null) { if (query == null) {

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2021-2025 the original author or authors. * Copyright 2021-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -28,8 +28,8 @@ import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.jspecify.annotations.Nullable;
import org.springframework.data.elasticsearch.core.query.BaseQuery; import org.springframework.data.elasticsearch.core.query.BaseQuery;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert; import org.springframework.util.Assert;
/** /**
@ -44,7 +44,7 @@ import org.springframework.util.Assert;
public class NativeQuery extends BaseQuery { public class NativeQuery extends BaseQuery {
@Nullable private final Query query; @Nullable private final Query query;
private org.springframework.data.elasticsearch.core.query.@Nullable Query springDataQuery; @Nullable private org.springframework.data.elasticsearch.core.query.Query springDataQuery;
@Nullable private Query filter; @Nullable private Query filter;
// note: the new client does not have pipeline aggs, these are just set up as normal aggs // note: the new client does not have pipeline aggs, these are just set up as normal aggs
private final Map<String, Aggregation> aggregations = new LinkedHashMap<>(); private final Map<String, Aggregation> aggregations = new LinkedHashMap<>();
@ -117,7 +117,7 @@ public class NativeQuery extends BaseQuery {
* @see NativeQueryBuilder#withQuery(org.springframework.data.elasticsearch.core.query.Query). * @see NativeQueryBuilder#withQuery(org.springframework.data.elasticsearch.core.query.Query).
* @since 5.1 * @since 5.1
*/ */
public void setSpringDataQuery(org.springframework.data.elasticsearch.core.query.@Nullable Query springDataQuery) { public void setSpringDataQuery(@Nullable org.springframework.data.elasticsearch.core.query.Query springDataQuery) {
this.springDataQuery = springDataQuery; this.springDataQuery = springDataQuery;
} }
@ -129,7 +129,8 @@ public class NativeQuery extends BaseQuery {
return knnSearches; return knnSearches;
} }
public org.springframework.data.elasticsearch.core.query.@Nullable Query getSpringDataQuery() { @Nullable
public org.springframework.data.elasticsearch.core.query.Query getSpringDataQuery() {
return springDataQuery; return springDataQuery;
} }
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2022-2025 the original author or authors. * Copyright 2022-2024 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -33,8 +33,8 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.Function; import java.util.function.Function;
import org.jspecify.annotations.Nullable;
import org.springframework.data.elasticsearch.core.query.BaseQueryBuilder; import org.springframework.data.elasticsearch.core.query.BaseQueryBuilder;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert; import org.springframework.util.Assert;
/** /**
@ -53,7 +53,7 @@ public class NativeQueryBuilder extends BaseQueryBuilder<NativeQuery, NativeQuer
private final List<SortOptions> sortOptions = new ArrayList<>(); private final List<SortOptions> sortOptions = new ArrayList<>();
private final Map<String, JsonData> searchExtensions = new LinkedHashMap<>(); private final Map<String, JsonData> searchExtensions = new LinkedHashMap<>();
private org.springframework.data.elasticsearch.core.query.@Nullable Query springDataQuery; @Nullable private org.springframework.data.elasticsearch.core.query.Query springDataQuery;
@Nullable private KnnQuery knnQuery; @Nullable private KnnQuery knnQuery;
@Nullable private List<KnnSearch> knnSearches = Collections.emptyList(); @Nullable private List<KnnSearch> knnSearches = Collections.emptyList();
@ -104,7 +104,8 @@ public class NativeQueryBuilder extends BaseQueryBuilder<NativeQuery, NativeQuer
return knnSearches; return knnSearches;
} }
public org.springframework.data.elasticsearch.core.query.@Nullable Query getSpringDataQuery() { @Nullable
public org.springframework.data.elasticsearch.core.query.Query getSpringDataQuery() {
return springDataQuery; return springDataQuery;
} }

Some files were not shown because too many files have changed in this diff Show More