1
0
mirror of synced 2026-05-22 20:23:18 +00:00

Compare commits

...

100 Commits

Author SHA1 Message Date
Christoph Strobl 53ac53d146 Release version 6.0.2 (2025.1.2).
See #3214
2026-01-16 10:36:18 +01:00
Christoph Strobl 6c656dff17 Prepare 6.0.2 (2025.1.2).
See #3214
2026-01-16 10:35:37 +01:00
Mark Paluch cfa303c6a3 Add Readme templates.
See spring-projects/spring-data-build#2758
2026-01-12 15:27:26 +01:00
Mark Paluch 353c463aa8 Extend license header copyright years to present.
See #3221
2026-01-05 08:45:42 +01:00
Peter-Josef Meisch cb67bfb534 Upgrade to Elasticsearch 9.2.3.
Closes #3217

Signed-off-by: Peter-Josef Meisch <pj.meisch@sothawo.com>
2025-12-24 16:21:03 +01:00
Mark Paluch 49cce254ce After release cleanups.
See #3197
2025-12-12 12:22:56 +01:00
Mark Paluch 597409c4c2 Prepare next development iteration.
See #3197
2025-12-12 12:22:55 +01:00
Mark Paluch 66144d10f8 Release version 6.0.1 (2025.1.1).
See #3197
2025-12-12 12:20:35 +01:00
Mark Paluch e6aefc8180 Prepare 6.0.1 (2025.1.1).
See #3197
2025-12-12 12:20:16 +01:00
Mark Paluch a7bd311106 Polishing.
Simplify test dependency setup, remove no longer required servlet/xbean dependencies, exclude commons-lang3 in favor of the Testcontainers variant. Remove outdated commons-codec dependency in favor of the Testcontainers variant.

See #3212
2025-12-11 09:02:48 +01:00
Mark Paluch 003d75f022 Add @ContextConfiguration(…) to test classes that use @SpringIntegrationTest on super classes.
Closes #3212
2025-12-11 09:02:48 +01:00
Mark Paluch 535b407085 Update CI Properties.
See #3197
2025-12-10 08:35:04 +01:00
Peter-Josef Meisch 44919d4cbe Upgrade Elasticsearch to 9.2.2.
Close #3208

Signed-off-by: Peter-Josef Meisch <pj.meisch@sothawo.com>
2025-12-05 00:01:14 +01:00
Peter-Josef Meisch 6260f278ba Fix UpdateQuery.Builder to allow only a scriptname to be set.
Signed-off-by: Peter-Josef Meisch <pj.meisch@sothawo.com>
(cherry picked from commit 69746441e1)
2025-12-04 23:25:34 +01:00
Peter-Josef Meisch b3bd77aa46 Adjust aot hints for Elasticsearch 9 client.
The hints for the old httpclient are only needed when the old library is on the classpath, in case a user still uses the old RestClient. For the new Elasticsearch client there are no aot hints required.

Closes: #3203

Signed-off-by: Peter-Josef Meisch <pj.meisch@sothawo.com>
(cherry picked from commit e31b66768b)
2025-11-25 20:11:04 +01:00
Peter-Josef Meisch bea651bc95 Fix documentation.
Closes #3199

Signed-off-by: Peter-Josef Meisch <pj.meisch@sothawo.com>
(cherry picked from commit 5821a81db9)
2025-11-14 19:02:47 +01:00
Mark Paluch 175614cd94 After release cleanups.
See #3186
2025-11-14 13:56:30 +01:00
Mark Paluch c4c73709c8 Prepare next development iteration.
See #3186
2025-11-14 13:56:29 +01:00
Mark Paluch e4fb2908c0 Release version 6.0 GA (2025.1.0).
See #3186
2025-11-14 13:53:51 +01:00
Mark Paluch 97c2524db5 Prepare 6.0 GA (2025.1.0).
See #3186
2025-11-14 13:53:27 +01:00
Mark Paluch 6e3654866a Update Update security documentation.
See #3186
2025-11-14 10:43:37 +01:00
Mark Paluch 5c25ca922e Upgrade to Elasticsearch 9.2.1.
Closes #3194
2025-11-14 09:47:05 +01:00
Steven bc7cfdf6e9 Update clients.adoc to show how to log Request/Response for Rest5_Client (#3157)
* Update clients.adoc to show how to log Request/Response for Rest5_Client

Signed-off-by: Steven <steven.pearce@nowyoyo.com>

* Update clients.adoc to use tabs when available

---------

Signed-off-by: Steven <steven.pearce@nowyoyo.com>
2025-11-08 18:46:28 +01:00
Peter-Josef Meisch 6f0263b3af Update documentation.
Closes #3192

Signed-off-by: Peter-Josef Meisch <pj.meisch@sothawo.com>
2025-11-08 18:42:02 +01:00
Christoph Strobl bcbe4534c2 After release cleanups.
See #3189
2025-10-31 11:14:16 +01:00
Christoph Strobl c999465876 Prepare next development iteration.
See #3189
2025-10-31 11:14:15 +01:00
Christoph Strobl 5b87eeca69 Release version 6.0 RC2 (2025.1.0).
See #3189
2025-10-31 11:10:24 +01:00
Christoph Strobl 54b1983eef Prepare 6.0 RC2 (2025.1.0).
See #3189
2025-10-31 11:09:52 +01:00
Mark Paluch 68c9f04619 Move Commons PropertyPath and TypeInformation types to core package.
See spring-projects/spring-data-commons#3393
2025-10-30 11:27:35 +01:00
Mark Paluch 2c49dc75de Upgrade to Testcontainers 2.0.
See spring-projects/spring-data-build#2688
2025-10-28 11:07:05 +01:00
Peter-Josef Meisch 828f588f3e Upgrade to Elasticsearch 9.2.0
Original Pull Request #3191
Closes: #3190
Signed-off-by: Peter-Josef Meisch <pj.meisch@sothawo.com>
2025-10-27 18:16:34 +01:00
Peter-Josef Meisch 21bc62b78c Add SpEL support for settingPath in @Settings annotation.
Original Pull Request #3188
Closes #3187
Signed-off-by: Peter-Josef Meisch <pj.meisch@sothawo.com>
2025-10-26 18:25:56 +01:00
Christoph Strobl b552128198 After release cleanups.
See #3171
2025-10-17 12:41:12 +02:00
Christoph Strobl 18d582af6a Prepare next development iteration.
See #3171
2025-10-17 12:41:10 +02:00
Christoph Strobl fa3e7741f2 Release version 6.0 RC1 (2025.1.0).
See #3171
2025-10-17 12:36:47 +02:00
Christoph Strobl e9e6da239e Prepare 6.0 RC1 (2025.1.0).
See #3171
2025-10-17 12:35:34 +02:00
Peter-Josef Meisch 923d3b413d Upgrade to Elasticsearch 9.1.5.
Original Pull Request #3182
Closes #3180
Signed-off-by: Peter-Josef Meisch <pj.meisch@sothawo.com>
2025-10-17 00:03:18 +02:00
Mark Paluch 16f3addaf6 Remove accidental org.jetbrains:annotations usage.
See spring-projects/spring-data-build#2670
2025-10-10 09:25:17 +02:00
Peter-Josef Meisch 0e1a97a27a Fix string comparison in TypeUtils.
Original Pull Request #3177
Closes #3176
Signed-off-by: Peter-Josef Meisch <pj.meisch@sothawo.com>
2025-10-03 10:48:25 +02:00
Mark Paluch df79368299 Update CI Properties.
See #3171
2025-09-26 12:01:27 +02:00
Mark Paluch 11b3cd5b3e Update GitHub Actions.
See #3171
2025-09-23 10:52:08 +02:00
Peter-Josef Meisch e06aca9594 Upgrade to Elasticsearch 9.1.4
Original Pull Request #3174
Closes #3173

Signed-off-by: Peter-Josef Meisch <pj.meisch@sothawo.com>
2025-09-21 08:33:51 +02:00
Peter-Josef Meisch 5529af8f76 Adjust test to slower performance of build machines in Jenkins
Signed-off-by: Peter-Josef Meisch <pj.meisch@sothawo.com>
2025-09-20 20:14:59 +02:00
Peter-Josef Meisch c0dd082f4e Speedup Criteria hashcode calculation
Original Pull Request #3172
Closes #3083
Signed-off-by: Peter-Josef Meisch <pj.meisch@sothawo.com>
2025-09-20 19:49:38 +02:00
Christoph Strobl 9aa65560cc After release cleanups.
See #3154
2025-09-12 12:47:16 +02:00
Christoph Strobl 560d1e9153 Prepare next development iteration.
See #3154
2025-09-12 12:47:15 +02:00
Christoph Strobl 78cbad5093 Release version 6.0 M6 (2025.1.0).
See #3154
2025-09-12 12:43:45 +02:00
Christoph Strobl be3aee93fb Prepare 6.0 M6 (2025.1.0).
See #3154
2025-09-12 12:42:59 +02:00
Mark Paluch fb986e17f8 Polishing.
Update project metadata, add PJ as project lead (long overdue).

See #3154
2025-09-12 11:39:35 +02:00
Mark Paluch 3911b69869 Upgrade to elasticsearch-java 9.1.4.
Closes #3168
2025-09-12 11:37:29 +02:00
Mark Paluch b49fedaafc Adapt tests to MappingException cause when entity creation fails.
Closes #3167
2025-09-09 15:33:41 +02:00
Peter-Josef Meisch 087f3a80c5 Upgrade to Elasticsearch 9.1.3.
Original Pull Request #3165
Closes #3161

Signed-off-by: Peter-Josef Meisch <pj.meisch@sothawo.com>
2025-08-31 17:27:35 +02:00
Peter-Josef Meisch 46e997b81d Upgrade dependencies.
Original Pull Request #3163
Closes #3162

Signed-off-by: Peter-Josef Meisch <pj.meisch@sothawo.com>
2025-08-31 12:00:55 +02:00
Mark Paluch 1f5747294e Refine version properties for documentation build.
See spring-projects/spring-data-build#2638
2025-08-18 09:16:47 +02:00
Mark Paluch 92b6f28e31 After release cleanups.
See #3135
2025-08-15 10:47:30 +02:00
Mark Paluch 646f07c42b Prepare next development iteration.
See #3135
2025-08-15 10:47:29 +02:00
Mark Paluch 875ba54d33 Release version 6.0 M5 (2025.1.0).
See #3135
2025-08-15 10:45:11 +02:00
Mark Paluch 80b406ea22 Prepare 6.0 M5 (2025.1.0).
See #3135
2025-08-15 10:44:53 +02:00
Mark Paluch 9d987cbcc9 Polishing.
Use documentation variables for references, reorder antora keys.

See #3135
2025-08-14 17:27:50 +02:00
Peter-Josef Meisch 1505dd5129 Upgrade to Elasticsearch 9.1.1.
Original Pull Request #3150
Closes #3148
Signed-off-by: Peter-Josef Meisch <pj.meisch@sothawo.com>
2025-08-12 18:07:14 +02:00
Peter-Josef Meisch 6697755b45 Upgrade Elasticsearch to 9.1.0.
Original Pull Request #3147
Closes #3145
Signed-off-by: Peter-Josef Meisch <pj.meisch@sothawo.com>
2025-08-06 20:52:04 +02:00
Peter-Josef Meisch e49bb63df4 Fix handling of ResponseException from legacy client dependency.
Original Pull Request #3146
Closes #3144

Signed-off-by: Peter-Josef Meisch <pj.meisch@sothawo.com>
2025-08-04 20:50:47 +02:00
Peter-Josef Meisch 006cda6de6 Adjust Rest5Client building by using and exposing the callbacks provided by the Elasticsearch Java client library.
Original Pull Request #3143
Closes #3129

Signed-off-by: Peter-Josef Meisch <pj.meisch@sothawo.com>
2025-08-02 18:33:04 +02:00
Peter-Josef Meisch f51efa2cad Cleanup nullability issues
Original Pull Request #3142
Closes #3141
Signed-off-by: Peter-Josef Meisch <pj.meisch@sothawo.com>
2025-08-02 13:20:28 +02:00
Peter-Josef Meisch 6e30801a59 Upgrade to Elasticsearch 9.0.4
Original Pull Request #3140
Closes #3139

Signed-off-by: Peter-Josef Meisch <pj.meisch@sothawo.com>
2025-08-02 07:49:32 +02:00
Peter-Josef Meisch e64d0ada62 Polishing
Signed-off-by: Peter-Josef Meisch <pj.meisch@sothawo.com>
2025-07-22 18:36:04 +02:00
Anton 7f7cf3f52e Fixed PrimaryTerm/SeqNo datatypes in UpdateQuery.
Original Pull Request #3137
Closes #3136

Signed-off-by: Anton Buz <buzdalkin.a@vlprojects.pro>
2025-07-22 18:35:43 +02:00
Mark Paluch 55d470fc91 After release cleanups.
See #3115
2025-07-18 13:14:47 +02:00
Mark Paluch b7290b5d9c Prepare next development iteration.
See #3115
2025-07-18 13:14:46 +02:00
Mark Paluch 40414f0bde Release version 6.0 M4 (2025.1.0).
See #3115
2025-07-18 13:12:28 +02:00
Mark Paluch cb71caa504 Prepare 6.0 M4 (2025.1.0).
See #3115
2025-07-18 13:12:11 +02:00
Mark Paluch ed9abce7af Upgrade to Maven Wrapper 3.9.11.
See #3130
2025-07-17 13:59:56 +02:00
Peter-Josef Meisch 12ddb74fae Fix the calculation of the requested number of documents.
Original Pull Request #3128
Closes #3127

Signed-off-by: Peter-Josef Meisch <pj.meisch@sothawo.com>
2025-07-15 18:28:51 +02:00
Peter-Josef Meisch 6324b72707 Use the new Rest5Client as default, provide the old RestClient as optional.
Original Pull Request: #3125
Closes #3117

Signed-off-by: Peter-Josef Meisch <pj.meisch@sothawo.com>
2025-06-25 20:09:00 +02:00
Peter-Josef Meisch 6e49980c7c Upgrade to Elasticsearch 9.0.3.
Original Pull Request #3124
Closes #3123
Signed-off-by: Peter-Josef Meisch <pj.meisch@sothawo.com>
2025-06-25 17:24:08 +02:00
Peter-Josef Meisch f9509f2696 Upgrade to Elasticsearch 9.0.2.
Original Pull Request #3122
Closes #3121
Signed-off-by: Peter-Josef Meisch <pj.meisch@sothawo.com>
2025-06-14 17:30:22 +02:00
Mark Paluch 7f53944e1b Adapt to generics changes in CoroutineCrudRepository.
Closes #3118
2025-06-12 09:14:22 +02:00
Peter-Josef Meisch a9d2aaa93d Polishing.
Signed-off-by: Peter-Josef Meisch <pj.meisch@sothawo.com>
2025-05-29 18:10:48 +02:00
Laura Trotta 158f5fc342 es java client major update.
Original Pull Request #3116
Closes #3110
Signed-off-by: Laura Trotta <laura.trotta@elastic.co>
2025-05-29 15:56:35 +02:00
Peter-Josef Meisch 6268133506 Update versions documentation
Signed-off-by: Peter-Josef Meisch <pj.meisch@sothawo.com>
2025-05-24 14:58:04 +02:00
Mark Paluch 923787c2d1 After release cleanups.
See #3097
2025-05-16 14:18:48 +02:00
Mark Paluch 62fcbd44fa Prepare next development iteration.
See #3097
2025-05-16 14:18:47 +02:00
Mark Paluch 77ba620fc6 Release version 6.0 M3 (2025.1.0).
See #3097
2025-05-16 14:16:18 +02:00
Mark Paluch 06704d974d Prepare 6.0 M3 (2025.1.0).
See #3097
2025-05-16 14:15:56 +02:00
Mark Paluch 897cb0a957 Add optional Querydsl dependency.
Closes #3107
2025-05-16 12:18:51 +02:00
Mark Paluch a8557a36dc Update CI Properties.
See #3097
2025-05-16 12:18:51 +02:00
Mark Paluch 2678cdc7b6 After release cleanups.
See #3047
2025-05-16 12:18:51 +02:00
Mark Paluch eb42312ebe Prepare next development iteration.
See #3047
2025-05-16 12:18:51 +02:00
Mark Paluch af13fe0247 Release version 6.0 M2 (2025.1.0).
See #3047
2025-05-16 12:18:51 +02:00
Mark Paluch e81810c0d7 Prepare 6.0 M2 (2025.1.0).
See #3047
2025-05-16 12:18:51 +02:00
Peter-Josef Meisch e9c7c0ee95 Switch to jspecify nullability annotations.
Original Pull Request #3065
Closes #2984

Signed-off-by: Peter-Josef Meisch <pj.meisch@sothawo.com>
2025-05-16 12:18:50 +02:00
Peter-Josef Meisch 3a4425053e Cleanup unneeded imports after deprecation removal
Signed-off-by: Peter-Josef Meisch <pj.meisch@sothawo.com>
2025-05-16 12:18:50 +02:00
Christoph Strobl 09984f86e6 After release cleanups.
See #3006
2025-05-16 12:18:50 +02:00
Christoph Strobl 710526c5f6 Prepare next development iteration.
See #3006
2025-05-16 12:18:50 +02:00
Christoph Strobl 1acd392af7 Release version 6.0 M1 (2025.1.0).
See #3006
2025-05-16 12:18:50 +02:00
Christoph Strobl 76fe240a24 Prepare 6.0 M1 (2025.1.0).
See #3006
2025-05-16 12:18:50 +02:00
Mark Paluch e298bc9f7a Adopt to changes in Spring Framework 7.
See #3038
2025-05-16 12:18:50 +02:00
Peter-Josef Meisch 49d5dee5aa Update versions documentation
Signed-off-by: Peter-Josef Meisch <pj.meisch@sothawo.com>
2025-05-16 12:18:49 +02:00
Mark Paluch df6a127629 After release cleanups.
See #3096
2025-05-16 12:18:48 +02:00
Mark Paluch 08a1ef3a28 Prepare next development iteration.
See #3096
2025-05-16 11:31:15 +02:00
678 changed files with 4562 additions and 2432 deletions
+83
View File
@@ -0,0 +1,83 @@
= Spring Data for Elasticsearch image:https://jenkins.spring.io/buildStatus/icon?job=spring-data-elasticsearch%2Fmain&subject=Build[link=https://jenkins.spring.io/view/SpringData/job/spring-data-elasticsearch/] https://gitter.im/spring-projects/spring-data[image:https://badges.gitter.im/spring-projects/spring-data.svg[Gitter]] image:https://img.shields.io/badge/Revved%20up%20by-Develocity-06A0CE?logo=Gradle&labelColor=02303A["Revved up by Develocity", link="https://ge.spring.io/scans?search.rootProjectNames=Spring Data Elasticsearch"]
The primary goal of the https://projects.spring.io/spring-data[Spring Data] project is to make it easier to build Spring-powered applications that use new data access technologies such as non-relational databases, map-reduce frameworks, and cloud based data services.
The Spring Data Elasticsearch project provides integration with the https://www.elastic.co/[Elasticsearch] search engine.
Key functional areas of Spring Data Elasticsearch are a POJO centric model for interacting with Elasticsearch Documents and easily writing a Repository style data access layer.
This project is lead and maintained by the community.
== Features
* Spring configuration support using Java based `@Configuration` classes or an XML namespace for an ES client instances.
* `ElasticsearchOperations` class and implementations that increases productivity performing common ES operations.
Includes integrated object mapping between documents and POJOs.
* Feature Rich Object Mapping integrated with Springs Conversion Service
* Annotation based mapping metadata
* Automatic implementation of `Repository` interfaces including support for custom search methods.
* CDI support for repositories
include::https://raw.githubusercontent.com/spring-projects/spring-data-build/refs/heads/main/etc/readme/code-of-conduct.adoc[]
== Getting Started
Here is a quick teaser of an application using Spring Data Repositories in Java:
[source,java]
----
public interface PersonRepository extends CrudRepository<Person, Long> {
List<Person> findByLastname(String lastname);
List<Person> findByFirstnameLike(String firstname);
}
@Service
public class MyService {
private final PersonRepository repository;
public MyService(PersonRepository repository) {
this.repository = repository;
}
public void doWork() {
repository.deleteAll();
Person person = new Person();
person.setFirstname("Oliver");
person.setLastname("Gierke");
repository.save(person);
List<Person> lastNameResults = repository.findByLastname("Gierke");
List<Person> firstNameResults = repository.findByFirstnameLike("Oli");
}
}
----
=== Using the RestClient
Please check the https://docs.spring.io/spring-data/elasticsearch/docs/current/reference/html/#elasticsearch.clients.configuration[official documentation].
include::https://raw.githubusercontent.com/spring-projects/spring-data-build/refs/heads/main/etc/readme/dependencies.adoc[]
**Compatibility Matrix**
The compatibility between Spring Data Elasticsearch, Elasticsearch client drivers and Spring Boot versions can be found in the https://docs.spring.io/spring-data/elasticsearch/docs/current/reference/html/#preface.versions[reference documentation].
To use the Release candidate versions of the upcoming major version, use our Maven milestone repository and declare the appropriate dependency version:
[source,xml]
----
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-elasticsearch</artifactId>
<version>${version}.RCx</version> <!-- x being 1, 2, ... -->
</dependency>
----
include::https://raw.githubusercontent.com/spring-projects/spring-data-build/refs/heads/main/etc/readme/getting-help.adoc[]
include::https://raw.githubusercontent.com/spring-projects/spring-data-build/refs/heads/main/etc/readme/license.adoc[]
+21
View File
@@ -0,0 +1,21 @@
# GitHub Actions for CodeQL Scanning
name: "CodeQL Advanced"
on:
push:
pull_request:
workflow_dispatch:
schedule:
# https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#schedule
- cron: '0 5 * * *'
permissions: read-all
jobs:
codeql-analysis-call:
permissions:
actions: read
contents: read
security-events: write
uses: spring-io/github-actions/.github/workflows/codeql-analysis.yml@1
+45
View File
@@ -0,0 +1,45 @@
# GitHub Actions to automate GitHub issues for Spring Data Project Management
name: Spring Data GitHub Issues
on:
issues:
types: [opened, edited, reopened]
issue_comment:
types: [created]
pull_request_target:
types: [opened, edited, reopened]
permissions:
contents: read
issues: write
pull-requests: write
jobs:
Inbox:
runs-on: ubuntu-latest
if: github.repository_owner == 'spring-projects' && (github.event.action == 'opened' || github.event.action == 'reopened') && github.event.pull_request == null && !contains(join(github.event.issue.labels.*.name, ', '), 'dependency-upgrade') && !contains(github.event.issue.title, 'Release ')
steps:
- name: Create or Update Issue Card
uses: actions/add-to-project@v1.0.2
with:
project-url: https://github.com/orgs/spring-projects/projects/25
github-token: ${{ secrets.GH_ISSUES_TOKEN_SPRING_DATA }}
Pull-Request:
runs-on: ubuntu-latest
if: github.repository_owner == 'spring-projects' && (github.event.action == 'opened' || github.event.action == 'reopened') && github.event.pull_request != null
steps:
- name: Create or Update Pull Request Card
uses: actions/add-to-project@v1.0.2
with:
project-url: https://github.com/orgs/spring-projects/projects/25
github-token: ${{ secrets.GH_ISSUES_TOKEN_SPRING_DATA }}
Feedback-Provided:
runs-on: ubuntu-latest
if: github.repository_owner == 'spring-projects' && github.event_name == 'issue_comment' && github.event.action == 'created' && github.actor != 'spring-projects-issues' && github.event.pull_request == null && github.event.issue.state == 'open' && contains(toJSON(github.event.issue.labels), 'waiting-for-feedback')
steps:
- name: Update Project Card
uses: actions/add-to-project@v1.0.2
with:
project-url: https://github.com/orgs/spring-projects/projects/25
github-token: ${{ secrets.GH_ISSUES_TOKEN_SPRING_DATA }}
+2 -2
View File
@@ -1,3 +1,3 @@
#Thu Nov 07 09:47:28 CET 2024
#Thu Jul 17 13:59:56 CEST 2025
wrapperUrl=https\://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar
distributionUrl=https\://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.9/apache-maven-3.9.9-bin.zip
distributionUrl=https\://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.11/apache-maven-3.9.11-bin.zip
Vendored
+1 -1
View File
@@ -9,7 +9,7 @@ pipeline {
triggers {
pollSCM 'H/10 * * * *'
upstream(upstreamProjects: "spring-data-commons/main", threshold: hudson.model.Result.SUCCESS)
upstream(upstreamProjects: "spring-data-commons/4.0.x", threshold: hudson.model.Result.SUCCESS)
}
options {
+11 -5
View File
@@ -1,9 +1,15 @@
# Security Policy
= Security Policy
## Supported Versions
== Reporting a Vulnerability
Please see the https://spring.io/projects/spring-data-elasticsearch[Spring Data Elasticsearch] project page for supported versions.
Please, https://github.com/spring-projects/security-advisories/security/advisories/new[open a draft security advisory] if you need to disclose and discuss a security issue in private with the Spring Data team.
Note that we only accept reports against https://spring.io/projects/spring-data#support[supported versions].
## Reporting a Vulnerability
For more details, check out our https://spring.io/security-policy[security policy].
Please don't raise security vulnerabilities here. Head over to https://pivotal.io/security to learn how to disclose them responsibly.
== JAR signing
Spring Data JARs released on Maven Central are signed.
You'll find more information about the key here: https://spring.io/GPG-KEY-spring.txt
Versions released prior to 2023 may be signed with a different key.
+5 -4
View File
@@ -1,6 +1,6 @@
# Java versions
java.main.tag=17.0.15_6-jdk-focal
java.next.tag=24.0.1_9-jdk-noble
java.main.tag=25-jdk-noble
java.next.tag=25-jdk-noble
# Docker container images - standard
docker.java.main.image=library/eclipse-temurin:${java.main.tag}
@@ -14,11 +14,12 @@ docker.mongodb.8.0.version=8.0.9
# Supported versions of Redis
docker.redis.6.version=6.2.13
docker.redis.7.version=7.2.4
docker.redis.8.version=8.2.2
docker.valkey.8.version=8.1.1
# Docker environment settings
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.basic=-v $HOME:/tmp/jenkins-home --ulimit nofile=32000:32000
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 --ulimit nofile=32000:32000
# Credentials
docker.registry=
+58 -40
View File
@@ -1,16 +1,16 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-elasticsearch</artifactId>
<version>5.5.0</version>
<version>6.0.2</version>
<parent>
<groupId>org.springframework.data.build</groupId>
<artifactId>spring-data-parent</artifactId>
<version>3.5.0</version>
<version>4.0.2</version>
</parent>
<name>Spring Data Elasticsearch</name>
@@ -18,16 +18,16 @@
<url>https://github.com/spring-projects/spring-data-elasticsearch</url>
<properties>
<springdata.commons>3.5.0</springdata.commons>
<springdata.commons>4.0.2</springdata.commons>
<!-- version of the ElasticsearchClient -->
<elasticsearch-java>8.18.1</elasticsearch-java>
<elasticsearch-java>9.2.3</elasticsearch-java>
<elasticsearch-rest-client>9.2.3</elasticsearch-rest-client>
<hoverfly>0.19.0</hoverfly>
<log4j>2.23.1</log4j>
<hoverfly>0.20.2</hoverfly>
<log4j>2.25.1</log4j>
<jsonassert>1.5.3</jsonassert>
<testcontainers>1.20.0</testcontainers>
<wiremock>3.9.1</wiremock>
<wiremock>3.9.2</wiremock>
<java-module-name>spring.data.elasticsearch</java-module-name>
@@ -41,6 +41,15 @@
</properties>
<developers>
<developer>
<id>sothawo</id>
<name>Peter-Josef Meisch</name>
<email>pj.meisch at sothawo.com</email>
<roles>
<role>Project Lead</role>
</roles>
<timezone>+1</timezone>
</developer>
<developer>
<id>biomedcentral</id>
<name>BioMed Central Development Team</name>
@@ -77,16 +86,32 @@
</developerConnection>
</scm>
<ciManagement>
<system>Bamboo</system>
<url>https://build.spring.io/browse/SPRINGDATAES</url>
</ciManagement>
<issueManagement>
<system>GitHub</system>
<url>https://github.com/spring-projects/spring-data-elasticsearch/issues</url>
</issueManagement>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.19.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.20.0</version>
<scope>test</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- Spring -->
@@ -132,16 +157,25 @@
</exclusions>
</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>
<version>${elasticsearch-rest-client}</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 -->
@@ -229,6 +263,14 @@
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId>
<version>26.0.2-1</version>
<scope>test</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
@@ -280,21 +322,6 @@
<scope>test</scope>
</dependency>
<!-- Upgrade xbean to 4.5 to prevent incompatibilities due to ASM versions -->
<dependency>
<groupId>org.apache.xbean</groupId>
<artifactId>xbean-asm5-shaded</artifactId>
<version>4.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
@@ -304,16 +331,7 @@
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>elasticsearch</artifactId>
<version>${testcontainers}</version>
<scope>test</scope>
</dependency>
<!--we need Murmur3Hash in a test, before 5.2 we had it from the old Elasticsearch dependency -->
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.15</version>
<artifactId>testcontainers-elasticsearch</artifactId>
<scope>test</scope>
</dependency>
+1 -1
View File
@@ -17,7 +17,7 @@ content:
- url: https://github.com/spring-projects/spring-data-commons
# Refname matching:
# https://docs.antora.org/antora/latest/playbook/content-refname-matching/
branches: [ main, 3.4.x, 3.3.x ]
branches: [ main ]
start_path: src/main/antora
asciidoc:
attributes:
+1
View File
@@ -12,6 +12,7 @@
*** 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.4-5.5.adoc[]
*** xref:migration-guides/migration-guide-5.5-6.0.adoc[]
* xref:elasticsearch.adoc[]
@@ -5,7 +5,7 @@
Spring Data support for Elasticsearch contains a wide range of features:
* Spring configuration support for various xref:elasticsearch/clients.adoc[Elasticsearch clients].
* The xref:elasticsearch/template.adoc[`ElasticsearchTemplate` and `ReactiveElasticsearchTemplate`] helper classes that provide object mapping between ES index operations and POJOs.
* The xref:elasticsearch/template.adoc[`ElasticsearchTemplate` and `ReactiveElasticsearchTemplate`] helper classes that provide object mapping between Elasticsearch index operations and POJOs.
* xref:elasticsearch/template.adoc#exception-translation[Exception translation] into Spring's portable {springDocsUrl}data-access.html#dao-exceptions[Data Access Exception Hierarchy].
* Feature rich xref:elasticsearch/object-mapping.adoc[object mapping] integrated with _Spring's_ {springDocsUrl}core.html#core-convert[Conversion Service].
* xref:elasticsearch/object-mapping.adoc#elasticsearch.mapping.meta-model.annotations[Annotation-based mapping] metadata that is extensible to support other metadata formats.
@@ -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;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
public interface Persistable<ID> {
@Nullable
@@ -81,5 +81,5 @@ class MyConfiguration {
}
----
If your code contains more than one `AuditorAware` bean for different types, you must provide the name of the bean to use as an argument to the `auditorAwareRef` parameter of the
`@EnableElasticsearchAuditing` annotation.
If your code contains more than one `AuditorAware` bean for different types, you must provide the name of the bean to use as an argument to the `auditorAwareRef` parameter of the
`@EnableElasticsearchAuditing` annotation.
@@ -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.
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.restclient]]
== Imperative Rest Client
[[elasticsearch.clients.rest5client]]
== Imperative Rest5Client
To use the imperative (non-reactive) client, a configuration bean must be configured like this:
To use the imperative (non-reactive) Rest5Client - the default client provided by the Elasticsearch Java client library from version 9 on -, a configuration bean must be configured like this:
====
[source,java]
@@ -31,7 +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]
====
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:
@@ -39,7 +39,85 @@ The following beans can then be injected in other Spring components:
====
[source,java]
----
import org.springframework.beans.factory.annotation.Autowired;@Autowired
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 then 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:
====
[source,java]
----
import org.springframework.beans.factory.annotation.Autowired;
@Autowired
ElasticsearchOperations operations; <.>
@Autowired
@@ -61,8 +139,8 @@ JsonpMapper jsonpMapper; <.>
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.reactiverestclient]]
== Reactive Rest Client
[[elasticsearch.clients.reactiverest5client]]
== Reactive Rest5Client
When working with the reactive stack, the configuration must be derived from a different class:
@@ -93,6 +171,69 @@ The following beans can then be injected in other Spring components:
====
[source,java]
----
import org.springframework.beans.factory.annotation.Autowired;
@Autowired
ReactiveElasticsearchOperations operations; <.>
@Autowired
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]
----
import org.springframework.beans.factory.annotation.Autowired;
@Autowired
ReactiveElasticsearchOperations operations; <.>
@@ -161,7 +302,7 @@ ClientConfiguration clientConfiguration = ClientConfiguration.builder()
<.> Define default headers, if they need to be customized
<.> Use the builder to provide cluster addresses, set default `HttpHeaders` or enable SSL.
<.> Optionally enable SSL.There exist overloads of this function that can take a `SSLContext` or as an alternative the fingerprint of the certificate as it is output by Elasticsearch 8 on startup.
<.> Optionally enable SSL.There exist overloads of this function that can take a `SSLContext` or as an alternative the fingerprint of the certificate as it is output by Elasticsearch on startup (since version 8).
<.> Optionally set a proxy.
<.> Optionally set a path prefix, mostly used when different clusters a behind some reverse proxy.
<.> Set the connection timeout.
@@ -183,8 +324,25 @@ In the case this is not enough, the user can add callback functions by using the
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
`Rest5Client`:
====
[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]]
==== Configuration of the low level Elasticsearch `RestClient`:
==== Configuration of the deprecated low level Elasticsearch `RestClient`:
This callback provides a `org.elasticsearch.client.RestClientBuilder` that can be used to configure the Elasticsearch
`RestClient`:
@@ -193,7 +351,7 @@ This callback provides a `org.elasticsearch.client.RestClientBuilder` that can b
----
ClientConfiguration.builder()
.connectedTo("localhost:9200", "localhost:9291")
.withClientConfigurer(ElasticsearchClients.ElasticsearchRestClientConfigurationCallback.from(restClientBuilder -> {
.withClientConfigurer(RestClients.ElasticsearchRestClientConfigurationCallback.from(restClientBuilder -> {
// configure the Elasticsearch RestClient
return restClientBuilder;
}))
@@ -201,10 +359,29 @@ ClientConfiguration.builder()
----
====
[[elasticsearch.clients.configurationcallbacks.httpasync]]
==== Configuration of the HttpAsyncClient used by the low level Elasticsearch `RestClient`:
[[elasticsearch.clients.configurationcallbacks.httpasync5]]
==== Configuration of the HttpAsyncClient used by the low level Elasticsearch `Rest5Client`:
This callback provides a `org.apache.http.impl.nio.client.HttpAsyncClientBuilder` to configure the HttpCLient that is
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]]
==== Configuration of the HttpAsyncClient used by the deprecated low level Elasticsearch `RestClient`:
This callback provides a `org.apache.http.impl.nio.client.HttpAsyncClientBuilder` to configure the HttpClient that is
used by the `RestClient`.
====
@@ -212,7 +389,7 @@ used by the `RestClient`.
----
ClientConfiguration.builder()
.connectedTo("localhost:9200", "localhost:9291")
.withClientConfigurer(ElasticsearchClients.ElasticsearchHttpClientConfigurationCallback.from(httpAsyncClientBuilder -> {
.withClientConfigurer(RestClients.ElasticsearchHttpClientConfigurationCallback.from(httpAsyncClientBuilder -> {
// configure the HttpAsyncClient
return httpAsyncClientBuilder;
}))
@@ -220,15 +397,92 @@ ClientConfiguration.builder()
----
====
[[elasticsearch.clients.configurationcallbacks.connectionconfig]]
==== Configuration of the ConnectionConfig used by the low level Elasticsearch `Rest5Client`:
This callback provides a `org.apache.hc.client5.http.config.ConnectionConfig` to configure the connection that is
used by the `Rest5Client`.
====
[source,java]
----
ClientConfiguration.builder()
.connectedTo("localhost:9200", "localhost:9291")
.withClientConfigurer(Rest5Clients.ElasticsearchConnectionConfigurationCallback.from(connectionConfigBuilder -> {
// configure the connection
return connectionConfigBuilder;
}))
.build();
----
====
[[elasticsearch.clients.configurationcallbacks.connectioncmanager]]
==== Configuration of the ConnectionManager used by the low level Elasticsearch `Rest5Client`:
This callback provides a `org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManagerBuilder` to configure the connection manager that is
used by the `Rest5Client`.
====
[source,java]
----
ClientConfiguration.builder()
.connectedTo("localhost:9200", "localhost:9291")
.withClientConfigurer(Rest5Clients.ElasticsearchConnectionManagerCallback.from(connectionManagerBuilder -> {
// configure the connection manager
return connectionManagerBuilder;
}))
.build();
----
====
[[elasticsearch.clients.configurationcallbacks.requestconfig]]
==== Configuration of the RequestConfig used by the low level Elasticsearch `Rest5Client`:
This callback provides a `org.apache.hc.client5.http.config.RequestConfig` to configure the RequestConfig that is
used by the `Rest5Client`.
====
[source,java]
----
ClientConfiguration.builder()
.connectedTo("localhost:9200", "localhost:9291")
.withClientConfigurer(Rest5Clients.ElasticsearchRequestConfigCallback.from(requestConfigBuilder -> {
// configure the request config
return requestConfigBuilder;
}))
.build();
----
====
[[elasticsearch.clients.logging]]
== Client Logging
To see what is actually sent to and received from the server `Request` / `Response` logging on the transport level needs to be turned on as outlined in the snippet below.
This can be enabled in the Elasticsearch client by setting the level of the `tracer` package to "trace" (see
https://www.elastic.co/guide/en/elasticsearch/client/java-api-client/current/java-rest-low-usage-logging.html)
This can be enabled in the Elasticsearch client by setting the level of the `co.elastic.clients.transport.rest5_client.low_level.Request` package to "trace" (see
https://www.elastic.co/docs/reference/elasticsearch/clients/java/transport/rest5-client/usage/logging)
.Enable transport layer logging
[tabs]
======
XML::
+
[source,xml]
----
<logger name="tracer" level="trace"/>
<logger name="co.elastic.clients.transport.rest5_client.low_level.Request" level="trace"/>
----
yml::
+
[source,yml]
----
logging.level:
co.elastic.clients.transport.rest5_client.low_level.Request: trace
----
ini::
+
[source,ini]
----
logging.level.co.elastic.clients.transport.rest5_client.low_level.Request=trace
----
======
@@ -1,6 +1,16 @@
[[new-features]]
= What's new
[[new-features.6-0-0]]
== New in Spring Data Elasticsearch 6.0
* Upgrade to Spring 7
* Switch to jspecify nullability annotations
* Upgrade to Elasticsearch 9.2.2
* Use the new Elasticsearch Rest5Client as default
* Add support for SpEL expressions in the `settingPath` parameter of the `@Setting` annotation
[[new-features.5-5-0]]
== New in Spring Data Elasticsearch 5.5
@@ -11,7 +11,7 @@ When creating Elasticsearch indices with Spring Data Elasticsearch different ind
The following arguments are available:
* `useServerConfiguration` does not send any settings parameters, so the Elasticsearch server configuration determines them.
* `settingPath` refers to a JSON file defining the settings that must be resolvable in the classpath
* `settingPath` refers to a JSON file defining the settings that must be resolvable in the classpath, it is possible to use a SpEL expression here
* `shards` the number of shards to use, defaults to _1_
* `replicas` the number of replicas, defaults to _1_
* `refreshIntervall`, defaults to _"1s"_
@@ -376,7 +376,7 @@ So calling the method with a `List` of `["id1", "id2", "id3"]` would produce the
.Declare query on the method using the `@Query` annotation with SpEL expression.
====
https://docs.spring.io/spring-framework/reference/core/expressions.html[SpEL expression] is also supported when defining query in `@Query`.
{spring-framework-docs}/core/expressions.html[SpEL expression] is also supported when defining query in `@Query`.
[source,java]
----
@@ -453,7 +453,7 @@ We can pass `new QueryParameter("John")` as the parameter now, and it will produ
.accessing bean property.
====
https://docs.spring.io/spring-framework/reference/core/expressions/language-ref/bean-references.html[Bean property] is also supported to access.
{spring-framework-docs}/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:
[source,java]
@@ -523,7 +523,7 @@ A collection of `names` like `List.of("name1", "name2")` will produce the follow
.access property in the `Collection` param.
====
https://docs.spring.io/spring-framework/reference/core/expressions/language-ref/collection-projection.html[SpEL Collection Projection] is convenient to use when values in the `Collection` parameter is not plain `String`:
{spring-framework-docs}/core/expressions/language-ref/collection-projection.html[SpEL Collection Projection] is convenient to use when values in the `Collection` parameter is not plain `String`:
[source,java]
----
@@ -20,12 +20,12 @@ Whereas the birthdate is fix, the age depends on the time when a query is issued
====
[source,java]
----
import org.jspecify.annotations.Nullable;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.DateFormat;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.ScriptedField;
import org.springframework.lang.Nullable;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
@@ -6,9 +6,10 @@ The following table shows the Elasticsearch and Spring versions that are used by
[cols="^,^,^,^",options="header"]
|===
| Spring Data Release Train | Spring Data Elasticsearch | Elasticsearch | Spring Framework
| 2025.1 | 6.0.x | 9.2.3 | 7.0.x
| 2025.0 | 5.5.x | 8.18.1 | 6.2.x
| 2024.1 | 5.4.x | 8.15.5 | 6.1.x
| 2024.0 | 5.3.xfootnote:oom[Out of maintenance] | 8.13.4 | 6.1.x
| 2024.1 | 5.4.xfootnote:oom[Out of maintenance] | 8.15.5 | 6.1.x
| 2024.0 | 5.3.xfootnote:oom[] | 8.13.4 | 6.1.x
| 2023.1 (Vaughan) | 5.2.xfootnote:oom[] | 8.11.1 | 6.1.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
@@ -0,0 +1,27 @@
[[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.
In the `org.springframework.data.elasticsearch.core.query.UpdateQuery` class the type of the two fields `ifSeqNo` and `ifPrimaryTerm` has changed from `Integer` to `Long` to align with the normal query and the underlying Elasticsearch client.
[[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>>)
```
@@ -3,19 +3,20 @@ prerelease: ${antora-component.prerelease}
asciidoc:
attributes:
copyright-year: ${current.year}
version: ${project.version}
springversionshort: ${spring.short}
springversion: ${spring}
attribute-missing: 'warn'
commons: ${springdata.commons.docs}
chomp: 'all'
version: '${project.version}'
copyright-year: '${current.year}'
springversionshort: '${spring.short}'
springversion: '${spring}'
commons: '${springdata.commons.docs}'
include-xml-namespaces: false
spring-data-commons-docs-url: https://docs.spring.io/spring-data/commons/reference
spring-data-commons-javadoc-base: https://docs.spring.io/spring-data/commons/docs/${springdata.commons}/api/
springdocsurl: https://docs.spring.io/spring-framework/reference/{springversionshort}
springjavadocurl: https://docs.spring.io/spring-framework/docs/${spring}/javadoc-api
spring-data-commons-docs-url: '${documentation.baseurl}/spring-data/commons/reference/${springdata.commons.short}'
spring-data-commons-javadoc-base: '{spring-data-commons-docs-url}/api/java'
springdocsurl: '${documentation.baseurl}/spring-framework/reference/{springversionshort}'
spring-framework-docs: '{springdocsurl}'
springjavadocurl: '${documentation.spring-javadoc-url}'
spring-framework-javadoc: '{springjavadocurl}'
springhateoasversion: ${spring-hateoas}
releasetrainversion: ${releasetrain}
springhateoasversion: '${spring-hateoas}'
releasetrainversion: '${releasetrain}'
store: Elasticsearch
@@ -1,5 +1,5 @@
/*
* Copyright 2020-2025 the original author or authors.
* Copyright 2020-present 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2022-2025 the original author or authors.
* Copyright 2022-present 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.
@@ -15,10 +15,10 @@
*/
package org.springframework.data.elasticsearch;
import org.springframework.lang.Nullable;
import java.util.List;
import org.jspecify.annotations.Nullable;
/**
* Object describing an Elasticsearch error
*
@@ -26,8 +26,7 @@ import java.util.List;
* @since 4.4
*/
public class ElasticsearchErrorCause {
@Nullable
private final String type;
@Nullable private final String type;
private final String reason;
@@ -1,5 +1,5 @@
/*
* Copyright 2019-2025 the original author or authors.
* Copyright 2019-present 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2025 the original author or authors.
* Copyright 2021-present 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2022-2025 the original author or authors.
* Copyright 2022-present 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2025 the original author or authors.
* Copyright 2021-present 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2020-2025 the original author or authors.
* Copyright 2020-present 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.
@@ -15,8 +15,8 @@
*/
package org.springframework.data.elasticsearch;
import org.jspecify.annotations.Nullable;
import org.springframework.dao.UncategorizedDataAccessException;
import org.springframework.lang.Nullable;
/**
* @author Peter-Josef Meisch
@@ -1,5 +1,5 @@
/*
* Copyright 2023-2025 the original author or authors.
* Copyright 2023-present 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2024-2025 the original author or authors.
* Copyright 2024-present 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2024-2025 the original author or authors.
* Copyright 2024-present 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2019-2025 the original author or authors.
* Copyright 2019-present 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2013-2025 the original author or authors.
* Copyright 2013-present 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2025 the original author or authors.
* Copyright 2021-present 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2014-2025 the original author or authors.
* Copyright 2014-present 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2013-2025 the original author or authors.
* Copyright 2013-present 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.
@@ -107,17 +107,15 @@ public @interface Document {
*/
Alias[] aliases() default {};
/**
/**
* Note: the enum value FORCE, which was introduced in 4.4 has been removed
* again by Elasticsearch.
* @since 4.3
*/
enum VersionType {
INTERNAL("internal"), //
EXTERNAL("external"), //
EXTERNAL_GTE("external_gte"), //
/**
* @since 4.4
*/
FORCE("force");
EXTERNAL_GTE("external_gte"); //
private final String esName;
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2025 the original author or authors.
* Copyright 2021-present 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2013-2025 the original author or authors.
* Copyright 2013-present 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2024-2025 the original author or authors.
* Copyright 2024-present 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2013-2025 the original author or authors.
* Copyright 2013-present 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2024-2025 the original author or authors.
* Copyright 2024-present 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2013-2025 the original author or authors.
* Copyright 2013-present 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2017-2025 the original author or authors.
* Copyright 2017-present 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2020-2025 the original author or authors.
* Copyright 2020-present 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2020-2025 the original author or authors.
* Copyright 2020-present 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2020-2025 the original author or authors.
* Copyright 2020-present 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2019-2025 the original author or authors.
* Copyright 2019-present 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2019-2025 the original author or authors.
* Copyright 2019-present 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2023-2025 the original author or authors.
* Copyright 2023-present 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2014-2025 the original author or authors.
* Copyright 2014-present 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2020-2025 the original author or authors.
* Copyright 2020-present 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2020-2025 the original author or authors.
* Copyright 2020-present 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2024-2025 the original author or authors.
* Copyright 2024-present 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2024-2025 the original author or authors.
* Copyright 2024-present 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2024-2025 the original author or authors.
* Copyright 2024-present 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2014-2025 the original author or authors.
* Copyright 2014-present 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2024-2025 the original author or authors.
* Copyright 2024-present 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2014-2025 the original author or authors.
* Copyright 2014-present 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2020-2025 the original author or authors.
* Copyright 2020-present 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2013-2025 the original author or authors.
* Copyright 2013-present 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2025 the original author or authors.
* Copyright 2025-present 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2014-2025 the original author or authors.
* Copyright 2014-present 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2019-2025 the original author or authors.
* Copyright 2019-present 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2022-2025 the original author or authors.
* Copyright 2022-present 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2019-2025 the original author or authors.
* Copyright 2019-present 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2025 the original author or authors.
* Copyright 2021-present 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2022-2025 the original author or authors.
* Copyright 2022-present 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2025 the original author or authors.
* Copyright 2021-present 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.
@@ -1,3 +1,2 @@
@org.springframework.lang.NonNullApi
@org.springframework.lang.NonNullFields
@org.jspecify.annotations.NullMarked
package org.springframework.data.elasticsearch.annotations;
@@ -1,5 +1,5 @@
/*
* Copyright 2023-2025 the original author or authors.
* Copyright 2023-present 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.
@@ -17,7 +17,7 @@ package org.springframework.data.elasticsearch.aot;
import java.util.function.Predicate;
import org.springframework.data.util.ReactiveWrappers;
import org.springframework.data.core.ReactiveWrappers;
/**
* @author Peter-Josef Meisch
@@ -1,5 +1,5 @@
/*
* Copyright 2023-2025 the original author or authors.
* Copyright 2023-present 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.
@@ -19,6 +19,7 @@ import static org.springframework.data.elasticsearch.aot.ElasticsearchAotPredica
import java.util.Arrays;
import org.jspecify.annotations.Nullable;
import org.springframework.aot.hint.MemberCategory;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
@@ -32,7 +33,6 @@ import org.springframework.data.elasticsearch.core.event.ReactiveAfterConvertCal
import org.springframework.data.elasticsearch.core.event.ReactiveAfterLoadCallback;
import org.springframework.data.elasticsearch.core.event.ReactiveAfterSaveCallback;
import org.springframework.data.elasticsearch.core.event.ReactiveBeforeConvertCallback;
import org.springframework.lang.Nullable;
/**
* @author Peter-Josef Meisch
@@ -1,3 +1,2 @@
@org.springframework.lang.NonNullApi
@org.springframework.lang.NonNullFields
@org.jspecify.annotations.NullMarked
package org.springframework.data.elasticsearch.aot;
@@ -1,5 +1,5 @@
/*
* Copyright 2018-2025 the original author or authors.
* Copyright 2018-present 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.
@@ -25,8 +25,8 @@ import java.util.function.Supplier;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import org.jspecify.annotations.Nullable;
import org.springframework.data.elasticsearch.support.HttpHeaders;
import org.springframework.lang.Nullable;
/**
* Configuration interface exposing common client configuration properties for Elasticsearch clients.
@@ -127,10 +127,16 @@ public interface ClientConfiguration {
Optional<String> getCaFingerprint();
/**
* Returns the {@link HostnameVerifier} to use. Can be {@link Optional#empty()} if not configured.
* Returns the {@link HostnameVerifier} to use. Must 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.
* @deprecated since 6.0
*/
// todo #3117 document this
@Deprecated(since = "6.0", forRemoval=true)
Optional<HostnameVerifier> getHostNameVerifier();
/**
@@ -1,5 +1,5 @@
/*
* Copyright 2018-2025 the original author or authors.
* Copyright 2018-present 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.
@@ -25,11 +25,11 @@ import java.util.function.Supplier;
import javax.net.ssl.HostnameVerifier;
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.MaybeSecureClientConfigurationBuilder;
import org.springframework.data.elasticsearch.client.ClientConfiguration.TerminalClientConfigurationBuilder;
import org.springframework.data.elasticsearch.support.HttpHeaders;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
@@ -1,5 +1,5 @@
/*
* Copyright 2018-2025 the original author or authors.
* Copyright 2018-present 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.
@@ -24,9 +24,8 @@ import java.util.function.Supplier;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import org.elasticsearch.client.RestClientBuilder.HttpClientConfigCallback;
import org.jspecify.annotations.Nullable;
import org.springframework.data.elasticsearch.support.HttpHeaders;
import org.springframework.lang.Nullable;
/**
* Default {@link ClientConfiguration} implementation.
@@ -1,5 +1,5 @@
/*
* Copyright 2018-2025 the original author or authors.
* Copyright 2018-present 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2018-2025 the original author or authors.
* Copyright 2018-present 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2018-2025 the original author or authors.
* Copyright 2018-present 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2022-2025 the original author or authors.
* Copyright 2022-present 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2022-2025 the original author or authors.
* Copyright 2022-present 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2024-2025 the original author or authors.
* Copyright 2024-present 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.
@@ -17,10 +17,10 @@ package org.springframework.data.elasticsearch.client.elc;
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.Query;
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
@@ -38,8 +38,8 @@ public abstract class AbstractQueryProcessor {
* @param queryConverter correct mapped field names and the values to the converted values.
* @return an Elasticsearch {@literal query}.
*/
@Nullable
static co.elastic.clients.elasticsearch._types.query_dsl.Query getEsQuery(@Nullable Query query,
static co.elastic.clients.elasticsearch._types.query_dsl.@Nullable Query getEsQuery(@Nullable Query query,
@Nullable Consumer<Query> queryConverter) {
if (query == null) {
return null;
@@ -1,5 +1,5 @@
/*
* Copyright 2022-2025 the original author or authors.
* Copyright 2022-present 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2025 the original author or authors.
* Copyright 2021-present 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2025 the original author or authors.
* Copyright 2021-present 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2025 the original author or authors.
* Copyright 2021-present 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2025 the original author or authors.
* Copyright 2021-present 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2025 the original author or authors.
* Copyright 2021-present 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2025 the original author or authors.
* Copyright 2021-present 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.
@@ -31,13 +31,13 @@ import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import org.jspecify.annotations.Nullable;
import org.springframework.data.elasticsearch.annotations.FieldType;
import org.springframework.data.elasticsearch.core.query.Criteria;
import org.springframework.data.elasticsearch.core.query.Field;
import org.springframework.data.elasticsearch.core.query.HasChildQuery;
import org.springframework.data.elasticsearch.core.query.HasParentQuery;
import org.springframework.data.elasticsearch.core.query.InnerHitsQuery;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2025 the original author or authors.
* Copyright 2021-present 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.
@@ -24,16 +24,9 @@ import co.elastic.clients.elasticsearch.core.search.Hit;
import co.elastic.clients.elasticsearch.core.search.NestedIdentity;
import co.elastic.clients.json.JsonData;
import co.elastic.clients.json.JsonpMapper;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
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;
@@ -41,9 +34,15 @@ 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;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* Utility class to adapt different Elasticsearch responses to a
* {@link org.springframework.data.elasticsearch.core.document.Document}
@@ -55,187 +54,188 @@ import org.springframework.util.Assert;
*/
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.
*
* @param hit the hit object
* @param jsonpMapper to map JsonData objects
* @return the created {@link SearchDocument}
*/
public static SearchDocument from(Hit<?> hit, JsonpMapper jsonpMapper) {
/**
* Creates a {@link SearchDocument} from a {@link Hit} returned by the Elasticsearch client.
*
* @param hit the hit object
* @param jsonpMapper to map JsonData objects
* @return the created {@link SearchDocument}
*/
public static SearchDocument from(Hit<?> hit, JsonpMapper jsonpMapper) {
Assert.notNull(hit, "hit must not be null");
Assert.notNull(hit, "hit must not be null");
Map<String, List<String>> highlightFields = hit.highlight();
Map<String, List<String>> highlightFields = hit.highlight();
Map<String, SearchDocumentResponse> innerHits = new LinkedHashMap<>();
hit.innerHits().forEach((name, innerHitsResult) -> {
// noinspection ReturnOfNull
innerHits.put(name, SearchDocumentResponseBuilder.from(innerHitsResult.hits(), null, null, null, 0, null, null,
searchDocument -> null, jsonpMapper));
});
Map<String, SearchDocumentResponse> innerHits = new LinkedHashMap<>();
hit.innerHits().forEach((name, innerHitsResult) -> {
// noinspection ReturnOfNull
innerHits.put(name, SearchDocumentResponseBuilder.from(innerHitsResult.hits(), null, null, null, 0, null, null,
searchDocument -> null, jsonpMapper));
});
NestedMetaData nestedMetaData = from(hit.nested());
NestedMetaData nestedMetaData = from(hit.nested());
Explanation explanation = from(hit.explanation());
Explanation explanation = from(hit.explanation());
List<String> matchedQueries = hit.matchedQueries();
Map<String, Double> matchedQueries = hit.matchedQueries();
Function<Map<String, JsonData>, EntityAsMap> fromFields = fields -> {
StringBuilder sb = new StringBuilder("{");
final boolean[] firstField = { true };
hit.fields().forEach((key, jsonData) -> {
if (!firstField[0]) {
sb.append(',');
}
sb.append('"').append(key).append("\":") //
.append(jsonData.toJson(jsonpMapper).toString());
firstField[0] = false;
});
sb.append('}');
return new EntityAsMap().fromJson(sb.toString());
};
Function<Map<String, JsonData>, EntityAsMap> fromFields = fields -> {
StringBuilder sb = new StringBuilder("{");
final boolean[] firstField = {true};
hit.fields().forEach((key, jsonData) -> {
if (!firstField[0]) {
sb.append(',');
}
sb.append('"').append(key).append("\":") //
.append(jsonData.toJson(jsonpMapper).toString());
firstField[0] = false;
});
sb.append('}');
return new EntityAsMap().fromJson(sb.toString());
};
EntityAsMap hitFieldsAsMap = fromFields.apply(hit.fields());
EntityAsMap hitFieldsAsMap = fromFields.apply(hit.fields());
Map<String, List<Object>> documentFields = new LinkedHashMap<>();
hitFieldsAsMap.forEach((key, value) -> {
if (value instanceof List) {
// noinspection unchecked
documentFields.put(key, (List<Object>) value);
} else {
documentFields.put(key, Collections.singletonList(value));
}
});
Map<String, List<Object>> documentFields = new LinkedHashMap<>();
hitFieldsAsMap.forEach((key, value) -> {
if (value instanceof List) {
// noinspection unchecked
documentFields.put(key, (List<Object>) value);
} else {
documentFields.put(key, Collections.singletonList(value));
}
});
Document document;
Object source = hit.source();
if (source == null) {
document = Document.from(hitFieldsAsMap);
} else {
if (source instanceof EntityAsMap entityAsMap) {
document = Document.from(entityAsMap);
} else if (source instanceof JsonData jsonData) {
document = Document.from(jsonData.to(EntityAsMap.class));
} else {
Document document;
Object source = hit.source();
if (source == null) {
document = Document.from(hitFieldsAsMap);
} else {
if (source instanceof EntityAsMap entityAsMap) {
document = Document.from(entityAsMap);
} else if (source instanceof JsonData jsonData) {
document = Document.from(jsonData.to(EntityAsMap.class));
} else {
if (LOGGER.isWarnEnabled()) {
LOGGER.warn(String.format("Cannot map from type " + source.getClass().getName()));
}
document = Document.create();
}
}
document.setIndex(hit.index());
document.setId(hit.id());
if (LOGGER.isWarnEnabled()) {
LOGGER.warn(String.format("Cannot map from type " + source.getClass().getName()));
}
document = Document.create();
}
}
document.setIndex(hit.index());
document.setId(hit.id());
if (hit.version() != null) {
document.setVersion(hit.version());
}
document.setSeqNo(hit.seqNo() != null && hit.seqNo() >= 0 ? hit.seqNo() : -2); // -2 was the default value in the
// old client
document.setPrimaryTerm(hit.primaryTerm() != null && hit.primaryTerm() > 0 ? hit.primaryTerm() : 0);
if (hit.version() != null) {
document.setVersion(hit.version());
}
document.setSeqNo(hit.seqNo() != null && hit.seqNo() >= 0 ? hit.seqNo() : -2); // -2 was the default value in the
// old client
document.setPrimaryTerm(hit.primaryTerm() != null && hit.primaryTerm() > 0 ? hit.primaryTerm() : 0);
float score = hit.score() != null ? hit.score().floatValue() : Float.NaN;
return new SearchDocumentAdapter(document, score, hit.sort().stream().map(TypeUtils::toObject).toArray(),
documentFields, highlightFields, innerHits, nestedMetaData, explanation, matchedQueries, hit.routing());
}
float score = hit.score() != null ? hit.score().floatValue() : Float.NaN;
return new SearchDocumentAdapter(document, score, hit.sort().stream().map(TypeUtils::toObject).toArray(),
documentFields, highlightFields, innerHits, nestedMetaData, explanation, matchedQueries, hit.routing());
}
public static SearchDocument from(CompletionSuggestOption<EntityAsMap> completionSuggestOption) {
public static SearchDocument from(CompletionSuggestOption<EntityAsMap> completionSuggestOption) {
Document document = completionSuggestOption.source() != null ? Document.from(completionSuggestOption.source())
: Document.create();
document.setIndex(completionSuggestOption.index());
Document document = completionSuggestOption.source() != null ? Document.from(completionSuggestOption.source())
: Document.create();
document.setIndex(completionSuggestOption.index());
if (completionSuggestOption.id() != null) {
document.setId(completionSuggestOption.id());
}
if (completionSuggestOption.id() != null) {
document.setId(completionSuggestOption.id());
}
float score = completionSuggestOption.score() != null ? completionSuggestOption.score().floatValue() : Float.NaN;
return new SearchDocumentAdapter(document, score, new Object[] {}, Collections.emptyMap(), Collections.emptyMap(),
Collections.emptyMap(), null, null, null, completionSuggestOption.routing());
}
float score = completionSuggestOption.score() != null ? completionSuggestOption.score().floatValue() : Float.NaN;
return new SearchDocumentAdapter(document, score, new Object[]{}, Collections.emptyMap(), Collections.emptyMap(),
Collections.emptyMap(), null, null, null, completionSuggestOption.routing());
}
@Nullable
private static Explanation from(@Nullable co.elastic.clients.elasticsearch.core.explain.Explanation explanation) {
@Nullable
private static Explanation from(co.elastic.clients.elasticsearch.core.explain.@Nullable Explanation explanation) {
if (explanation == null) {
return null;
}
List<Explanation> details = explanation.details().stream().map(DocumentAdapters::from).collect(Collectors.toList());
return new Explanation(true, (double) explanation.value(), explanation.description(), details);
}
if (explanation == null) {
return null;
}
List<Explanation> details = explanation.details().stream().map(DocumentAdapters::from).collect(Collectors.toList());
return new Explanation(true, (double) explanation.value(), explanation.description(), details);
}
private static Explanation from(ExplanationDetail explanationDetail) {
private static Explanation from(ExplanationDetail explanationDetail) {
List<Explanation> details = explanationDetail.details().stream().map(DocumentAdapters::from)
.collect(Collectors.toList());
return new Explanation(null, (double) explanationDetail.value(), explanationDetail.description(), details);
}
List<Explanation> details = explanationDetail.details().stream().map(DocumentAdapters::from)
.collect(Collectors.toList());
return new Explanation(null, (double) explanationDetail.value(), explanationDetail.description(), details);
}
@Nullable
private static NestedMetaData from(@Nullable NestedIdentity nestedIdentity) {
@Nullable
private static NestedMetaData from(@Nullable NestedIdentity nestedIdentity) {
if (nestedIdentity == null) {
return null;
}
if (nestedIdentity == null) {
return null;
}
NestedMetaData child = from(nestedIdentity.nested());
return NestedMetaData.of(nestedIdentity.field(), nestedIdentity.offset(), child);
}
NestedMetaData child = from(nestedIdentity.nested());
return NestedMetaData.of(nestedIdentity.field(), nestedIdentity.offset(), child);
}
/**
* Creates a {@link Document} from a {@link GetResponse} where the found document is contained as {@link EntityAsMap}.
*
* @param getResponse the response instance
* @return the Document
*/
@Nullable
public static Document from(GetResult<EntityAsMap> getResponse) {
/**
* Creates a {@link Document} from a {@link GetResponse} where the found document is contained as {@link EntityAsMap}.
*
* @param getResponse the response instance
* @return the Document
*/
@Nullable
public static Document from(GetResult<EntityAsMap> getResponse) {
Assert.notNull(getResponse, "getResponse must not be null");
Assert.notNull(getResponse, "getResponse must not be null");
if (!getResponse.found()) {
return null;
}
if (!getResponse.found()) {
return null;
}
Document document = getResponse.source() != null ? Document.from(getResponse.source()) : Document.create();
document.setIndex(getResponse.index());
document.setId(getResponse.id());
Document document = getResponse.source() != null ? Document.from(getResponse.source()) : Document.create();
document.setIndex(getResponse.index());
document.setId(getResponse.id());
if (getResponse.version() != null) {
document.setVersion(getResponse.version());
}
if (getResponse.version() != null) {
document.setVersion(getResponse.version());
}
if (getResponse.seqNo() != null) {
document.setSeqNo(getResponse.seqNo());
}
if (getResponse.seqNo() != null) {
document.setSeqNo(getResponse.seqNo());
}
if (getResponse.primaryTerm() != null) {
document.setPrimaryTerm(getResponse.primaryTerm());
}
if (getResponse.primaryTerm() != null) {
document.setPrimaryTerm(getResponse.primaryTerm());
}
return document;
}
return document;
}
/**
* Creates a list of {@link MultiGetItem}s from a {@link MgetResponse} where the data is contained as
* {@link EntityAsMap} instances.
*
* @param mgetResponse the response instance
* @return list of multiget items
*/
public static List<MultiGetItem<Document>> from(MgetResponse<EntityAsMap> mgetResponse) {
/**
* Creates a list of {@link MultiGetItem}s from a {@link MgetResponse} where the data is contained as
* {@link EntityAsMap} instances.
*
* @param mgetResponse the response instance
* @return list of multiget items
*/
public static List<MultiGetItem<Document>> from(MgetResponse<EntityAsMap> mgetResponse) {
Assert.notNull(mgetResponse, "mgetResponse must not be null");
Assert.notNull(mgetResponse, "mgetResponse must not be null");
return mgetResponse.docs().stream() //
.map(itemResponse -> MultiGetItem.of( //
itemResponse.isFailure() ? null : from(itemResponse.result()), //
ResponseConverter.getFailure(itemResponse)))
.collect(Collectors.toList());
}
return mgetResponse.docs().stream() //
.map(itemResponse -> MultiGetItem.of( //
itemResponse.isFailure() ? null : from(itemResponse.result()), //
ResponseConverter.getFailure(itemResponse)))
.collect(Collectors.toList());
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2022-2025 the original author or authors.
* Copyright 2022-present 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2025 the original author or authors.
* Copyright 2021-present 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.
@@ -22,8 +22,8 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.jspecify.annotations.Nullable;
import org.springframework.data.elasticsearch.core.AggregationsContainer;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
@@ -1,5 +1,5 @@
/*
* Copyright 2022-2025 the original author or authors.
* Copyright 2022-present 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2022-2025 the original author or authors.
* Copyright 2022-present 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.
@@ -19,12 +19,12 @@ import co.elastic.clients.elasticsearch.ElasticsearchClient;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jspecify.annotations.Nullable;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.FactoryBeanNotInitializedException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.data.elasticsearch.client.ClientConfiguration;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2025 the original author or authors.
* Copyright 2021-present 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.
@@ -15,44 +15,38 @@
*/
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.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.TransportUtils;
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.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.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.impl.nio.client.HttpAsyncClientBuilder;
import org.apache.http.message.BasicHeader;
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.RestClientBuilder;
import org.jspecify.annotations.Nullable;
import org.springframework.data.elasticsearch.client.ClientConfiguration;
import org.springframework.data.elasticsearch.support.HttpHeaders;
import org.springframework.lang.Nullable;
import org.springframework.data.elasticsearch.support.VersionInfo;
import org.springframework.util.Assert;
/**
* Utility class to create the different Elasticsearch clients
* Utility class to create the different Elasticsearch clients. The RestClient class is the one used in Elasticsearch
* 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
* @since 4.4
@@ -119,18 +113,32 @@ public final class ElasticsearchClients {
*
* @param restClient the underlying {@link RestClient}
* @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) {
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}.
*
* @param restClient the underlying {@link RestClient}
* @param transportOptions options to be added to each request.
* @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,
@Nullable TransportOptions transportOptions, JsonpMapper jsonpMapper) {
@@ -139,6 +147,21 @@ public final class ElasticsearchClients {
var transport = getElasticsearchTransport(restClient, REACTIVE_CLIENT, transportOptions, jsonpMapper);
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}.
@@ -156,17 +179,21 @@ public final class ElasticsearchClients {
// region imperative client
/**
* Creates a new imperative {@link ElasticsearchClient}
* Creates a new imperative {@link ElasticsearchClient}. This uses a RestClient, if the old RestClient is needed, this
* 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}.
* @return the {@link ElasticsearchClient}
*/
public static ElasticsearchClient createImperative(ClientConfiguration clientConfiguration) {
return createImperative(getRestClient(clientConfiguration), null, DEFAULT_JSONP_MAPPER);
return createImperative(getRest5Client(clientConfiguration), null, DEFAULT_JSONP_MAPPER);
}
/**
* Creates a new imperative {@link ElasticsearchClient}
* Creates a new imperative {@link ElasticsearchClient}. This uses a RestClient, if the old RestClient is needed, this
* 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 transportOptions options to be added to each request.
@@ -174,7 +201,7 @@ public final class ElasticsearchClients {
*/
public static ElasticsearchClient createImperative(ClientConfiguration clientConfiguration,
TransportOptions transportOptions) {
return createImperative(getRestClient(clientConfiguration), transportOptions, DEFAULT_JSONP_MAPPER);
return createImperative(getRest5Client(clientConfiguration), transportOptions, DEFAULT_JSONP_MAPPER);
}
/**
@@ -182,11 +209,23 @@ public final class ElasticsearchClients {
*
* @param restClient the RestClient to use
* @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) {
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}
*
@@ -194,7 +233,9 @@ public final class ElasticsearchClients {
* @param transportOptions options to be added to each request.
* @param jsonpMapper the mapper for the transport to use
* @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,
JsonpMapper jsonpMapper) {
@@ -206,6 +247,27 @@ public final class ElasticsearchClients {
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}.
*
@@ -220,96 +282,6 @@ public final class ElasticsearchClients {
}
// 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
/**
* Creates an {@link ElasticsearchTransport} that will use the given client that additionally is customized with a
@@ -320,7 +292,9 @@ public final class ElasticsearchClients {
* @param transportOptions options for the transport
* @param jsonpMapper mapper for the transport
* @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,
@Nullable TransportOptions transportOptions, JsonpMapper jsonpMapper) {
@@ -329,7 +303,7 @@ public final class ElasticsearchClients {
Assert.notNull(jsonpMapper, "jsonpMapper must not be null");
TransportOptions.Builder transportOptionsBuilder = transportOptions != null ? transportOptions.toBuilder()
: new RestClientOptions(RequestOptions.DEFAULT, false).toBuilder();
: new RestClientOptions(org.elasticsearch.client.RequestOptions.DEFAULT, false).toBuilder();
RestClientOptions.Builder restClientOptionsBuilder = getRestClientOptionsBuilder(transportOptions);
@@ -353,70 +327,35 @@ public final class ElasticsearchClients {
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
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;
}
}
// todo #3117 remove and document that ElasticsearchHttpClientConfigurationCallback has been move to RestClients.
}
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2025 the original author or authors.
* Copyright 2021-present 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.
@@ -20,12 +20,13 @@ 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 co.elastic.clients.transport.rest5_client.Rest5ClientOptions;
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.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.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
@@ -38,7 +39,9 @@ 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.
* classes must provide the {@link ClientConfiguration} to use. From Version 6.0 on, this class uses the new Rest5Client
* from Elasticsearch 9. The old implementation using the RestClient is still available under the name
* {@link ElasticsearchLegacyRestClientConfiguration}.
*
* @author Peter-Josef Meisch
* @since 4.4
@@ -60,27 +63,27 @@ public abstract class ElasticsearchConfiguration extends ElasticsearchConfigurat
* @return RestClient
*/
@Bean
public RestClient elasticsearchRestClient(ClientConfiguration clientConfiguration) {
public Rest5Client elasticsearchRest5Client(ClientConfiguration clientConfiguration) {
Assert.notNull(clientConfiguration, "clientConfiguration must not be null");
return ElasticsearchClients.getRestClient(clientConfiguration);
return Rest5Clients.getRest5Client(clientConfiguration);
}
/**
* Provides the Elasticsearch transport to be used. The default implementation uses the {@link RestClient} bean and
* Provides the Elasticsearch transport to be used. The default implementation uses the {@link Rest5Client} 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) {
public ElasticsearchTransport elasticsearchTransport(Rest5Client rest5Client, JsonpMapper jsonpMapper) {
Assert.notNull(restClient, "restClient must not be null");
Assert.notNull(rest5Client, "restClient must not be null");
Assert.notNull(jsonpMapper, "jsonpMapper must not be null");
return ElasticsearchClients.getElasticsearchTransport(restClient, ElasticsearchClients.IMPERATIVE_CLIENT,
return ElasticsearchClients.getElasticsearchTransport(rest5Client, ElasticsearchClients.IMPERATIVE_CLIENT,
transportOptions(), jsonpMapper);
}
@@ -115,7 +118,7 @@ public abstract class ElasticsearchConfiguration extends ElasticsearchConfigurat
}
/**
* Provides the JsonpMapper bean that is used in the {@link #elasticsearchTransport(RestClient, JsonpMapper)} method.
* Provides the JsonpMapper bean that is used in the {@link #elasticsearchTransport(Rest5Client, JsonpMapper)} method.
*
* @return the {@link JsonpMapper} to use
* @since 5.2
@@ -135,6 +138,6 @@ public abstract class ElasticsearchConfiguration extends ElasticsearchConfigurat
* @return the options that should be added to every request. Must not be {@literal null}
*/
public TransportOptions transportOptions() {
return new RestClientOptions(RequestOptions.DEFAULT, false);
return new Rest5ClientOptions(RequestOptions.DEFAULT, false);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2025 the original author or authors.
* Copyright 2021-present 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.
@@ -24,6 +24,7 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.elasticsearch.client.ResponseException;
import org.jspecify.annotations.Nullable;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.dao.DataIntegrityViolationException;
@@ -33,6 +34,7 @@ import org.springframework.data.elasticsearch.NoSuchIndexException;
import org.springframework.data.elasticsearch.ResourceNotFoundException;
import org.springframework.data.elasticsearch.UncategorizedElasticsearchException;
import org.springframework.data.elasticsearch.VersionConflictException;
import org.springframework.util.ClassUtils;
/**
* Simple {@link PersistenceExceptionTranslator} for Elasticsearch. Convert the given runtime exception to an
@@ -45,6 +47,9 @@ import org.springframework.data.elasticsearch.VersionConflictException;
*/
public class ElasticsearchExceptionTranslator implements PersistenceExceptionTranslator {
public static final boolean LEGACY_RESTCLIENT_PRESENT = ClassUtils
.isPresent("org.elasticsearch.client.ResponseException", ElasticsearchExceptionTranslator.class.getClassLoader());
private final JsonpMapper jsonpMapper;
public ElasticsearchExceptionTranslator(JsonpMapper jsonpMapper) {
@@ -68,7 +73,7 @@ public class ElasticsearchExceptionTranslator implements PersistenceExceptionTra
}
@Override
public DataAccessException translateExceptionIfPossible(RuntimeException ex) {
public @Nullable DataAccessException translateExceptionIfPossible(RuntimeException ex) {
checkForConflictException(ex);
@@ -118,15 +123,20 @@ public class ElasticsearchExceptionTranslator implements PersistenceExceptionTra
Integer status = null;
String message = null;
if (exception instanceof ResponseException responseException) {
if (LEGACY_RESTCLIENT_PRESENT && exception instanceof ResponseException responseException) {
// this code is for the old RestClient
status = responseException.getResponse().getStatusLine().getStatusCode();
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) {
checkForConflictException(exception.getCause());
}
if (status != null && message != null) {
if (status == 409 && message.contains("type\":\"version_conflict_engine_exception"))
if (status == 409 && message.contains("version_conflict_engine_exception"))
if (message.contains("version conflict, required seqNo")) {
throw new OptimisticLockingFailureException("Cannot index a document due to seq_no+primary_term conflict",
exception);
@@ -0,0 +1,144 @@
/*
* Copyright 2021-present 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);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2025 the original author or authors.
* Copyright 2021-present 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.
@@ -40,6 +40,7 @@ import java.util.stream.Collectors;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jspecify.annotations.Nullable;
import org.springframework.data.elasticsearch.BulkFailureException;
import org.springframework.data.elasticsearch.client.UnsupportedBackendOperation;
import org.springframework.data.elasticsearch.core.AbstractElasticsearchTemplate;
@@ -59,7 +60,6 @@ import org.springframework.data.elasticsearch.core.reindex.ReindexRequest;
import org.springframework.data.elasticsearch.core.reindex.ReindexResponse;
import org.springframework.data.elasticsearch.core.script.Script;
import org.springframework.data.elasticsearch.core.sql.SqlResponse;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
@@ -658,7 +658,7 @@ public class ElasticsearchTemplate extends AbstractElasticsearchTemplate {
QueryResponse response = sqlClient.query(requestConverter.sqlQueryRequest(query));
return responseConverter.sqlResponse(response);
} catch (IOException e) {
} catch (Exception e) {
throw exceptionTranslator.translateException(e);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2025 the original author or authors.
* Copyright 2021-present 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2022-2025 the original author or authors.
* Copyright 2022-present 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.
@@ -17,9 +17,12 @@ package org.springframework.data.elasticsearch.client.elc;
import static org.springframework.data.elasticsearch.client.elc.TypeUtils.*;
import co.elastic.clients.util.NamedValue;
import java.util.Arrays;
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.ElasticsearchPersistentProperty;
import org.springframework.data.elasticsearch.core.query.highlight.Highlight;
@@ -27,7 +30,6 @@ 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.HighlightParameters;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.lang.Nullable;
import org.springframework.util.StringUtils;
/**
@@ -43,7 +45,8 @@ class HighlightQueryBuilder {
private final RequestConverter requestConverter;
HighlightQueryBuilder(
MappingContext<? extends ElasticsearchPersistentEntity<?>, ElasticsearchPersistentProperty> mappingContext, RequestConverter requestConverter) {
MappingContext<? extends ElasticsearchPersistentEntity<?>, ElasticsearchPersistentProperty> mappingContext,
RequestConverter requestConverter) {
this.mappingContext = mappingContext;
this.requestConverter = requestConverter;
}
@@ -59,10 +62,11 @@ class HighlightQueryBuilder {
for (HighlightField highlightField : highlight.getFields()) {
String mappedName = mapFieldName(highlightField.getName(), type);
highlightBuilder.fields(mappedName, hf -> {
addParameters(highlightField.getParameters(), hf, type);
return hf;
});
highlightBuilder.fields(
NamedValue.of(mappedName, co.elastic.clients.elasticsearch.core.search.HighlightField.of(hf -> {
addParameters(highlightField.getParameters(), hf, type);
return hf;
})));
}
return highlightBuilder.build();
@@ -1,5 +1,5 @@
/*
* Copyright 2021-2025 the original author or authors.
* Copyright 2021-present 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.
@@ -27,8 +27,10 @@ import java.util.Map;
import java.util.Objects;
import java.util.Set;
import org.jspecify.annotations.Nullable;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.elasticsearch.ResourceNotFoundException;
import org.springframework.data.elasticsearch.UncategorizedElasticsearchException;
import org.springframework.data.elasticsearch.annotations.Mapping;
import org.springframework.data.elasticsearch.core.IndexInformation;
@@ -49,7 +51,6 @@ import org.springframework.data.elasticsearch.core.mapping.Alias;
import org.springframework.data.elasticsearch.core.mapping.CreateIndexSettings;
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
/**
@@ -315,15 +316,20 @@ public class IndicesTemplate extends ChildTemplate<ElasticsearchTransport, Elast
}
@Override
public TemplateData getTemplate(GetTemplateRequest getTemplateRequest) {
public @Nullable TemplateData getTemplate(GetTemplateRequest getTemplateRequest) {
Assert.notNull(getTemplateRequest, "getTemplateRequest must not be null");
co.elastic.clients.elasticsearch.indices.GetTemplateRequest getTemplateRequestES = requestConverter
.indicesGetTemplateRequest(getTemplateRequest);
GetTemplateResponse getTemplateResponse = execute(client -> client.getTemplate(getTemplateRequestES));
return responseConverter.indicesGetTemplateData(getTemplateResponse, getTemplateRequest.getTemplateName());
try {
GetTemplateResponse getTemplateResponse = execute(client -> client.getTemplate(getTemplateRequestES));
return responseConverter.indicesGetTemplateData(getTemplateResponse, getTemplateRequest.getTemplateName());
} catch (ResourceNotFoundException e) {
// since Elasticsearch 9.1.0 we get an exception (404) instead of an empty result
return null;
}
}
@Override

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