From 62681335063f0a35042ba25b6f6656a316942ca8 Mon Sep 17 00:00:00 2001 From: Peter-Josef Meisch Date: Sat, 24 May 2025 14:58:04 +0200 Subject: [PATCH 1/5] Update versions documentation Signed-off-by: Peter-Josef Meisch --- .../antora/modules/ROOT/pages/elasticsearch/versions.adoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/antora/modules/ROOT/pages/elasticsearch/versions.adoc b/src/main/antora/modules/ROOT/pages/elasticsearch/versions.adoc index b626405a8..23990e2a7 100644 --- a/src/main/antora/modules/ROOT/pages/elasticsearch/versions.adoc +++ b/src/main/antora/modules/ROOT/pages/elasticsearch/versions.adoc @@ -6,8 +6,8 @@ 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 (in development) | 6.0.x | 8.17.2 | 6.2.x -| 2025.0 | 5.5.x | 8.17.2 | 6.2.x +| 2025.1 (in development) | 6.0.x | 8.18.1 | 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 | 2023.1 (Vaughan) | 5.2.xfootnote:oom[] | 8.11.1 | 6.1.x From 158f5fc342a0933a09ad2beacb17c5b0540e861f Mon Sep 17 00:00:00 2001 From: Laura Trotta <153528055+l-trotta@users.noreply.github.com> Date: Thu, 29 May 2025 15:56:35 +0200 Subject: [PATCH 2/5] es java client major update. Original Pull Request #3116 Closes #3110 Signed-off-by: Laura Trotta --- pom.xml | 2 +- .../client/elc/DocumentAdapters.java | 2 +- .../ReactiveElasticsearchIndicesClient.java | 8 --- .../client/elc/RequestConverter.java | 63 ++++++++++--------- .../client/elc/ResponseConverter.java | 8 +-- .../data/elasticsearch/core/SearchHit.java | 8 +-- .../core/document/SearchDocument.java | 2 +- .../core/document/SearchDocumentAdapter.java | 6 +- .../elasticsearch/core/query/ScriptData.java | 24 ++----- .../elasticsearch/core/query/ScriptType.java | 27 -------- .../elasticsearch/core/query/UpdateQuery.java | 19 ++---- .../core/reindex/ReindexRequest.java | 7 +-- .../elasticsearch/core/script/Script.java | 4 -- .../client/elc/DocumentAdaptersUnitTests.java | 9 +-- .../ElasticsearchELCIntegrationTests.java | 3 +- .../core/ElasticsearchIntegrationTests.java | 1 - ...iptedAndRuntimeFieldsIntegrationTests.java | 2 - ...iptedAndRuntimeFieldsIntegrationTests.java | 2 - .../testcontainers-elasticsearch.properties | 2 +- 19 files changed, 68 insertions(+), 131 deletions(-) delete mode 100644 src/main/java/org/springframework/data/elasticsearch/core/query/ScriptType.java diff --git a/pom.xml b/pom.xml index 5a5bbef47..4396ce5a6 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ 4.0.0-SNAPSHOT - 8.18.1 + 9.0.1 0.19.0 2.23.1 diff --git a/src/main/java/org/springframework/data/elasticsearch/client/elc/DocumentAdapters.java b/src/main/java/org/springframework/data/elasticsearch/client/elc/DocumentAdapters.java index ccb937bf7..ea38dfe58 100644 --- a/src/main/java/org/springframework/data/elasticsearch/client/elc/DocumentAdapters.java +++ b/src/main/java/org/springframework/data/elasticsearch/client/elc/DocumentAdapters.java @@ -83,7 +83,7 @@ public static SearchDocument from(Hit hit, JsonpMapper jsonpMapper) { Explanation explanation = from(hit.explanation()); - List matchedQueries = hit.matchedQueries(); + Map matchedQueries = hit.matchedQueries(); Function, EntityAsMap> fromFields = fields -> { StringBuilder sb = new StringBuilder("{"); diff --git a/src/main/java/org/springframework/data/elasticsearch/client/elc/ReactiveElasticsearchIndicesClient.java b/src/main/java/org/springframework/data/elasticsearch/client/elc/ReactiveElasticsearchIndicesClient.java index e5f6df392..3ebde9776 100644 --- a/src/main/java/org/springframework/data/elasticsearch/client/elc/ReactiveElasticsearchIndicesClient.java +++ b/src/main/java/org/springframework/data/elasticsearch/client/elc/ReactiveElasticsearchIndicesClient.java @@ -539,14 +539,6 @@ public Mono stats() { return stats(builder -> builder); } - public Mono unfreeze(UnfreezeRequest request) { - return Mono.fromFuture(transport.performRequestAsync(request, UnfreezeRequest._ENDPOINT, transportOptions)); - } - - public Mono unfreeze(Function> fn) { - return unfreeze(fn.apply(new UnfreezeRequest.Builder()).build()); - } - public Mono updateAliases(UpdateAliasesRequest request) { return Mono.fromFuture(transport.performRequestAsync(request, UpdateAliasesRequest._ENDPOINT, transportOptions)); } diff --git a/src/main/java/org/springframework/data/elasticsearch/client/elc/RequestConverter.java b/src/main/java/org/springframework/data/elasticsearch/client/elc/RequestConverter.java index a8d8beabe..e1a6c0927 100644 --- a/src/main/java/org/springframework/data/elasticsearch/client/elc/RequestConverter.java +++ b/src/main/java/org/springframework/data/elasticsearch/client/elc/RequestConverter.java @@ -42,10 +42,10 @@ import co.elastic.clients.elasticsearch.core.bulk.IndexOperation; import co.elastic.clients.elasticsearch.core.bulk.UpdateOperation; import co.elastic.clients.elasticsearch.core.mget.MultiGetOperation; -import co.elastic.clients.elasticsearch.core.msearch.MultisearchBody; import co.elastic.clients.elasticsearch.core.msearch.MultisearchHeader; import co.elastic.clients.elasticsearch.core.search.Highlight; 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; @@ -751,11 +751,10 @@ private CreateOperation bulkCreateOperation(IndexQuery query, IndexCoordinate } return co.elastic.clients.elasticsearch._types.Script.of(sb -> { sb.lang(scriptData.language()) - .params(params); - if (scriptData.type() == ScriptType.INLINE) { - sb.source(scriptData.script()); - } else if (scriptData.type() == ScriptType.STORED) { - sb.id(scriptData.script()); + .params(params) + .id(scriptData.scriptName()); + if (scriptData.script() != null){ + sb.source(s -> s.scriptString(scriptData.script())); } return sb; }); @@ -927,9 +926,13 @@ public co.elastic.clients.elasticsearch.core.ReindexRequest reindex(ReindexReque ReindexRequest.Script script = reindexRequest.getScript(); if (script != null) { - builder.script(sb -> sb - .lang(script.getLang()) - .source(script.getSource())); + builder.script(sb -> { + if (script.getSource() != null){ + sb.source(s -> s.scriptString(script.getSource())); + } + sb.lang(script.getLang()); + return sb; + }); } builder.timeout(time(reindexRequest.getTimeout())) // @@ -1086,12 +1089,11 @@ public DeleteByQueryRequest documentDeleteByQueryRequest(DeleteQuery query, @Nul uqb.script(sb -> { sb.lang(query.getLang()).params(params); - - if (query.getScriptType() == ScriptType.INLINE) { - sb.source(query.getScript()); // - } else if (query.getScriptType() == ScriptType.STORED) { - sb.id(query.getScript()); + if (query.getScript() != null){ + sb.source(s -> s.scriptString(query.getScript())); } + sb.id(query.getId()); + return sb; }); } @@ -1254,11 +1256,11 @@ public MsearchTemplateRequest searchMsearchTemplateRequest( mtrb.searchTemplates(stb -> stb .header(msearchHeaderBuilder(query, param.index(), routing)) .body(bb -> { - bb // - .explain(query.getExplain()) // - .id(query.getId()) // - .source(query.getSource()) // - ; + bb.explain(query.getExplain()) // + .id(query.getId()); // + if (query.getSource() != null){ + bb.source(s -> s.scriptString(query.getSource())); + } if (!CollectionUtils.isEmpty(query.getParams())) { Map params = getTemplateParams(query.getParams().entrySet()); @@ -1349,7 +1351,9 @@ public MsearchRequest searchMsearchRequest( if (script != null) { rfb.script(s -> { - s.source(script); + if (script != null) { + s.source(so -> so.scriptString(script)); + } if (runtimeField.getParams() != null) { s.params(TypeUtils.paramsMap(runtimeField.getParams())); @@ -1551,7 +1555,9 @@ private void prepareSearchRequest(Query query, @Nullable String routing, @Nu String script = runtimeField.getScript(); if (script != null) { rfb.script(s -> { - s.source(script); + if (script != null) { + s.source(so -> so.scriptString(script)); + } if (runtimeField.getParams() != null) { s.params(TypeUtils.paramsMap(runtimeField.getParams())); @@ -1648,7 +1654,7 @@ private void addHighlight(Query query, SearchRequest.Builder builder) { builder.highlight(highlight); } - private void addHighlight(Query query, MultisearchBody.Builder builder) { + private void addHighlight(Query query, SearchRequestBody.Builder builder) { Highlight highlight = query.getHighlightQuery() .map(highlightQuery -> new HighlightQueryBuilder(elasticsearchConverter.getMappingContext(), this) @@ -1772,7 +1778,7 @@ private void prepareNativeSearch(NativeQuery query, SearchRequest.Builder builde } @SuppressWarnings("DuplicatedCode") - private void prepareNativeSearch(NativeQuery query, MultisearchBody.Builder builder) { + private void prepareNativeSearch(NativeQuery query, SearchRequestBody.Builder builder) { builder // .suggest(query.getSuggester()) // @@ -1891,10 +1897,11 @@ public SearchTemplateRequest searchTemplate(SearchTemplateQuery query, @Nullable .id(query.getId()) // .index(Arrays.asList(index.getIndexNames())) // .preference(query.getPreference()) // - .searchType(searchType(query.getSearchType())) // - .source(query.getSource()) // - ; + .searchType(searchType(query.getSearchType())); // + if (query.getSource() != null) { + builder.source(so -> so.scriptString(query.getSource())); + } if (query.getRoute() != null) { builder.routing(query.getRoute()); } else if (StringUtils.hasText(routing)) { @@ -1936,8 +1943,8 @@ public PutScriptRequest scriptPut(Script script) { return PutScriptRequest.of(b -> b // .id(script.id()) // .script(sb -> sb // - .lang(script.language()) // - .source(script.source()))); + .lang(script.language()) // + .source(s -> s.scriptString(script.source())))); } public GetScriptRequest scriptGet(String name) { diff --git a/src/main/java/org/springframework/data/elasticsearch/client/elc/ResponseConverter.java b/src/main/java/org/springframework/data/elasticsearch/client/elc/ResponseConverter.java index 7024584f3..771b1104a 100644 --- a/src/main/java/org/springframework/data/elasticsearch/client/elc/ResponseConverter.java +++ b/src/main/java/org/springframework/data/elasticsearch/client/elc/ResponseConverter.java @@ -191,7 +191,7 @@ public Document indicesGetMapping(GetMappingResponse getMappingResponse, IndexCo Assert.notNull(getMappingResponse, "getMappingResponse must not be null"); Assert.notNull(indexCoordinates, "indexCoordinates must not be null"); - Map mappings = getMappingResponse.result(); + Map mappings = getMappingResponse.mappings(); if (mappings == null || mappings.isEmpty()) { return Document.create(); @@ -219,7 +219,7 @@ public List indicesGetIndexInformations(GetIndexResponse getIn List indexInformationList = new ArrayList<>(); - getIndexResponse.result().forEach((indexName, indexState) -> { + getIndexResponse.indices().forEach((indexName, indexState) -> { Settings settings = indexState.settings() != null ? Settings.parse(toJson(indexState.settings(), jsonpMapper)) : new Settings(); Document mappings = indexState.mappings() != null ? Document.parse(toJson(indexState.mappings(), jsonpMapper)) @@ -239,7 +239,7 @@ public Map> indicesGetAliasData(GetAliasResponse getAlias Assert.notNull(getAliasResponse, "getAliasResponse must not be null"); Map> aliasDataMap = new HashMap<>(); - getAliasResponse.result().forEach((indexName, alias) -> { + getAliasResponse.aliases().forEach((indexName, alias) -> { Set aliasDataSet = new HashSet<>(); alias.aliases() .forEach((aliasName, aliasDefinition) -> aliasDataSet.add(indicesGetAliasData(aliasName, aliasDefinition))); @@ -535,7 +535,7 @@ public Script scriptResponse(GetScriptResponse response) { ? Script.builder() // .withId(response.id()) // .withLanguage(response.script().lang()) // - .withSource(response.script().source()).build() // + .withSource(response.script().source().scriptString()).build() // : null; } // endregion diff --git a/src/main/java/org/springframework/data/elasticsearch/core/SearchHit.java b/src/main/java/org/springframework/data/elasticsearch/core/SearchHit.java index da59efdf5..6a6f21920 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/SearchHit.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/SearchHit.java @@ -48,12 +48,12 @@ public class SearchHit { @Nullable private final NestedMetaData nestedMetaData; @Nullable private final String routing; @Nullable private final Explanation explanation; - private final List matchedQueries = new ArrayList<>(); + private final Map matchedQueries = new LinkedHashMap<>(); public SearchHit(@Nullable String index, @Nullable String id, @Nullable String routing, float score, @Nullable Object[] sortValues, @Nullable Map> highlightFields, @Nullable Map> innerHits, @Nullable NestedMetaData nestedMetaData, - @Nullable Explanation explanation, @Nullable List matchedQueries, T content) { + @Nullable Explanation explanation, @Nullable Map matchedQueries, T content) { this.index = index; this.id = id; this.routing = routing; @@ -73,7 +73,7 @@ public SearchHit(@Nullable String index, @Nullable String id, @Nullable String r this.content = content; if (matchedQueries != null) { - this.matchedQueries.addAll(matchedQueries); + this.matchedQueries.putAll(matchedQueries); } } @@ -194,7 +194,7 @@ public Explanation getExplanation() { * @return the matched queries for this SearchHit. */ @Nullable - public List getMatchedQueries() { + public Map getMatchedQueries() { return matchedQueries; } } diff --git a/src/main/java/org/springframework/data/elasticsearch/core/document/SearchDocument.java b/src/main/java/org/springframework/data/elasticsearch/core/document/SearchDocument.java index 63192272e..b51c028e7 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/document/SearchDocument.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/document/SearchDocument.java @@ -125,5 +125,5 @@ default String getRouting() { * @return the matched queries for the SearchHit. */ @Nullable - List getMatchedQueries(); + Map getMatchedQueries(); } diff --git a/src/main/java/org/springframework/data/elasticsearch/core/document/SearchDocumentAdapter.java b/src/main/java/org/springframework/data/elasticsearch/core/document/SearchDocumentAdapter.java index de424c719..4a1bf2f35 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/document/SearchDocumentAdapter.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/document/SearchDocumentAdapter.java @@ -41,12 +41,12 @@ public class SearchDocumentAdapter implements SearchDocument { private final Map innerHits = new HashMap<>(); @Nullable private final NestedMetaData nestedMetaData; @Nullable private final Explanation explanation; - @Nullable private final List matchedQueries; + @Nullable private final Map matchedQueries; @Nullable private final String routing; public SearchDocumentAdapter(Document delegate, float score, Object[] sortValues, Map> fields, Map> highlightFields, Map innerHits, - @Nullable NestedMetaData nestedMetaData, @Nullable Explanation explanation, @Nullable List matchedQueries, + @Nullable NestedMetaData nestedMetaData, @Nullable Explanation explanation, @Nullable Map matchedQueries, @Nullable String routing) { this.delegate = delegate; @@ -249,7 +249,7 @@ public Explanation getExplanation() { @Override @Nullable - public List getMatchedQueries() { + public Map getMatchedQueries() { return matchedQueries; } diff --git a/src/main/java/org/springframework/data/elasticsearch/core/query/ScriptData.java b/src/main/java/org/springframework/data/elasticsearch/core/query/ScriptData.java index 1a81988cd..1597f064f 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/query/ScriptData.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/query/ScriptData.java @@ -27,15 +27,12 @@ * @author Peter-Josef Meisch * @since 4.4 */ -public record ScriptData(ScriptType type, @Nullable String language, @Nullable String script, +public record ScriptData(@Nullable String language, @Nullable String script, @Nullable String scriptName, @Nullable Map params) { - public ScriptData(ScriptType type, @Nullable String language, @Nullable String script, @Nullable String scriptName, + public ScriptData(@Nullable String language, @Nullable String script, @Nullable String scriptName, @Nullable Map params) { - Assert.notNull(type, "type must not be null"); - - this.type = type; this.language = language; this.script = script; this.scriptName = scriptName; @@ -45,9 +42,9 @@ public ScriptData(ScriptType type, @Nullable String language, @Nullable String s /** * @since 5.2 */ - public static ScriptData of(ScriptType type, @Nullable String language, @Nullable String script, + public static ScriptData of(@Nullable String language, @Nullable String script, @Nullable String scriptName, @Nullable Map params) { - return new ScriptData(type, language, script, scriptName, params); + return new ScriptData(language, script, scriptName, params); } public static ScriptData of(Function builderFunction) { @@ -68,7 +65,6 @@ public static Builder builder() { * @since 5.2 */ public static final class Builder { - @Nullable private ScriptType type; @Nullable private String language; @Nullable private String script; @Nullable private String scriptName; @@ -76,14 +72,6 @@ public static final class Builder { private Builder() {} - public Builder withType(ScriptType type) { - - Assert.notNull(type, "type must not be null"); - - this.type = type; - return this; - } - public Builder withLanguage(@Nullable String language) { this.language = language; return this; @@ -106,9 +94,7 @@ public Builder withParams(@Nullable Map params) { public ScriptData build() { - Assert.notNull(type, "type must be set"); - - return new ScriptData(type, language, script, scriptName, params); + return new ScriptData(language, script, scriptName, params); } } } diff --git a/src/main/java/org/springframework/data/elasticsearch/core/query/ScriptType.java b/src/main/java/org/springframework/data/elasticsearch/core/query/ScriptType.java deleted file mode 100644 index 1c6ceecab..000000000 --- a/src/main/java/org/springframework/data/elasticsearch/core/query/ScriptType.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2021-2025 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.data.elasticsearch.core.query; - -/** - * Define script types for update queries. - * - * @author Farid Faoudi - * @since 4.2 - */ - -public enum ScriptType { - INLINE, STORED -} diff --git a/src/main/java/org/springframework/data/elasticsearch/core/query/UpdateQuery.java b/src/main/java/org/springframework/data/elasticsearch/core/query/UpdateQuery.java index 087f0c105..75959bb56 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/query/UpdateQuery.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/query/UpdateQuery.java @@ -76,7 +76,7 @@ private UpdateQuery(String id, @Nullable String script, @Nullable Map searchHit = new Hit.Builder() // .index("index") // .id("42") // - .matchedQueries("query1", "query2") // + .matchedQueries("query1", 1D) // .build(); SearchDocument searchDocument = DocumentAdapters.from(searchHit, jsonpMapper); SoftAssertions softly = new SoftAssertions(); - List matchedQueries = searchDocument.getMatchedQueries(); + Map matchedQueries = searchDocument.getMatchedQueries(); softly.assertThat(matchedQueries).isNotNull(); - softly.assertThat(matchedQueries).hasSize(2); - softly.assertThat(matchedQueries).isEqualTo(Arrays.asList("query1", "query2")); + softly.assertThat(matchedQueries).hasSize(1); + softly.assertThat(matchedQueries).isEqualTo(Map.of("query1",1D)); softly.assertAll(); } } diff --git a/src/test/java/org/springframework/data/elasticsearch/core/ElasticsearchELCIntegrationTests.java b/src/test/java/org/springframework/data/elasticsearch/core/ElasticsearchELCIntegrationTests.java index 884fde8d9..826c2e416 100644 --- a/src/test/java/org/springframework/data/elasticsearch/core/ElasticsearchELCIntegrationTests.java +++ b/src/test/java/org/springframework/data/elasticsearch/core/ElasticsearchELCIntegrationTests.java @@ -46,7 +46,6 @@ import org.springframework.data.elasticsearch.core.query.Query; import org.springframework.data.elasticsearch.core.query.RescorerQuery; import org.springframework.data.elasticsearch.core.query.ScriptData; -import org.springframework.data.elasticsearch.core.query.ScriptType; import org.springframework.data.elasticsearch.core.query.ScriptedField; import org.springframework.data.elasticsearch.junit.jupiter.ElasticsearchTemplateConfiguration; import org.springframework.data.elasticsearch.utils.IndexNameProvider; @@ -183,7 +182,7 @@ protected Query getMatchAllQueryWithIncludesAndInlineExpressionScript(@Nullable return nativeQueryBuilder.withScriptedField(new ScriptedField( // fieldName, // - new ScriptData(ScriptType.INLINE, "expression", script, null, params))) // + new ScriptData( "expression", script, null, params))) // .build(); } diff --git a/src/test/java/org/springframework/data/elasticsearch/core/ElasticsearchIntegrationTests.java b/src/test/java/org/springframework/data/elasticsearch/core/ElasticsearchIntegrationTests.java index 3a2e89212..195b11b3d 100755 --- a/src/test/java/org/springframework/data/elasticsearch/core/ElasticsearchIntegrationTests.java +++ b/src/test/java/org/springframework/data/elasticsearch/core/ElasticsearchIntegrationTests.java @@ -1630,7 +1630,6 @@ void shouldDoUpdateByQueryForExistingDocument() { final Query query = operations.matchAllQuery(); final UpdateQuery updateQuery = UpdateQuery.builder(query) - .withScriptType(ScriptType.INLINE) .withScript("ctx._source['message'] = params['newMessage']").withLang("painless") .withParams(Collections.singletonMap("newMessage", messageAfterUpdate)).withAbortOnVersionConflict(true) .build(); diff --git a/src/test/java/org/springframework/data/elasticsearch/core/query/scriptedandruntimefields/ReactiveScriptedAndRuntimeFieldsIntegrationTests.java b/src/test/java/org/springframework/data/elasticsearch/core/query/scriptedandruntimefields/ReactiveScriptedAndRuntimeFieldsIntegrationTests.java index deef102e0..c17b4a8df 100644 --- a/src/test/java/org/springframework/data/elasticsearch/core/query/scriptedandruntimefields/ReactiveScriptedAndRuntimeFieldsIntegrationTests.java +++ b/src/test/java/org/springframework/data/elasticsearch/core/query/scriptedandruntimefields/ReactiveScriptedAndRuntimeFieldsIntegrationTests.java @@ -48,7 +48,6 @@ import org.springframework.data.elasticsearch.core.query.Query; import org.springframework.data.elasticsearch.core.query.RuntimeField; import org.springframework.data.elasticsearch.core.query.ScriptData; -import org.springframework.data.elasticsearch.core.query.ScriptType; import org.springframework.data.elasticsearch.junit.jupiter.SpringIntegrationTest; import org.springframework.data.elasticsearch.repository.ReactiveElasticsearchRepository; import org.springframework.data.elasticsearch.utils.IndexNameProvider; @@ -165,7 +164,6 @@ private static org.springframework.data.elasticsearch.core.query.ScriptedField g return org.springframework.data.elasticsearch.core.query.ScriptedField.of( fieldName, ScriptData.of(b -> b - .withType(ScriptType.INLINE) .withScript("doc['value'].size() > 0 ? doc['value'].value * params['factor'] : 0") .withParams(Map.of("factor", factor)))); } diff --git a/src/test/java/org/springframework/data/elasticsearch/core/query/scriptedandruntimefields/ScriptedAndRuntimeFieldsIntegrationTests.java b/src/test/java/org/springframework/data/elasticsearch/core/query/scriptedandruntimefields/ScriptedAndRuntimeFieldsIntegrationTests.java index 20f29ab66..d4b147d46 100644 --- a/src/test/java/org/springframework/data/elasticsearch/core/query/scriptedandruntimefields/ScriptedAndRuntimeFieldsIntegrationTests.java +++ b/src/test/java/org/springframework/data/elasticsearch/core/query/scriptedandruntimefields/ScriptedAndRuntimeFieldsIntegrationTests.java @@ -45,7 +45,6 @@ import org.springframework.data.elasticsearch.core.query.Query; import org.springframework.data.elasticsearch.core.query.RuntimeField; import org.springframework.data.elasticsearch.core.query.ScriptData; -import org.springframework.data.elasticsearch.core.query.ScriptType; import org.springframework.data.elasticsearch.junit.jupiter.SpringIntegrationTest; import org.springframework.data.elasticsearch.repository.ElasticsearchRepository; import org.springframework.data.elasticsearch.utils.IndexNameProvider; @@ -314,7 +313,6 @@ private static org.springframework.data.elasticsearch.core.query.ScriptedField b return org.springframework.data.elasticsearch.core.query.ScriptedField.of( fieldName, ScriptData.of(b -> b - .withType(ScriptType.INLINE) .withScript("doc['value'].size() > 0 ? doc['value'].value * params['factor'] : 0") .withParams(Map.of("factor", factor)))); } diff --git a/src/test/resources/testcontainers-elasticsearch.properties b/src/test/resources/testcontainers-elasticsearch.properties index 6860b4150..a16e4a2af 100644 --- a/src/test/resources/testcontainers-elasticsearch.properties +++ b/src/test/resources/testcontainers-elasticsearch.properties @@ -15,7 +15,7 @@ # # sde.testcontainers.image-name=docker.elastic.co/elasticsearch/elasticsearch -sde.testcontainers.image-version=8.18.1 +sde.testcontainers.image-version=9.0.1 # # # 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 From a9d2aaa93dc1c80a74638755ca83b98048e02dbb Mon Sep 17 00:00:00 2001 From: Peter-Josef Meisch Date: Thu, 29 May 2025 18:10:48 +0200 Subject: [PATCH 3/5] Polishing. Signed-off-by: Peter-Josef Meisch --- src/main/antora/modules/ROOT/nav.adoc | 1 + .../elasticsearch/elasticsearch-new.adoc | 8 + .../ROOT/pages/elasticsearch/versions.adoc | 2 +- .../migration-guide-5.5-6.0.adoc | 21 + .../client/elc/DocumentAdapters.java | 382 +++++++++--------- .../elasticsearch/core/query/ScriptData.java | 168 ++++---- .../elasticsearch/core/script/Script.java | 3 + 7 files changed, 321 insertions(+), 264 deletions(-) create mode 100644 src/main/antora/modules/ROOT/pages/migration-guides/migration-guide-5.5-6.0.adoc diff --git a/src/main/antora/modules/ROOT/nav.adoc b/src/main/antora/modules/ROOT/nav.adoc index 53580343a..fa1ee8110 100644 --- a/src/main/antora/modules/ROOT/nav.adoc +++ b/src/main/antora/modules/ROOT/nav.adoc @@ -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[] diff --git a/src/main/antora/modules/ROOT/pages/elasticsearch/elasticsearch-new.adoc b/src/main/antora/modules/ROOT/pages/elasticsearch/elasticsearch-new.adoc index 5dca4fab6..f1e07dd19 100644 --- a/src/main/antora/modules/ROOT/pages/elasticsearch/elasticsearch-new.adoc +++ b/src/main/antora/modules/ROOT/pages/elasticsearch/elasticsearch-new.adoc @@ -1,6 +1,14 @@ [[new-features]] = What's new +[[new-features.6-0-0]] +== New in Spring Data Elasticsearch 6.6 + +* Upgarde to Spring 7 +* Switch to jspecify nullability annotations +* Upgrade to Elasticsearch 9.0.1 + + [[new-features.5-5-0]] == New in Spring Data Elasticsearch 5.5 diff --git a/src/main/antora/modules/ROOT/pages/elasticsearch/versions.adoc b/src/main/antora/modules/ROOT/pages/elasticsearch/versions.adoc index 23990e2a7..8fb6d7261 100644 --- a/src/main/antora/modules/ROOT/pages/elasticsearch/versions.adoc +++ b/src/main/antora/modules/ROOT/pages/elasticsearch/versions.adoc @@ -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 (in development) | 6.0.x | 8.18.1 | 7.0.x +| 2025.1 (in development) | 6.0.x | 9.0.1 | 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 diff --git a/src/main/antora/modules/ROOT/pages/migration-guides/migration-guide-5.5-6.0.adoc b/src/main/antora/modules/ROOT/pages/migration-guides/migration-guide-5.5-6.0.adoc new file mode 100644 index 000000000..7667701a1 --- /dev/null +++ b/src/main/antora/modules/ROOT/pages/migration-guides/migration-guide-5.5-6.0.adoc @@ -0,0 +1,21 @@ +[[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 + +[[elasticsearch-migration-guide-5.5-6.0.deprecations]] +== Deprecations + + +=== 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>) +``` diff --git a/src/main/java/org/springframework/data/elasticsearch/client/elc/DocumentAdapters.java b/src/main/java/org/springframework/data/elasticsearch/client/elc/DocumentAdapters.java index ea38dfe58..53e8cefa7 100644 --- a/src/main/java/org/springframework/data/elasticsearch/client/elc/DocumentAdapters.java +++ b/src/main/java/org/springframework/data/elasticsearch/client/elc/DocumentAdapters.java @@ -24,14 +24,6 @@ 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; @@ -44,6 +36,13 @@ import org.springframework.data.elasticsearch.core.document.SearchDocumentResponse; 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 @@ */ final class DocumentAdapters { - private static final Log LOGGER = LogFactory.getLog(DocumentAdapters.class); - - 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) { - - Assert.notNull(hit, "hit must not be null"); - - Map> highlightFields = hit.highlight(); - - Map 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()); - - Explanation explanation = from(hit.explanation()); - - Map matchedQueries = hit.matchedQueries(); - - Function, 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()); - - Map> documentFields = new LinkedHashMap<>(); - hitFieldsAsMap.forEach((key, value) -> { - if (value instanceof List) { - // noinspection unchecked - documentFields.put(key, (List) 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 { - - 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); - - 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 completionSuggestOption) { - - Document document = completionSuggestOption.source() != null ? Document.from(completionSuggestOption.source()) - : Document.create(); - document.setIndex(completionSuggestOption.index()); - - 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()); - } - - @Nullable - private static Explanation from(co.elastic.clients.elasticsearch.core.explain.@Nullable Explanation explanation) { - - if (explanation == null) { - return null; - } - List 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) { - - List 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) { - - if (nestedIdentity == null) { - return null; - } - - 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 getResponse) { - - Assert.notNull(getResponse, "getResponse must not be 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()); - - if (getResponse.version() != null) { - document.setVersion(getResponse.version()); - } - - if (getResponse.seqNo() != null) { - document.setSeqNo(getResponse.seqNo()); - } - - if (getResponse.primaryTerm() != null) { - document.setPrimaryTerm(getResponse.primaryTerm()); - } - - 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> from(MgetResponse mgetResponse) { - - 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()); - } + private static final Log LOGGER = LogFactory.getLog(DocumentAdapters.class); + + 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) { + + Assert.notNull(hit, "hit must not be null"); + + Map> highlightFields = hit.highlight(); + + Map 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()); + + Explanation explanation = from(hit.explanation()); + + Map matchedQueries = hit.matchedQueries(); + + Function, 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()); + + Map> documentFields = new LinkedHashMap<>(); + hitFieldsAsMap.forEach((key, value) -> { + if (value instanceof List) { + // noinspection unchecked + documentFields.put(key, (List) 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 { + + 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); + + 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 completionSuggestOption) { + + Document document = completionSuggestOption.source() != null ? Document.from(completionSuggestOption.source()) + : Document.create(); + document.setIndex(completionSuggestOption.index()); + + 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()); + } + + @Nullable + private static Explanation from(co.elastic.clients.elasticsearch.core.explain.@Nullable Explanation explanation) { + + if (explanation == null) { + return null; + } + List 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) { + + List 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) { + + if (nestedIdentity == null) { + return null; + } + + 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 getResponse) { + + Assert.notNull(getResponse, "getResponse must not be 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()); + + if (getResponse.version() != null) { + document.setVersion(getResponse.version()); + } + + if (getResponse.seqNo() != null) { + document.setSeqNo(getResponse.seqNo()); + } + + if (getResponse.primaryTerm() != null) { + document.setPrimaryTerm(getResponse.primaryTerm()); + } + + 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> from(MgetResponse mgetResponse) { + + 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()); + } } diff --git a/src/main/java/org/springframework/data/elasticsearch/core/query/ScriptData.java b/src/main/java/org/springframework/data/elasticsearch/core/query/ScriptData.java index 1597f064f..fc81b95d4 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/query/ScriptData.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/query/ScriptData.java @@ -15,86 +15,110 @@ */ package org.springframework.data.elasticsearch.core.query; -import java.util.Map; -import java.util.function.Function; - import org.jspecify.annotations.Nullable; import org.springframework.util.Assert; +import java.util.Map; +import java.util.function.Function; + /** * value class combining script information. + *

+ * A script is either an inline script, then the script parameters must be set + * or it refers to a stored script, then the name parameter is required. * + * @param language the language when the script is passed in the script parameter + * @param script the script to use as inline script + * @param scriptName the name when using a stored script + * @param params the script parameters * @author Peter-Josef Meisch * @since 4.4 */ public record ScriptData(@Nullable String language, @Nullable String script, - @Nullable String scriptName, @Nullable Map params) { - - public ScriptData(@Nullable String language, @Nullable String script, @Nullable String scriptName, - @Nullable Map params) { - - this.language = language; - this.script = script; - this.scriptName = scriptName; - this.params = params; - } - - /** - * @since 5.2 - */ - public static ScriptData of(@Nullable String language, @Nullable String script, - @Nullable String scriptName, @Nullable Map params) { - return new ScriptData(language, script, scriptName, params); - } - - public static ScriptData of(Function builderFunction) { - - Assert.notNull(builderFunction, "f must not be null"); - - return builderFunction.apply(new Builder()).build(); - } - - /** - * @since 5.2 - */ - public static Builder builder() { - return new Builder(); - } - - /** - * @since 5.2 - */ - public static final class Builder { - @Nullable private String language; - @Nullable private String script; - @Nullable private String scriptName; - @Nullable private Map params; - - private Builder() {} - - public Builder withLanguage(@Nullable String language) { - this.language = language; - return this; - } - - public Builder withScript(@Nullable String script) { - this.script = script; - return this; - } - - public Builder withScriptName(@Nullable String scriptName) { - this.scriptName = scriptName; - return this; - } - - public Builder withParams(@Nullable Map params) { - this.params = params; - return this; - } - - public ScriptData build() { - - return new ScriptData(language, script, scriptName, params); - } - } + @Nullable String scriptName, @Nullable Map params) { + + /* + * constructor overload to check the parameters + */ + public ScriptData(@Nullable String language, @Nullable String script, @Nullable String scriptName, + @Nullable Map params) { + + Assert.isTrue(script != null || scriptName != null, "script or scriptName is required"); + + this.language = language; + this.script = script; + this.scriptName = scriptName; + this.params = params; + } + + /** + * factory method to create a ScriptData object. + * + * @since 5.2 + */ + public static ScriptData of(@Nullable String language, @Nullable String script, + @Nullable String scriptName, @Nullable Map params) { + return new ScriptData(language, script, scriptName, params); + } + + /** + * factory method to create a ScriptData object using a ScriptBuilder callback. + * + * @param builderFunction function called to populate the builder + * @return + */ + public static ScriptData of(Function builderFunction) { + + Assert.notNull(builderFunction, "builderFunction must not be null"); + + return builderFunction.apply(new Builder()).build(); + } + + /** + * @since 5.2 + */ + public static Builder builder() { + return new Builder(); + } + + /** + * @since 5.2 + */ + public static final class Builder { + @Nullable + private String language; + @Nullable + private String script; + @Nullable + private String scriptName; + @Nullable + private Map params; + + private Builder() { + } + + public Builder withLanguage(@Nullable String language) { + this.language = language; + return this; + } + + public Builder withScript(@Nullable String script) { + this.script = script; + return this; + } + + public Builder withScriptName(@Nullable String scriptName) { + this.scriptName = scriptName; + return this; + } + + public Builder withParams(@Nullable Map params) { + this.params = params; + return this; + } + + public ScriptData build() { + return new ScriptData(language, script, scriptName, params); + } + } } diff --git a/src/main/java/org/springframework/data/elasticsearch/core/script/Script.java b/src/main/java/org/springframework/data/elasticsearch/core/script/Script.java index b1f35896b..1f29c6c22 100644 --- a/src/main/java/org/springframework/data/elasticsearch/core/script/Script.java +++ b/src/main/java/org/springframework/data/elasticsearch/core/script/Script.java @@ -28,6 +28,7 @@ public record Script(String id, String language, String source) { Assert.notNull(id, "id must not be null"); Assert.notNull(language, "language must not be null"); + Assert.notNull(source, "source must not be null"); } public static ScriptBuilder builder() { @@ -60,6 +61,8 @@ public ScriptBuilder withLanguage(String language) { public ScriptBuilder withSource(String source) { + Assert.notNull(source, "source must not be null"); + this.source = source; return this; } From 7f53944e1b51f5bd044b5da9b0b0002ed3d1f7fb Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Thu, 12 Jun 2025 09:14:22 +0200 Subject: [PATCH 4/5] Adapt to generics changes in `CoroutineCrudRepository`. Closes #3118 --- .../repository/CoroutineElasticsearchRepository.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/org/springframework/data/elasticsearch/repository/CoroutineElasticsearchRepository.kt b/src/main/kotlin/org/springframework/data/elasticsearch/repository/CoroutineElasticsearchRepository.kt index 221db17db..79c932fea 100644 --- a/src/main/kotlin/org/springframework/data/elasticsearch/repository/CoroutineElasticsearchRepository.kt +++ b/src/main/kotlin/org/springframework/data/elasticsearch/repository/CoroutineElasticsearchRepository.kt @@ -24,4 +24,4 @@ import org.springframework.data.repository.kotlin.CoroutineSortingRepository * @since 5.2 */ @NoRepositoryBean -interface CoroutineElasticsearchRepository : CoroutineCrudRepository, CoroutineSortingRepository +interface CoroutineElasticsearchRepository : CoroutineCrudRepository, CoroutineSortingRepository From f9509f26965235880c92b6a058d2b4ea8ceb7bdf Mon Sep 17 00:00:00 2001 From: Peter-Josef Meisch Date: Sat, 14 Jun 2025 17:30:22 +0200 Subject: [PATCH 5/5] Upgrade to Elasticsearch 9.0.2. Original Pull Request #3122 Closes #3121 Signed-off-by: Peter-Josef Meisch --- pom.xml | 2 +- .../modules/ROOT/pages/elasticsearch/elasticsearch-new.adoc | 4 ++-- .../antora/modules/ROOT/pages/elasticsearch/versions.adoc | 2 +- src/test/resources/testcontainers-elasticsearch.properties | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pom.xml b/pom.xml index 4396ce5a6..4fcfd20c4 100644 --- a/pom.xml +++ b/pom.xml @@ -21,7 +21,7 @@ 4.0.0-SNAPSHOT - 9.0.1 + 9.0.2 0.19.0 2.23.1 diff --git a/src/main/antora/modules/ROOT/pages/elasticsearch/elasticsearch-new.adoc b/src/main/antora/modules/ROOT/pages/elasticsearch/elasticsearch-new.adoc index f1e07dd19..d4a9c565d 100644 --- a/src/main/antora/modules/ROOT/pages/elasticsearch/elasticsearch-new.adoc +++ b/src/main/antora/modules/ROOT/pages/elasticsearch/elasticsearch-new.adoc @@ -2,11 +2,11 @@ = What's new [[new-features.6-0-0]] -== New in Spring Data Elasticsearch 6.6 +== New in Spring Data Elasticsearch 6.0 * Upgarde to Spring 7 * Switch to jspecify nullability annotations -* Upgrade to Elasticsearch 9.0.1 +* Upgrade to Elasticsearch 9.0.2 [[new-features.5-5-0]] diff --git a/src/main/antora/modules/ROOT/pages/elasticsearch/versions.adoc b/src/main/antora/modules/ROOT/pages/elasticsearch/versions.adoc index 8fb6d7261..861e2ff3b 100644 --- a/src/main/antora/modules/ROOT/pages/elasticsearch/versions.adoc +++ b/src/main/antora/modules/ROOT/pages/elasticsearch/versions.adoc @@ -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 (in development) | 6.0.x | 9.0.1 | 7.0.x +| 2025.1 (in development) | 6.0.x | 9.0.2 | 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 diff --git a/src/test/resources/testcontainers-elasticsearch.properties b/src/test/resources/testcontainers-elasticsearch.properties index a16e4a2af..8784f82c3 100644 --- a/src/test/resources/testcontainers-elasticsearch.properties +++ b/src/test/resources/testcontainers-elasticsearch.properties @@ -15,7 +15,7 @@ # # sde.testcontainers.image-name=docker.elastic.co/elasticsearch/elasticsearch -sde.testcontainers.image-version=9.0.1 +sde.testcontainers.image-version=9.0.2 # # # 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