1
0
mirror of synced 2026-05-24 05:03:17 +00:00

Compare commits

...

27 Commits

Author SHA1 Message Date
Mark Paluch dde239cab6 Release version 6.0.5 (2025.1.5).
See #3257
2026-04-17 16:39:32 +02:00
Mark Paluch f34dbb1915 Prepare 6.0.5 (2025.1.5).
See #3257
2026-04-17 16:39:11 +02:00
Peter-Josef Meisch 8875fb79a8 Upgrade to Elasticsearch 9.2.8 - the missing parts (#3271)
Signed-off-by: Peter-Josef Meisch <pj.meisch@sothawo.com>
2026-04-11 12:31:55 +02:00
Mark Paluch f6af6b6f33 Upgrade to Elasticsearch REST Client 9.2.8.
See #3269
2026-04-10 16:58:21 +02:00
Ralph Ursprung 6b3646bcc1 Make AOT hints for ELC optional.
see also opensearch-project/spring-data-opensearch#441

Signed-off-by: Ralph Ursprung <Ralph.Ursprung@avaloq.com>
(cherry picked from commit ffdbea4dba)
2026-03-31 18:20:14 +02:00
Peter-Josef Meisch 1cccc1cbb2 Ugrade Elasticsearch to version 9.2.7.
Closes #3264

Signed-off-by: Peter-Josef Meisch <pj.meisch@sothawo.com>
2026-03-22 17:04:39 +01:00
Mark Paluch 2c8e18ac35 After release cleanups.
See #3245
2026-03-13 11:38:31 +01:00
Mark Paluch c11146b0f2 Prepare next development iteration.
See #3245
2026-03-13 11:38:30 +01:00
Mark Paluch 01be7415db Release version 6.0.4 (2025.1.4).
See #3245
2026-03-13 11:35:34 +01:00
Mark Paluch 77c596ec01 Prepare 6.0.4 (2025.1.4).
See #3245
2026-03-13 11:35:09 +01:00
Peter-Josef Meisch 7f68f50e56 Upgrade to Elasticsearch 9.2.6
Signed-off-by: Peter-Josef Meisch <pj.meisch@sothawo.com>
2026-03-01 12:29:10 +01:00
Mark Paluch 89b3199c3f Update GitHub action branch triggers.
See #3245
2026-02-20 17:49:59 +01:00
Mark Paluch ad77924370 Refine Antora-build.
See spring-projects/spring-data-build#2797
2026-02-20 17:17:36 +01:00
Mark Paluch ce54645bbe Update GitHub action branch triggers.
See #3245
2026-02-19 14:46:36 +01:00
Christoph Strobl 93363c9e04 Remove obsolete CI configuration.
See spring-projects/spring-data-build#2764
2026-02-16 16:43:27 +01:00
Mark Paluch da40eb1b11 Add GitHub actions.
See spring-projects/spring-data-build#2764
2026-02-16 16:42:10 +01:00
noel1155 911d80e77e Fix error propagation in AbstractReactiveElasticsearchTemplate:save()
Previously, errors occurring during the saveAll operation within the reactive save method were swallowed because the inner subscriber did not have an error handler. This caused the Flux to hang indefinitely instead of terminating with an error.

This commit adds an error handler to the inner subscriber that:
1. Cancels the upstream subscription to prevent further processing.
2. Propagates the error to the sink, allowing the caller to receive the error signal.
3. Updates the map operation to return the entity for better debugging capability.

Signed-off-by: Noel F <noel@Noels-MacBook-Pro.local>

* Add test for error propagation in reactive Flux save operations

This test verifies that errors occurring during saveAll operations
with a Flux are properly propagated to the subscriber instead of
being swallowed. The test creates a Flux that emits valid entities
followed by an error, and confirms the error reaches the caller.

Signed-off-by: Noel F <noel@Noels-MacBook-Pro.local>

* undo format fixes

Signed-off-by: Noel F <noel@Noels-MacBook-Pro.local>

* Update error propagation test: expect 0 entities before error due to race condition

The manual subscriber's onError fires before in-flight saveAll can push
results through tryEmitNext, so the caller sees 0 entities before the error.
Updated test expectation and added clarifying comment.

Signed-off-by: Noel F <noel@Noels-MacBook-Pro.local>

---------

Signed-off-by: Noel F <noel@Noels-MacBook-Pro.local>
Co-authored-by: xylos19 <noel@Noels-MacBook-Pro.local>

Closes #3233

(cherry picked from commit 0c1f5369df)
2026-02-15 08:41:13 +01:00
Mark Paluch bd8f947a47 After release cleanups.
See #3226
2026-02-13 11:18:07 +01:00
Mark Paluch 9af8e2970a Prepare next development iteration.
See #3226
2026-02-13 11:18:06 +01:00
Mark Paluch 3a295cfa12 Release version 6.0.3 (2025.1.3).
See #3226
2026-02-13 11:15:46 +01:00
Mark Paluch efe7932d42 Prepare 6.0.3 (2025.1.3).
See #3226
2026-02-13 11:15:27 +01:00
Peter-Josef Meisch 26a7b48c4b Upgrade to Elasticsearch 9.2.5.
Closes #3236

Signed-off-by: Peter-Josef Meisch <pj.meisch@sothawo.com>
2026-02-08 18:24:59 +01:00
Peter-Josef Meisch 34a0d9b600 Fix setting script id in UpdateQuery request.
Closes #3231

Signed-off-by: Peter-Josef Meisch <pj.meisch@sothawo.com>
(cherry picked from commit ead1926d13)
2026-02-01 13:39:36 +01:00
Mark Paluch cb32d1991d Update CI Properties.
See #3226
2026-01-28 10:41:14 +01:00
Peter-Josef Meisch fbf9c355fa Upgrade to Elasticsearch 9.2.4. (#3229)
Closes #3228

Signed-off-by: Peter-Josef Meisch <pj.meisch@sothawo.com>
2026-01-23 19:53:00 +01:00
Christoph Strobl 2dbca48cdf After release cleanups.
See #3214
2026-01-16 10:39:48 +01:00
Christoph Strobl e7366973b7 Prepare next development iteration.
See #3214
2026-01-16 10:39:47 +01:00
20 changed files with 164 additions and 263 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
= 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"]
= Spring Data for Elasticsearch 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.
+27
View File
@@ -0,0 +1,27 @@
name: CI Build
on:
workflow_dispatch:
push:
branches: [ 6.0.x, 'issue/6.0.x/**' ]
permissions: read-all
jobs:
build-java:
strategy:
matrix:
java-version: [ base, main ]
name: Build project
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Setup Java and Maven
uses: spring-projects/spring-data-build/actions/setup-maven@4.0.x
with:
java-version: ${{ matrix.java-version }}
develocity-access-key: '${{ secrets.DEVELOCITY_ACCESS_KEY }}'
- name: Build
uses: spring-projects/spring-data-build/actions/maven-build@4.0.x
env:
TESTCONTAINERS_REUSE_ENABLE: true
+28
View File
@@ -0,0 +1,28 @@
name: Snapshots
on:
workflow_dispatch:
push:
branches: [ 6.0.x, 'issue/6.0.x/**' ]
permissions: read-all
jobs:
build-snapshots:
name: Build and deploy snapshots
if: ${{ github.repository_owner == 'spring-projects' }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Setup Java and Maven
uses: spring-projects/spring-data-build/actions/setup-maven@4.0.x
with:
develocity-access-key: '${{ secrets.DEVELOCITY_ACCESS_KEY }}'
- name: Deploy to Artifactory
uses: spring-projects/spring-data-build/actions/maven-artifactory-deploy@4.0.x
env:
TESTCONTAINERS_REUSE_ENABLE: true
with:
build-name: 'spring-data-elasticsearch'
username: '${{ secrets.ARTIFACTORY_USERNAME }}'
password: '${{ secrets.ARTIFACTORY_PASSWORD }}'
+1 -1
View File
@@ -3,6 +3,6 @@
<extension>
<groupId>io.spring.develocity.conventions</groupId>
<artifactId>develocity-conventions-maven-extension</artifactId>
<version>0.0.22</version>
<version>0.0.25</version>
</extension>
</extensions>
+1 -39
View File
@@ -1,43 +1,5 @@
= Continuous Integration
image:https://jenkins.spring.io/buildStatus/icon?job=spring-data-elasticsearch%2Fmain&subject=2020.0.0%20(main)[link=https://jenkins.spring.io/view/SpringData/job/spring-data-elasticsearch/]
image:https://jenkins.spring.io/buildStatus/icon?job=spring-data-elasticsearch%2F4.0.x&subject=Neumann%20(4.0.x)[link=https://jenkins.spring.io/view/SpringData/job/spring-data-elasticsearch/]
image:https://jenkins.spring.io/buildStatus/icon?job=spring-data-elasticsearch%2F3.2.x&subject=Moore%20(3.2.x)[link=https://jenkins.spring.io/view/SpringData/job/spring-data-elasticsearch/]
== Running CI tasks locally
Since this pipeline is purely Docker-based, it's easy to:
* Debug what went wrong on your local machine.
* Test out a a tweak to your `verify.sh` script before sending it out.
* Experiment against a new image before submitting your pull request.
All of these use cases are great reasons to essentially run what the CI server does on your local machine.
IMPORTANT: To do this you must have Docker installed on your machine.
1. `docker run -it --mount type=bind,source="$(pwd)",target=/spring-data-elasticsearch-github adoptopenjdk/openjdk8:latest /bin/bash`
+
This will launch the Docker image and mount your source code at `spring-data-elasticsearch-github`.
+
2. `cd spring-data-elasticsearch-github`
+
Next, run your tests from inside the container:
+
3. `./mvnw clean dependency:list test -Dsort` (or whatever profile you need to test out)
Since the container is binding to your source, you can make edits from your IDE and continue to run build jobs.
If you need to package things up, do this:
1. `docker run -it -v /var/run/docker.sock:/var/run/docker.sock --mount type=bind,source="$(pwd)",target=/spring-data-elasticsearch-github adoptopenjdk/openjdk8:latest /bin/bash`
+
This will launch the Docker image and mount your source code at `spring-data-elasticsearch-github`.
+
2. `cd spring-data-elasticsearch-github`
+
Next, try to package everything up from inside the container:
+
3. `./mvnw -Pci,snapshot -Dmaven.test.skip=true clean package`
NOTE: Docker containers can eat up disk space fast! From time to time, run `docker system prune` to clean out old images.
You can run CI jobs locally using Docker and act[https://nektosact.com/].
Vendored
-132
View File
@@ -1,132 +0,0 @@
def p = [:]
node {
checkout scm
p = readProperties interpolate: true, file: 'ci/pipeline.properties'
}
pipeline {
agent none
triggers {
pollSCM 'H/10 * * * *'
upstream(upstreamProjects: "spring-data-commons/4.0.x", threshold: hudson.model.Result.SUCCESS)
}
options {
disableConcurrentBuilds()
buildDiscarder(logRotator(numToKeepStr: '14'))
}
stages {
stage("test: baseline (main)") {
when {
beforeAgent(true)
anyOf {
branch(pattern: "main|(\\d\\.\\d\\.x)", comparator: "REGEXP")
not { triggeredBy 'UpstreamCause' }
}
}
agent {
label 'data'
}
options { timeout(time: 30, unit: 'MINUTES') }
environment {
ARTIFACTORY = credentials("${p['artifactory.credentials']}")
DEVELOCITY_ACCESS_KEY = credentials("${p['develocity.access-key']}")
}
steps {
script {
docker.withRegistry(p['docker.proxy.registry'], p['docker.proxy.credentials']) {
docker.image(p['docker.java.main.image']).inside(p['docker.java.inside.docker']) {
sh "PROFILE=none JENKINS_USER_NAME=${p['jenkins.user.name']} ci/verify.sh"
sh "JENKINS_USER_NAME=${p['jenkins.user.name']} ci/clean.sh"
}
}
}
}
}
stage("Test other configurations") {
when {
beforeAgent(true)
allOf {
branch(pattern: "main|(\\d\\.\\d\\.x)", comparator: "REGEXP")
not { triggeredBy 'UpstreamCause' }
}
}
parallel {
stage("test: baseline (next)") {
agent {
label 'data'
}
options { timeout(time: 30, unit: 'MINUTES') }
environment {
ARTIFACTORY = credentials("${p['artifactory.credentials']}")
DEVELOCITY_ACCESS_KEY = credentials("${p['develocity.access-key']}")
}
steps {
script {
docker.withRegistry(p['docker.proxy.registry'], p['docker.proxy.credentials']) {
docker.image(p['docker.java.next.image']).inside(p['docker.java.inside.docker']) {
sh "PROFILE=none JENKINS_USER_NAME=${p['jenkins.user.name']} ci/verify.sh"
sh "JENKINS_USER_NAME=${p['jenkins.user.name']} ci/clean.sh"
}
}
}
}
}
}
}
stage('Release to artifactory') {
when {
beforeAgent(true)
anyOf {
branch(pattern: "main|(\\d\\.\\d\\.x)", comparator: "REGEXP")
not { triggeredBy 'UpstreamCause' }
}
}
agent {
label 'data'
}
options { timeout(time: 20, unit: 'MINUTES') }
environment {
ARTIFACTORY = credentials("${p['artifactory.credentials']}")
DEVELOCITY_ACCESS_KEY = credentials("${p['develocity.access-key']}")
}
steps {
script {
docker.withRegistry(p['docker.proxy.registry'], p['docker.proxy.credentials']) {
docker.image(p['docker.java.main.image']).inside(p['docker.java.inside.docker']) {
sh 'MAVEN_OPTS="-Duser.name=' + "${p['jenkins.user.name']}" + ' -Duser.home=/tmp/jenkins-home" ' +
"./mvnw -s settings.xml -Pci,artifactory " +
"-Ddevelocity.storage.directory=/tmp/jenkins-home/.develocity-root " +
"-Dartifactory.server=${p['artifactory.url']} " +
"-Dartifactory.username=${ARTIFACTORY_USR} " +
"-Dartifactory.password=${ARTIFACTORY_PSW} " +
"-Dartifactory.staging-repository=${p['artifactory.repository.snapshot']} " +
"-Dartifactory.build-name=spring-data-elasticsearch " +
"-Dartifactory.build-number=spring-data-elasticsearch-${BRANCH_NAME}-build-${BUILD_NUMBER} " +
"-Dmaven.repo.local=/tmp/jenkins-home/.m2/spring-data-elasticsearch " +
"-Dmaven.test.skip=true clean deploy -U -B"
}
}
}
}
}
}
post {
changed {
script {
emailext(
subject: "[${currentBuild.fullDisplayName}] ${currentBuild.currentResult}",
mimeType: 'text/html',
recipientProviders: [[$class: 'CulpritsRecipientProvider'], [$class: 'RequesterRecipientProvider']],
body: "<a href=\"${env.BUILD_URL}\">${currentBuild.fullDisplayName} is reported as ${currentBuild.currentResult}</a>")
}
}
}
}
+1 -1
View File
@@ -1,4 +1,4 @@
= 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"]
= Spring Data for Elasticsearch 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.
-8
View File
@@ -1,8 +0,0 @@
#!/bin/bash -x
set -euo pipefail
export JENKINS_USER=${JENKINS_USER_NAME}
MAVEN_OPTS="-Duser.name=${JENKINS_USER} -Duser.home=/tmp/jenkins-home" \
./mvnw -s settings.xml clean -Dscan=false -Dmaven.repo.local=/tmp/jenkins-home/.m2/spring-data-elasticsearch -Ddevelocity.storage.directory=/tmp/jenkins-home/.develocity-root
-33
View File
@@ -1,33 +0,0 @@
# Java versions
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}
docker.java.next.image=library/eclipse-temurin:${java.next.tag}
# Supported versions of MongoDB
docker.mongodb.6.0.version=6.0.23
docker.mongodb.7.0.version=7.0.20
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 --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=
docker.credentials=hub.docker.com-springbuildmaster
docker.proxy.registry=https://docker-hub.usw1.packages.broadcom.com
docker.proxy.credentials=usw1_packages_broadcom_com-jenkins-token
artifactory.credentials=02bd1690-b54f-4c9f-819d-a77cb7a9822c
artifactory.url=https://repo.spring.io
artifactory.repository.snapshot=libs-snapshot-local
develocity.access-key=gradle_enterprise_secret_access_key
jenkins.user.name=spring-builds+jenkins
-10
View File
@@ -1,10 +0,0 @@
#!/bin/bash -x
set -euo pipefail
mkdir -p /tmp/jenkins-home/.m2/spring-data-elasticsearch
export JENKINS_USER=${JENKINS_USER_NAME}
MAVEN_OPTS="-Duser.name=${JENKINS_USER} -Duser.home=/tmp/jenkins-home" \
./mvnw -s settings.xml \
-P${PROFILE} clean dependency:list verify -Dsort -U -B -Dmaven.repo.local=/tmp/jenkins-home/.m2/spring-data-elasticsearch -Ddevelocity.storage.directory=/tmp/jenkins-home/.develocity-root
+5 -5
View File
@@ -5,12 +5,12 @@
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-elasticsearch</artifactId>
<version>6.0.2</version>
<version>6.0.5</version>
<parent>
<groupId>org.springframework.data.build</groupId>
<artifactId>spring-data-parent</artifactId>
<version>4.0.2</version>
<version>4.0.5</version>
</parent>
<name>Spring Data Elasticsearch</name>
@@ -18,11 +18,11 @@
<url>https://github.com/spring-projects/spring-data-elasticsearch</url>
<properties>
<springdata.commons>4.0.2</springdata.commons>
<springdata.commons>4.0.5</springdata.commons>
<!-- version of the ElasticsearchClient -->
<elasticsearch-java>9.2.3</elasticsearch-java>
<elasticsearch-rest-client>9.2.3</elasticsearch-rest-client>
<elasticsearch-java>9.2.8</elasticsearch-java>
<elasticsearch-rest-client>9.2.8</elasticsearch-rest-client>
<hoverfly>0.20.2</hoverfly>
<log4j>2.25.1</log4j>
+3 -7
View File
@@ -6,12 +6,8 @@ nav:
ext:
collector:
- run:
command: ./mvnw validate process-resources -am -Pantora-process-resources
command: ./mvnw -B validate process-resources dependency:unpack -am -Pantora-process-resources
local: true
scan:
dir: target/classes/
- run:
command: ./mvnw package -Pdistribute
local: true
scan:
dir: target/antora
- dir: target/classes/
- dir: target/antora/
@@ -6,7 +6,7 @@ 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.1 | 6.0.x | 9.2.8 | 7.0.x
| 2025.0 | 5.5.x | 8.18.1 | 6.2.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
@@ -48,6 +48,7 @@ import co.elastic.clients.elasticsearch.core.search.Rescore;
import co.elastic.clients.elasticsearch.core.search.SearchRequestBody;
import co.elastic.clients.elasticsearch.core.search.SourceConfig;
import co.elastic.clients.elasticsearch.indices.*;
import co.elastic.clients.elasticsearch.indices.ExistsIndexTemplateRequest;
import co.elastic.clients.elasticsearch.indices.ExistsRequest;
import co.elastic.clients.elasticsearch.indices.update_aliases.Action;
import co.elastic.clients.elasticsearch.sql.query.SqlFormat;
@@ -77,15 +78,12 @@ import java.util.stream.Stream;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jspecify.annotations.Nullable;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.core.RefreshPolicy;
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
import org.springframework.data.elasticsearch.core.document.Document;
import org.springframework.data.elasticsearch.core.index.AliasAction;
import org.springframework.data.elasticsearch.core.index.AliasActionParameters;
import org.springframework.data.elasticsearch.core.index.AliasActions;
import org.springframework.data.elasticsearch.core.index.*;
import org.springframework.data.elasticsearch.core.index.DeleteIndexTemplateRequest;
import org.springframework.data.elasticsearch.core.index.DeleteTemplateRequest;
import org.springframework.data.elasticsearch.core.index.ExistsTemplateRequest;
@@ -1065,7 +1063,10 @@ class RequestConverter extends AbstractQueryProcessor {
return UpdateRequest.of(uqb -> {
uqb.index(indexName).id(query.getId());
if (query.getScript() != null) {
var scriptData = query.getScriptData();
var script = scriptData != null ? scriptData.script() : null;
if (script != null) {
Map<String, JsonData> params = new HashMap<>();
if (query.getParams() != null) {
@@ -1073,11 +1074,14 @@ class RequestConverter extends AbstractQueryProcessor {
}
uqb.script(sb -> {
sb.lang(query.getLang()).params(params);
if (query.getScript() != null) {
sb.source(s -> s.scriptString(query.getScript()));
sb
.lang(scriptData.language())
.params(params);
if (script != null) {
sb.source(s -> s.scriptString(script));
}
sb.id(query.getId());
sb.id(scriptData.scriptName());
return sb;
});
@@ -1126,8 +1130,7 @@ class RequestConverter extends AbstractQueryProcessor {
}
return uqb;
} //
);
});
}
public UpdateByQueryRequest documentUpdateByQueryRequest(UpdateQuery updateQuery, IndexCoordinates index,
@@ -15,15 +15,9 @@
*/
package org.springframework.data.elasticsearch.client.elc.aot;
import co.elastic.clients.elasticsearch._types.mapping.RuntimeFieldType;
import co.elastic.clients.elasticsearch._types.mapping.TypeMapping;
import co.elastic.clients.elasticsearch.indices.IndexSettings;
import co.elastic.clients.elasticsearch.indices.PutMappingRequest;
import org.jspecify.annotations.Nullable;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
import org.springframework.aot.hint.TypeReference;
import org.springframework.util.ClassUtils;
/**
@@ -38,10 +32,14 @@ public class ElasticsearchClientRuntimeHints implements RuntimeHintsRegistrar {
public void registerHints(RuntimeHints hints, @Nullable ClassLoader classLoader) {
hints.reflection()
.registerType(TypeReference.of(IndexSettings.class), builder -> builder.withField("_DESERIALIZER"))
.registerType(TypeReference.of(PutMappingRequest.class), builder -> builder.withField("_DESERIALIZER"))
.registerType(TypeReference.of(RuntimeFieldType.class), builder -> builder.withField("_DESERIALIZER"))
.registerType(TypeReference.of(TypeMapping.class), builder -> builder.withField("_DESERIALIZER"));
.registerTypeIfPresent(classLoader, "co.elastic.clients.elasticsearch.indices.IndexSettings",
builder -> builder.withField("_DESERIALIZER"))
.registerTypeIfPresent(classLoader, "co.elastic.clients.elasticsearch.indices.PutMappingRequest",
builder -> builder.withField("_DESERIALIZER"))
.registerTypeIfPresent(classLoader, "co.elastic.clients.elasticsearch._types.mapping.RuntimeFieldType",
builder -> builder.withField("_DESERIALIZER"))
.registerTypeIfPresent(classLoader, "co.elastic.clients.elasticsearch._types.mapping.TypeMapping",
builder -> builder.withField("_DESERIALIZER"));
if (ClassUtils.isPresent("org.apache.http.impl.auth.BasicScheme",
ElasticsearchClientRuntimeHints.class.getClassLoader())) {
@@ -245,7 +245,10 @@ abstract public class AbstractReactiveElasticsearchTemplate
public void onNext(List<T> entityList) {
onNextHasBeenCalled.set(true);
saveAll(entityList, index)
.map(sink::tryEmitNext)
.map(entity -> {
sink.tryEmitNext(entity);
return entity;
})
.doOnComplete(() -> {
if (!upstreamComplete.get()) {
if (subscription == null) {
@@ -255,7 +258,14 @@ abstract public class AbstractReactiveElasticsearchTemplate
} else {
sink.tryEmitComplete();
}
}).subscribe();
})
.subscribe(v -> {
}, error -> {
if (subscription != null) {
subscription.cancel();
}
sink.tryEmitError(error);
});
}
@Override
+4 -1
View File
@@ -1,4 +1,4 @@
Spring Data Elasticsearch 6.0.2 (2025.1.2)
Spring Data Elasticsearch 6.0.5 (2025.1.5)
Copyright (c) [2013-2022] Pivotal Software, Inc.
This product is licensed to you under the Apache License, Version 2.0 (the "License").
@@ -18,3 +18,6 @@ conditions of the subcomponent's license, as noted in the LICENSE file.
@@ -17,6 +17,7 @@ package org.springframework.data.elasticsearch.client.elc;
import static org.assertj.core.api.Assertions.*;
import co.elastic.clients.elasticsearch.core.UpdateRequest;
import co.elastic.clients.json.jackson.JacksonJsonpMapper;
import java.util.List;
@@ -36,6 +37,7 @@ import org.springframework.data.elasticsearch.core.query.CriteriaQuery;
import org.springframework.data.elasticsearch.core.query.DeleteQuery;
import org.springframework.data.elasticsearch.core.query.DocValueField;
import org.springframework.data.elasticsearch.core.query.StringQuery;
import org.springframework.data.elasticsearch.core.query.UpdateQuery;
/**
* @author Peter-Josef Meisch
@@ -96,4 +98,37 @@ class RequestConverterTest {
@Nullable
@Field(type = FieldType.Text) private String text;
}
@Test // #3231
@DisplayName("should not use updatequery id for script id")
void shouldNotUseUpdatequeryIdForScriptId() {
var updateQuery = UpdateQuery
.builder("queryId")
.withScript("script")
.build();
UpdateRequest<org.springframework.data.elasticsearch.core.document.Document, ?> updateRequest = requestConverter
.documentUpdateRequest(updateQuery, IndexCoordinates.of("foo"), null, null);
assertThat(updateRequest.id()).isEqualTo("queryId");
assertThat(updateRequest.script().source().scriptString()).isEqualTo("script");
assertThat(updateRequest.script().id()).isNull();
}
@Test // #3231
@DisplayName("should use script name as update query id")
void shouldUseScriptNameAsUpdateQueryId() {
var updateQuery = UpdateQuery
.builder("queryId")
.withScript("script")
.withScriptName("scriptName")
.build();
UpdateRequest<org.springframework.data.elasticsearch.core.document.Document, ?> updateRequest = requestConverter
.documentUpdateRequest(updateQuery, IndexCoordinates.of("foo"), null, null);
assertThat(updateRequest.id()).isEqualTo("queryId");
assertThat(updateRequest.script().source().scriptString()).isEqualTo("script");
assertThat(updateRequest.script().id()).isEqualTo("scriptName");
}
}
@@ -1220,6 +1220,28 @@ public abstract class ReactiveElasticsearchIntegrationTests {
.allMatch(failureStatus -> failureStatus.status().equals(409));
}
@Test // Error propagation in reactive Flux save
@DisplayName("should propagate errors during Flux save operations")
void shouldPropagateErrorsDuringFluxSaveOperations() {
// Create a Flux that will produce an error after emitting some valid entities
Flux<SampleEntity> entitiesWithError = Flux.concat(
Flux.just(
randomEntity("valid entity 1"),
randomEntity("valid entity 2")),
Flux.error(new RuntimeException("Simulated error during entity creation")));
// The save operation should propagate the error to the subscriber.
// With the manual subscriber approach, the error propagates eagerly
// sink.tryEmitError is called before in-flight saveAll results can be emitted,
// so the caller sees 0 entities before the error.
operations.save(entitiesWithError, SampleEntity.class, 10)
.as(StepVerifier::create)
.expectNextCount(0)
.expectErrorMatches(throwable -> throwable instanceof RuntimeException &&
throwable.getMessage().equals("Simulated error during entity creation"))
.verify();
}
// endregion
// region Helper functions
@@ -15,7 +15,7 @@
#
#
sde.testcontainers.image-name=docker.elastic.co/elasticsearch/elasticsearch
sde.testcontainers.image-version=9.2.3
sde.testcontainers.image-version=9.2.8
#
#
# needed as we do a DELETE /* at the end of the tests, will be required from 8.0 on, produces a warning since 7.13