1
0
mirror of synced 2026-05-23 20:53:17 +00:00

Compare commits

...

21 Commits

Author SHA1 Message Date
Peter-Josef Meisch 6654eaa38f Upgrade Elasticsearch client to 9.4.1.
Closes #3288

Signed-off-by: Peter-Josef Meisch <pj.meisch@sothawo.com>
2026-05-22 22:00:04 +02:00
Peter-Josef Meisch ebdc57e4b2 Update documentation.
Closes #3286

Signed-off-by: Peter-Josef Meisch <pj.meisch@sothawo.com>
2026-05-09 17:57:50 +02:00
Peter-Josef Meisch 4cbfef39c6 Upgrade to Elasticsearch 9.4.0.
Closes #3284

Signed-off-by: Peter-Josef Meisch <pj.meisch@sothawo.com>
2026-05-09 17:50:47 +02:00
Peter-Josef Meisch 8ad2e8e0a0 nullability-fixes
Closes #3282

Signed-off-by: Peter-Josef Meisch <pj.meisch@sothawo.com>
2026-05-02 11:20:02 +02:00
Steven 795e1ef60a Refactor routing and null handling with a new getRouting methods. 2026-04-26 08:02:09 +02:00
Peter-Josef Meisch a08ffc85cf fix passing null routing to Elasticsearch's builder.
Closes #3278

Signed-off-by: Peter-Josef Meisch <pj.meisch@sothawo.com>
2026-04-22 20:43:52 +02:00
Mark Paluch c3eb590afe After release cleanups.
See #3258
2026-04-17 17:14:29 +02:00
Mark Paluch fa065c1f27 Prepare next development iteration.
See #3258
2026-04-17 17:14:28 +02:00
Mark Paluch 5706fc0d3f Release version 6.1 RC1 (2026.0.0).
See #3258
2026-04-17 17:12:04 +02:00
Mark Paluch ad68771825 Prepare 6.1 RC1 (2026.0.0).
See #3258
2026-04-17 17:11:42 +02:00
Peter-Josef Meisch eb5c6872d9 Upgrade Elasticsearch to 9.3.3/9.3.4
Signed-off-by: Peter-Josef Meisch <pj.meisch@sothawo.com>
2026-04-16 23:34:49 +02:00
dependabot[bot] 4ee59bb52f Bump org.apache.logging.log4j:log4j-core from 2.25.3 to 2.25.4
Bumps org.apache.logging.log4j:log4j-core from 2.25.3 to 2.25.4.

---
updated-dependencies:
- dependency-name: org.apache.logging.log4j:log4j-core
  dependency-version: 2.25.4
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-11 12:35:30 +02:00
Ralph Ursprung ffdbea4dba Make AOT hints for ELC optional.
see also opensearch-project/spring-data-opensearch#441

Signed-off-by: Ralph Ursprung <Ralph.Ursprung@avaloq.com>
2026-03-30 20:16:14 +02:00
Peter-Josef Meisch 7c1bc087ba Polishing
Signed-off-by: Peter-Josef Meisch <pj.meisch@sothawo.com>
2026-03-29 18:39:28 +02:00
rafareborn 475df8ef80 Clarify that interface-based projections are not supported.
Closes #3261

Signed-off-by: hxreborn <hxreborn@duck.com>
2026-03-29 18:37:31 +02:00
Peter-Josef Meisch 78bef3105c Upgrade Elasticsearch client to 9.3.3.
Closes #3262

Signed-off-by: Peter-Josef Meisch <pj.meisch@sothawo.com>
2026-03-22 16:54:55 +01:00
Peter-Josef Meisch 81d40611b9 Upgrade Elasticsearch client to 9.3.2.
Closes #3259

Signed-off-by: Peter-Josef Meisch <pj.meisch@sothawo.com>
2026-03-14 13:29:57 +01:00
Peter-Josef Meisch 446869154f Polishing 2026-03-14 13:10:51 +01:00
Andriy Redko 836187c170 Allow to customize mappings parameters.
Signed-off-by: Andriy Redko <drreta@gmail.com>
2026-03-14 13:07:01 +01:00
Christoph Strobl 87427d96a2 After release cleanups.
See #3244
2026-03-13 14:23:21 +01:00
Christoph Strobl 4803ac2f98 Prepare next development iteration.
See #3244
2026-03-13 14:23:19 +01:00
214 changed files with 2724 additions and 921 deletions
+20 -8
View File
@@ -5,12 +5,12 @@
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-elasticsearch</artifactId>
<version>6.1.0-M2</version>
<version>6.1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.data.build</groupId>
<artifactId>spring-data-parent</artifactId>
<version>4.1.0-M2</version>
<version>4.1.0-SNAPSHOT</version>
</parent>
<name>Spring Data Elasticsearch</name>
@@ -18,14 +18,14 @@
<url>https://github.com/spring-projects/spring-data-elasticsearch</url>
<properties>
<springdata.commons>4.1.0-M2</springdata.commons>
<springdata.commons>4.1.0-SNAPSHOT</springdata.commons>
<!-- version of the ElasticsearchClient -->
<elasticsearch-java>9.3.1</elasticsearch-java>
<elasticsearch-rest-client>9.3.1</elasticsearch-rest-client>
<elasticsearch-java>9.4.1</elasticsearch-java>
<elasticsearch-rest-client>9.4.1</elasticsearch-rest-client>
<hoverfly>0.20.2</hoverfly>
<log4j>2.25.3</log4j>
<log4j>2.25.4</log4j>
<jsonassert>1.5.3</jsonassert>
<wiremock>3.9.2</wiremock>
@@ -499,8 +499,20 @@
</profiles>
<repositories>
<repository>
<id>spring-snapshot</id>
<url>https://repo.spring.io/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
<releases>
<enabled>false</enabled>
</releases>
</repository>
<repository>
<id>spring-milestone</id>
<url>https://repo.spring.io/milestone</url>
</repository>
</repositories>
</project>
@@ -4,7 +4,7 @@
[[new-features.6-1-0]]
== New in Spring Data Elasticsearch 6.1
* Upgrade to Elasticsearch 9.3.1
* Upgrade to Elasticsearch 9.4.1
* Add support to use `IndexCoordinates` as repository query parameter
* Add support for includeNamedQueriesScore in Query
* Add support for Micrometer observation.
@@ -6,10 +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
| 2026.0 | 6.1.x | 9.3.1 | 7.0.x
| 2026.0 | 6.1.x | 9.4.1 | 7.0.x
| 2025.1 | 6.0.x | 9.2.2 | 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
| 2025.0 | 5.5.xfootnote:oom[Out of maintenance] | 8.18.1 | 6.2.x
| 2024.1 | 5.4.xfootnote:oom[] | 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
@@ -1,4 +1,13 @@
[[elasticsearch.projections]]
= Projections
[[elasticsearch.projections.limitations]]
== Spring Data Elasticsearch Projection Limitations
This chapter is pulled in from the Spring Data Commons documentation, but does not apply to Spring Data Elasticsearch.
IMPORTANT: Interface-based projections are not supported in Spring Data Elasticsearch repository query methods.
To limit the fields returned from Elasticsearch, use the xref:elasticsearch/repositories/elasticsearch-repositories.adoc#elasticsearch.repositories.annotations.sourcefilters[`@SourceFilters`] annotation on your repository methods instead.
include::{commons}@data-commons::page$repositories/projections.adoc[leveloffset=+1]
@@ -15,10 +15,11 @@
*/
package org.springframework.data.elasticsearch;
import org.springframework.dao.DataRetrievalFailureException;
import java.util.Map;
import org.jspecify.annotations.Nullable;
import org.springframework.dao.DataRetrievalFailureException;
/**
* @author Peter-Josef Meisch
* @author Illia Ulianov
@@ -42,6 +43,6 @@ public class BulkFailureException extends DataRetrievalFailureException {
* @author Illia Ulianov
* @since 5.2
*/
public record FailureDetails(Integer status, String errorMessage) {
public record FailureDetails(Integer status, @Nullable String errorMessage) {
}
}
@@ -28,7 +28,7 @@ import org.jspecify.annotations.Nullable;
public class ElasticsearchErrorCause {
@Nullable private final String type;
private final String reason;
@Nullable private final String reason;
@Nullable private final String stackTrace;
@@ -38,7 +38,7 @@ public class ElasticsearchErrorCause {
private final List<ElasticsearchErrorCause> suppressed;
public ElasticsearchErrorCause(@Nullable String type, String reason, @Nullable String stackTrace,
public ElasticsearchErrorCause(@Nullable String type, @Nullable String reason, @Nullable String stackTrace,
@Nullable ElasticsearchErrorCause causedBy, List<ElasticsearchErrorCause> rootCause,
List<ElasticsearchErrorCause> suppressed) {
this.type = type;
@@ -54,7 +54,7 @@ public class ElasticsearchErrorCause {
return type;
}
public String getReason() {
public @Nullable String getReason() {
return reason;
}
@@ -1,2 +1,18 @@
/*
* 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.
* 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.
*/
@org.jspecify.annotations.NullMarked
package org.springframework.data.elasticsearch.annotations;
@@ -1,2 +1,18 @@
/*
* 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.
* 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.
*/
@org.jspecify.annotations.NullMarked
package org.springframework.data.elasticsearch.aot;
@@ -24,6 +24,14 @@ 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;
@@ -36,13 +44,6 @@ import org.springframework.data.elasticsearch.core.document.SearchDocumentAdapte
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}
@@ -54,188 +55,187 @@ import java.util.stream.Collectors;
*/
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());
Map<String, Double> 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<@Nullable 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(co.elastic.clients.elasticsearch.core.explain.@Nullable 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());
}
}
@@ -114,7 +114,7 @@ public class IndicesTemplate extends ChildTemplate<ElasticsearchTransport, Elast
}
@Override
public boolean create(Map<String, Object> settings) {
public boolean create(Map<String, @Nullable Object> settings) {
Assert.notNull(settings, "settings must not be null");
@@ -122,7 +122,7 @@ public class IndicesTemplate extends ChildTemplate<ElasticsearchTransport, Elast
}
@Override
public boolean create(Map<String, Object> settings, Document mapping) {
public boolean create(Map<String, @Nullable Object> settings, Document mapping) {
Assert.notNull(settings, "settings must not be null");
Assert.notNull(mapping, "mapping must not be null");
@@ -135,7 +135,7 @@ public class IndicesTemplate extends ChildTemplate<ElasticsearchTransport, Elast
return doCreate(getIndexCoordinates(), createSettings(), createMapping());
}
protected boolean doCreate(IndexCoordinates indexCoordinates, Map<String, Object> settings,
protected boolean doCreate(IndexCoordinates indexCoordinates, Map<String, @Nullable Object> settings,
@Nullable Document mapping) {
Set<Alias> aliases = (boundClass != null) ? getAliasesFor(boundClass) : new HashSet<>();
CreateIndexSettings indexSettings = CreateIndexSettings.builder(indexCoordinates)
@@ -233,7 +233,7 @@ public class IndicesTemplate extends ChildTemplate<ElasticsearchTransport, Elast
}
@Override
public Map<String, Object> getMapping() {
public Map<String, @Nullable Object> getMapping() {
IndexCoordinates indexCoordinates = getIndexCoordinates();
GetMappingRequest getMappingRequest = requestConverter.indicesGetMappingRequest(indexCoordinates);
@@ -18,9 +18,30 @@ package org.springframework.data.elasticsearch.client.elc;
import static co.elastic.clients.util.ApiTypeHelper.*;
import static org.springframework.data.elasticsearch.client.elc.TypeUtils.*;
import co.elastic.clients.elasticsearch._types.Result;
import co.elastic.clients.elasticsearch.core.*;
import co.elastic.clients.elasticsearch.core.bulk.BulkResponseItem;
import co.elastic.clients.elasticsearch.core.search.ResponseBody;
import co.elastic.clients.json.JsonpMapper;
import co.elastic.clients.transport.Version;
import co.elastic.clients.transport.endpoints.BooleanResponse;
import io.micrometer.observation.Observation;
import io.micrometer.observation.ObservationRegistry;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.util.function.Tuple2;
import java.time.Duration;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.BiFunction;
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.NonNull;
import org.jspecify.annotations.Nullable;
import org.reactivestreams.Publisher;
import org.springframework.beans.BeansException;
@@ -52,28 +73,6 @@ import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import java.time.Duration;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.stream.Collectors;
import co.elastic.clients.elasticsearch._types.Result;
import co.elastic.clients.elasticsearch.core.*;
import co.elastic.clients.elasticsearch.core.bulk.BulkResponseItem;
import co.elastic.clients.elasticsearch.core.search.ResponseBody;
import co.elastic.clients.json.JsonpMapper;
import co.elastic.clients.transport.Version;
import co.elastic.clients.transport.endpoints.BooleanResponse;
import io.micrometer.observation.Observation;
import io.micrometer.observation.ObservationRegistry;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.util.function.Tuple2;
/**
* Implementation of {@link org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperations} using the new
* Elasticsearch client.
@@ -269,7 +268,7 @@ public class ReactiveElasticsearchTemplate extends AbstractReactiveElasticsearch
ExistsRequest existsRequest = requestConverter.documentExistsRequest(id, routingResolver.getRouting(), index);
return Mono.from(execute(
((ClientCallback<@NonNull Publisher<BooleanResponse>>) client -> client.exists(existsRequest))))
((ClientCallback<Publisher<BooleanResponse>>) client -> client.exists(existsRequest))))
.map(BooleanResponse::value) //
.onErrorReturn(NoSuchIndexException.class, false);
}
@@ -381,7 +380,7 @@ public class ReactiveElasticsearchTemplate extends AbstractReactiveElasticsearch
for (BulkResponseItem item : bulkResponse.items()) {
if (item.error() != null) {
if (item.error() != null && item.id() != null) {
failedDocuments.put(item.id(), new BulkFailureException.FailureDetails(item.status(), item.error().reason()));
}
}
@@ -538,7 +537,7 @@ public class ReactiveElasticsearchTemplate extends AbstractReactiveElasticsearch
return Mono.empty();
}
List<Object> sortOptions = hits.get(hits.size() - 1).sort().stream().map(TypeUtils::toObject)
List<Object> sortOptions = hits.get(hits.size() - 1).sort().stream().map(TypeUtils::toObjectNotNull)
.collect(Collectors.toList());
baseQuery.setSearchAfter(sortOptions);
SearchRequest followSearchRequest = requestConverter.searchRequest(baseQuery,
@@ -632,8 +631,8 @@ public class ReactiveElasticsearchTemplate extends AbstractReactiveElasticsearch
SearchRequest searchRequest = requestConverter.searchRequest(query, routingResolver.getRouting(), clazz, index,
false);
// noinspection unchecked
SearchDocumentCallback<T> callback = new ReadSearchDocumentCallback<>((Class<T>) clazz, index);
SearchDocumentResponse.EntityCreator<T> entityCreator = searchDocument -> callback.toEntity(searchDocument)
.toFuture();
@@ -108,7 +108,7 @@ public class ReactiveIndicesTemplate
}
@Override
public Mono<Boolean> create(Map<String, Object> settings) {
public Mono<Boolean> create(Map<String, @Nullable Object> settings) {
Assert.notNull(settings, "settings must not be null");
@@ -116,7 +116,7 @@ public class ReactiveIndicesTemplate
}
@Override
public Mono<Boolean> create(Map<String, Object> settings, Document mapping) {
public Mono<Boolean> create(Map<String, @Nullable Object> settings, Document mapping) {
Assert.notNull(settings, "settings must not be null");
Assert.notNull(mapping, "mapping must not be null");
@@ -132,7 +132,7 @@ public class ReactiveIndicesTemplate
doCreate(getIndexCoordinates(), settings, mapping))); //
}
private Mono<Boolean> doCreate(IndexCoordinates indexCoordinates, Map<String, Object> settings,
private Mono<Boolean> doCreate(IndexCoordinates indexCoordinates, Map<String, @Nullable Object> settings,
@Nullable Document mapping) {
Set<Alias> aliases = (boundClass != null) ? getAliasesFor(boundClass) : new HashSet<>();
CreateIndexSettings indexSettings = CreateIndexSettings.builder(indexCoordinates)
@@ -270,7 +270,7 @@ public class ReactiveIndicesTemplate
return getAliases(null, indexNames);
}
private Mono<Map<String, Set<AliasData>>> getAliases(@Nullable String[] aliasNames, @Nullable String[] indexNames) {
private Mono<Map<String, Set<AliasData>>> getAliases(String@Nullable [] aliasNames, String@Nullable [] indexNames) {
GetAliasRequest getAliasRequest = requestConverter.indicesGetAliasRequest(aliasNames, indexNames);
Mono<GetAliasResponse> getAliasResponse = Mono.from(execute(client -> client.getAlias(getAliasRequest)));
@@ -74,6 +74,7 @@ import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.Optional;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -113,6 +114,7 @@ import org.springframework.util.StringUtils;
* @author cdalxndr
* @author scoobyzhang
* @author Haibo Liu
* @author Steven Pearce
* @since 4.4
*/
class RequestConverter extends AbstractQueryProcessor {
@@ -173,17 +175,9 @@ class RequestConverter extends AbstractQueryProcessor {
private co.elastic.clients.elasticsearch.indices.Alias.Builder buildAlias(AliasActionParameters parameters,
co.elastic.clients.elasticsearch.indices.Alias.Builder aliasBuilder) {
if (parameters.getRouting() != null) {
aliasBuilder.routing(parameters.getRouting());
}
if (parameters.getIndexRouting() != null) {
aliasBuilder.indexRouting(parameters.getIndexRouting());
}
if (parameters.getSearchRouting() != null) {
aliasBuilder.searchRouting(parameters.getSearchRouting());
}
getRouting(parameters.getRouting()).ifPresent(aliasBuilder::routing);
getRouting(parameters.getIndexRouting()).ifPresent(aliasBuilder::indexRouting);
getRouting(parameters.getSearchRouting()).ifPresent(aliasBuilder::searchRouting);
if (parameters.getHidden() != null) {
aliasBuilder.isHidden(parameters.getHidden());
@@ -239,12 +233,16 @@ class RequestConverter extends AbstractQueryProcessor {
Map<String, co.elastic.clients.elasticsearch.indices.Alias> aliases = new HashMap<>();
for (Alias alias : indexSettings.getAliases()) {
co.elastic.clients.elasticsearch.indices.Alias esAlias = co.elastic.clients.elasticsearch.indices.Alias
.of(ab -> ab.filter(getQuery(alias.getFilter(), null))
.routing(alias.getRouting())
.indexRouting(alias.getIndexRouting())
.searchRouting(alias.getSearchRouting())
.isHidden(alias.getHidden())
.isWriteIndex(alias.getWriteIndex()));
.of(ab -> {
co.elastic.clients.elasticsearch.indices.Alias.Builder aliasBuilder = ab.filter(getQuery(alias.getFilter(), null))
.isHidden(alias.getHidden())
.isWriteIndex(alias.getWriteIndex());
getRouting(alias.getRouting()).ifPresent(aliasBuilder::routing);
getRouting(alias.getIndexRouting()).ifPresent(aliasBuilder::indexRouting);
getRouting(alias.getSearchRouting()).ifPresent(aliasBuilder::searchRouting);
return aliasBuilder;
});
aliases.put(alias.getAlias(), esAlias);
}
@@ -318,10 +316,11 @@ class RequestConverter extends AbstractQueryProcessor {
addActionBuilder //
.indices(Arrays.asList(parameters.getIndices())) //
.isHidden(parameters.getHidden()) //
.isWriteIndex(parameters.getWriteIndex()) //
.routing(parameters.getRouting()) //
.indexRouting(parameters.getIndexRouting()) //
.searchRouting(parameters.getSearchRouting()); //
.isWriteIndex(parameters.getWriteIndex()); //
getRouting(parameters.getRouting()).ifPresent(addActionBuilder::routing);
getRouting(parameters.getIndexRouting()).ifPresent(addActionBuilder::indexRouting);
getRouting(parameters.getSearchRouting()).ifPresent(addActionBuilder::searchRouting);
if (parameters.getAliases() != null) {
addActionBuilder.aliases(Arrays.asList(parameters.getAliases()));
@@ -589,10 +588,11 @@ class RequestConverter extends AbstractQueryProcessor {
builder.version(query.getVersion()).versionType(versionType);
}
builder //
.ifSeqNo(query.getSeqNo()) //
.ifPrimaryTerm(query.getPrimaryTerm()) //
.routing(query.getRouting()); //
builder
.ifSeqNo(query.getSeqNo())
.ifPrimaryTerm(query.getPrimaryTerm());
getRouting(query.getRouting()).ifPresent(builder::routing);
if (query.getOpType() != null) {
switch (query.getOpType()) {
@@ -642,8 +642,9 @@ class RequestConverter extends AbstractQueryProcessor {
builder //
.ifSeqNo(query.getSeqNo()) //
.ifPrimaryTerm(query.getPrimaryTerm()) //
.routing(query.getRouting()); //
.ifPrimaryTerm(query.getPrimaryTerm()); //
getRouting(query.getRouting()).ifPresent(builder::routing);
return builder.build();
}
@@ -684,8 +685,9 @@ class RequestConverter extends AbstractQueryProcessor {
builder //
.ifSeqNo(query.getSeqNo()) //
.ifPrimaryTerm(query.getPrimaryTerm()) //
.routing(query.getRouting()); //
.ifPrimaryTerm(query.getPrimaryTerm()); //
getRouting(query.getRouting()).ifPresent(builder::routing);
return builder.build();
}
@@ -722,11 +724,12 @@ class RequestConverter extends AbstractQueryProcessor {
});
uob
.routing(query.getRouting())
.ifSeqNo(query.getIfSeqNo())
.ifPrimaryTerm(query.getIfPrimaryTerm())
.retryOnConflict(query.getRetryOnConflict());
getRouting(query.getRouting()).ifPresent(uob::routing);
// no refresh, timeout, waitForActiveShards on UpdateOperation or UpdateAction
return uob.build();
@@ -776,9 +779,7 @@ class RequestConverter extends AbstractQueryProcessor {
builder.pipeline(bulkOptions.getPipeline());
}
if (bulkOptions.getRoutingId() != null) {
builder.routing(bulkOptions.getRoutingId());
}
getRouting(bulkOptions.getRoutingId()).ifPresent(builder::routing);
List<BulkOperation> operations = queries.stream().map(query -> {
BulkOperation.Builder ob = new BulkOperation.Builder();
@@ -805,10 +806,13 @@ class RequestConverter extends AbstractQueryProcessor {
Assert.notNull(id, "id must not be null");
Assert.notNull(indexCoordinates, "indexCoordinates must not be null");
return GetRequest.of(grb -> grb //
.index(indexCoordinates.getIndexName()) //
.id(id) //
.routing(routing));
return GetRequest.of(grb -> {
GetRequest.Builder builder = grb //
.index(indexCoordinates.getIndexName()) //
.id(id); //
getRouting(routing).ifPresent(builder::routing);
return builder;
});
}
public co.elastic.clients.elasticsearch.core.ExistsRequest documentExistsRequest(String id, @Nullable String routing,
@@ -817,10 +821,13 @@ class RequestConverter extends AbstractQueryProcessor {
Assert.notNull(id, "id must not be null");
Assert.notNull(indexCoordinates, "indexCoordinates must not be null");
return co.elastic.clients.elasticsearch.core.ExistsRequest.of(erb -> erb
.index(indexCoordinates.getIndexName())
.id(id)
.routing(routing));
return co.elastic.clients.elasticsearch.core.ExistsRequest.of(erb -> {
co.elastic.clients.elasticsearch.core.ExistsRequest.Builder builder = erb
.index(indexCoordinates.getIndexName())
.id(id);
getRouting(routing).ifPresent(builder::routing);
return builder;
});
}
public <T> MgetRequest documentMgetRequest(Query query, Class<T> clazz, IndexCoordinates index) {
@@ -838,11 +845,14 @@ class RequestConverter extends AbstractQueryProcessor {
SourceConfig sourceConfig = getSourceConfig(query);
List<MultiGetOperation> multiGetOperations = query.getIdsWithRouting().stream()
.map(idWithRouting -> MultiGetOperation.of(mgo -> mgo //
.index(index.getIndexName()) //
.id(idWithRouting.id()) //
.routing(idWithRouting.routing()) //
.source(sourceConfig)))
.map(idWithRouting -> MultiGetOperation.of(mgo -> {
MultiGetOperation.Builder builder = mgo //
.index(index.getIndexName()) //
.id(idWithRouting.id()) //
.source(sourceConfig);
getRouting(idWithRouting.routing()).ifPresent(builder::routing);
return builder;
}))
.collect(Collectors.toList());
return MgetRequest.of(mg -> mg//
@@ -964,10 +974,7 @@ class RequestConverter extends AbstractQueryProcessor {
return DeleteRequest.of(r -> {
r.id(id).index(index.getIndexName());
if (routing != null) {
r.routing(routing);
}
getRouting(routing).ifPresent(r::routing);
r.refresh(refresh(refreshPolicy));
return r;
});
@@ -991,11 +998,7 @@ class RequestConverter extends AbstractQueryProcessor {
b.scroll(time(query.getScrollTime()));
if (query.getRoute() != null) {
b.routing(query.getRoute());
} else if (StringUtils.hasText(routing)) {
b.routing(routing);
}
getRouting(query.getRoute(), routing).ifPresent(b::routing);
return b;
});
@@ -1015,11 +1018,7 @@ class RequestConverter extends AbstractQueryProcessor {
.scroll(time(query.getScroll()))
.scrollSize(query.getScrollSize());
if (query.getRouting() != null) {
dqb.routing(query.getRouting());
} else if (StringUtils.hasText(routing)) {
dqb.routing(routing);
}
getRouting(query.getRouting(), routing).ifPresent(dqb::routing);
if (query.getQ() != null) {
dqb.q(query.getQ())
@@ -1099,7 +1098,6 @@ class RequestConverter extends AbstractQueryProcessor {
uqb
.doc(query.getDocument())
.upsert(query.getUpsert())
.routing(query.getRouting() != null ? query.getRouting() : routing)
.scriptedUpsert(query.getScriptedUpsert())
.docAsUpsert(query.getDocAsUpsert())
.ifSeqNo(query.getIfSeqNo())
@@ -1107,6 +1105,8 @@ class RequestConverter extends AbstractQueryProcessor {
.refresh(query.getRefreshPolicy() != null ? refresh(query.getRefreshPolicy()) : refresh(refreshPolicy))
.retryOnConflict(query.getRetryOnConflict());
getRouting(query.getRouting(), routing).ifPresent(uqb::routing);
if (query.getFetchSource() != null) {
uqb.source(sc -> sc.fetch(query.getFetchSource()));
}
@@ -1149,13 +1149,14 @@ class RequestConverter extends AbstractQueryProcessor {
ub //
.index(Arrays.asList(index.getIndexNames())) //
.refresh(refreshPolicy == RefreshPolicy.IMMEDIATE) //
.routing(updateQuery.getRouting()) //
.script(getScript(updateQuery.getScriptData())) //
.maxDocs(updateQuery.getMaxDocs() != null ? Long.valueOf(updateQuery.getMaxDocs()) : null) //
.pipeline(updateQuery.getPipeline()) //
.requestsPerSecond(updateQuery.getRequestsPerSecond()) //
.slices(slices(updateQuery.getSlices() != null ? Long.valueOf(updateQuery.getSlices()) : null));
getRouting(updateQuery.getRouting()).ifPresent(ub::routing);
if (updateQuery.getAbortOnVersionConflict() != null) {
ub.conflicts(updateQuery.getAbortOnVersionConflict() ? Conflicts.Abort : Conflicts.Proceed);
}
@@ -1229,12 +1230,7 @@ class RequestConverter extends AbstractQueryProcessor {
builder.query(getQuery(query, clazz));
if (StringUtils.hasText(query.getRoute())) {
builder.routing(query.getRoute());
}
if (StringUtils.hasText(routing)) {
builder.routing(routing);
}
getRouting(query.getRoute(), routing).ifPresent(builder::routing);
addPostFilter(query, builder);
@@ -1401,11 +1397,7 @@ class RequestConverter extends AbstractQueryProcessor {
.requestCache(query.getRequestCache()) //
;
if (StringUtils.hasText(query.getRoute())) {
h.routing(query.getRoute());
} else if (StringUtils.hasText(routing)) {
h.routing(routing);
}
getRouting(query.getRoute(), routing).ifPresent(h::routing);
if (query.getPreference() != null) {
h.preference(query.getPreference());
@@ -1451,11 +1443,7 @@ class RequestConverter extends AbstractQueryProcessor {
builder.expandWildcards(expandWildcards(expandWildcards));
}
if (query.getRoute() != null) {
builder.routing(query.getRoute());
} else if (StringUtils.hasText(routing)) {
builder.routing(routing);
}
getRouting(query.getRoute(), routing).ifPresent(builder::routing);
if (query.getPreference() != null) {
builder.preference(query.getPreference());
@@ -1886,11 +1874,7 @@ class RequestConverter extends AbstractQueryProcessor {
if (query.getSource() != null) {
builder.source(so -> so.scriptString(query.getSource()));
}
if (query.getRoute() != null) {
builder.routing(query.getRoute());
} else if (StringUtils.hasText(routing)) {
builder.routing(routing);
}
getRouting(query.getRoute(), routing).ifPresent(builder::routing);
var expandWildcards = query.getExpandWildcards();
if (expandWildcards != null && !expandWildcards.isEmpty()) {
@@ -1990,6 +1974,16 @@ class RequestConverter extends AbstractQueryProcessor {
return null;
}
Optional<String> getRouting(@Nullable String routing) {
if (StringUtils.hasText(routing)) {
return Optional.of(routing);
}
return Optional.empty();
}
Optional<String> getRouting(@Nullable String routing1, @Nullable String routing2) {
return getRouting(routing1).or(() -> getRouting(routing2));
}
private VersionType retrieveVersionTypeFromPersistentEntity(@Nullable Class<?> clazz) {
ElasticsearchPersistentEntity<?> persistentEntity = getPersistentEntity(clazz);
@@ -22,7 +22,7 @@ import co.elastic.clients.elasticsearch._types.BulkIndexByScrollFailure;
import co.elastic.clients.elasticsearch._types.ErrorCause;
import co.elastic.clients.elasticsearch._types.Time;
import co.elastic.clients.elasticsearch._types.query_dsl.Query;
import co.elastic.clients.elasticsearch.cluster.ComponentTemplateSummary;
import co.elastic.clients.elasticsearch.cluster.ComponentTemplateSummaryRes;
import co.elastic.clients.elasticsearch.cluster.GetComponentTemplateResponse;
import co.elastic.clients.elasticsearch.cluster.HealthResponse;
import co.elastic.clients.elasticsearch.core.DeleteByQueryResponse;
@@ -66,6 +66,7 @@ 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.data.elasticsearch.support.DefaultStringObjectMap;
import org.springframework.lang.Contract;
import org.springframework.util.Assert;
/**
@@ -132,7 +133,7 @@ class ResponseConverter {
.build();
}
private TemplateResponseData clusterGetComponentTemplateData(ComponentTemplateSummary componentTemplateSummary) {
private TemplateResponseData clusterGetComponentTemplateData(ComponentTemplateSummaryRes componentTemplateSummary) {
var mapping = typeMapping(componentTemplateSummary.mappings());
var settings = new Settings();
@@ -335,11 +336,11 @@ class ResponseConverter {
.build();
}
private TemplateResponseData indexGetComponentTemplateData(IndexTemplateSummary indexTemplateSummary,
private TemplateResponseData indexGetComponentTemplateData(IndexTemplateSummaryWithRollover indexTemplateSummary,
List<String> composedOf) {
var mapping = typeMapping(indexTemplateSummary.mappings());
Function<IndexSettings, Settings> indexSettingsToSettings = indexSettings -> {
Function<@Nullable IndexSettings, @Nullable Settings> indexSettingsToSettings = indexSettings -> {
if (indexSettings == null) {
return null;
@@ -497,7 +498,7 @@ class ResponseConverter {
builder.withDeleted(response.deleted());
}
if(response.updated() != null) {
if (response.updated() != null) {
builder.withUpdated(response.updated());
}
@@ -574,17 +575,20 @@ class ResponseConverter {
}
}
@Contract("null -> null; !null -> !null")
@Nullable
static ElasticsearchErrorCause toErrorCause(@Nullable ErrorCause errorCause) {
if (errorCause != null) {
return new ElasticsearchErrorCause( //
errorCause.type(), //
errorCause.reason(), //
errorCause.stackTrace(), //
toErrorCause(errorCause.causedBy()), //
errorCause.rootCause().stream().map(ResponseConverter::toErrorCause).collect(Collectors.toList()), //
errorCause.suppressed().stream().map(ResponseConverter::toErrorCause).collect(Collectors.toList()));
return new ElasticsearchErrorCause(
errorCause.type(),
errorCause.reason(),
errorCause.stackTrace(),
toErrorCause(errorCause.causedBy()),
(List<ElasticsearchErrorCause>) (errorCause.rootCause().stream()
.map(ResponseConverter::toErrorCause).collect(Collectors.toList())),
(List<ElasticsearchErrorCause>) (errorCause.suppressed().stream().map(ResponseConverter::toErrorCause)
.collect(Collectors.toList())));
} else {
return null;
}
@@ -36,6 +36,7 @@ import java.util.EnumSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import org.jspecify.annotations.Nullable;
@@ -144,6 +145,12 @@ final class TypeUtils {
}
}
static Object toObjectNotNull(FieldValue fieldValue) {
Objects.requireNonNull(fieldValue);
return toObject(fieldValue);
}
@Nullable
static Object toObject(@Nullable FieldValue fieldValue) {
@@ -485,7 +492,7 @@ final class TypeUtils {
}
@Nullable
static IndexSettings indexSettings(@Nullable Map<String, Object> settings) {
static IndexSettings indexSettings(@Nullable Map<String, @Nullable Object> settings) {
return settings != null ? IndexSettings.of(b -> b.withJson(new StringReader(Document.from(settings).toJson())))
: null;
}
@@ -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())) {
@@ -1,2 +1,18 @@
/*
* 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.
* 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.
*/
@org.jspecify.annotations.NullMarked
package org.springframework.data.elasticsearch.client.elc.aot;
@@ -28,7 +28,6 @@ import org.apache.hc.core5.http.HttpHost;
import org.apache.hc.core5.http.message.BasicHeader;
import org.apache.hc.core5.http.nio.ssl.BasicClientTlsStrategy;
import org.apache.hc.core5.util.Timeout;
import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.Nullable;
import org.springframework.data.elasticsearch.client.ClientConfiguration;
import org.springframework.data.elasticsearch.support.HttpHeaders;
@@ -181,7 +180,7 @@ public final class Rest5Clients {
return builder;
}
private static HttpHost @NonNull [] getHttpHosts(ClientConfiguration clientConfiguration) {
private static HttpHost[] getHttpHosts(ClientConfiguration clientConfiguration) {
List<InetSocketAddress> hosts = clientConfiguration.getEndpoints();
boolean useSsl = clientConfiguration.useSsl();
return hosts.stream()
@@ -21,10 +21,8 @@ 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.NonNull;
import org.jspecify.annotations.Nullable;
import org.springframework.data.elasticsearch.client.ClientConfiguration;
import org.springframework.data.elasticsearch.client.elc.ElasticsearchClients;
import org.springframework.data.elasticsearch.support.HttpHeaders;
import org.springframework.util.Assert;
@@ -107,7 +105,7 @@ public final class RestClients {
return builder;
}
private static HttpHost @NonNull [] getHttpHosts(ClientConfiguration clientConfiguration) {
private static HttpHost[] getHttpHosts(ClientConfiguration clientConfiguration) {
List<InetSocketAddress> hosts = clientConfiguration.getEndpoints();
boolean useSsl = clientConfiguration.useSsl();
return hosts.stream()
@@ -130,10 +128,10 @@ public final class RestClients {
record CustomHeaderInjector(Supplier<HttpHeaders> headersSupplier) implements HttpRequestInterceptor {
@Override
public void process(HttpRequest request, HttpContext context) {
public void process(@Nullable HttpRequest request, @Nullable HttpContext context) {
HttpHeaders httpHeaders = headersSupplier.get();
if (httpHeaders != null && !httpHeaders.isEmpty()) {
if (!httpHeaders.isEmpty() && request != null) {
Arrays.stream(toHeaderArray(httpHeaders)).forEach(request::addHeader);
}
}
@@ -1,2 +1,18 @@
/*
* 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.
* 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.
*/
@org.jspecify.annotations.NullMarked
package org.springframework.data.elasticsearch.client;
@@ -1,2 +1,18 @@
/*
* 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.
* 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.
*/
@org.jspecify.annotations.NullMarked
package org.springframework.data.elasticsearch.client.util;
@@ -18,6 +18,7 @@ package org.springframework.data.elasticsearch.config;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.jspecify.annotations.Nullable;
@@ -98,7 +99,7 @@ public class ElasticsearchConfigurationSupport {
protected Collection<String> getMappingBasePackages() {
Package mappingBasePackage = getClass().getPackage();
return Collections.singleton(mappingBasePackage == null ? null : mappingBasePackage.getName());
return mappingBasePackage == null ? Collections.emptyList() : List.of(mappingBasePackage.getName());
}
/**
@@ -1,2 +1,18 @@
/*
* 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.
* 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.
*/
@org.jspecify.annotations.NullMarked
package org.springframework.data.elasticsearch.config;
@@ -59,6 +59,7 @@ import org.springframework.data.elasticsearch.support.VersionInfo;
import org.springframework.data.mapping.callback.EntityCallbacks;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.util.Streamable;
import org.springframework.lang.Contract;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
@@ -260,7 +261,7 @@ public abstract class AbstractElasticsearchTemplate implements ElasticsearchOper
List<IndexedObjectInformation> indexedObjectInformationList = bulkIndex(indexQueries, index);
Iterator<IndexedObjectInformation> iterator = indexedObjectInformationList.iterator();
// noinspection unchecked
// noinspection unchecked,DataFlowIssue
return indexQueries.stream() //
.map(IndexQuery::getObject) //
.map(entity -> (T) entityOperations.updateIndexedObject(
@@ -593,7 +594,7 @@ public abstract class AbstractElasticsearchTemplate implements ElasticsearchOper
}
protected <T> SearchDocumentResponse.EntityCreator<T> getEntityCreator(ReadDocumentCallback<T> documentCallback) {
return searchDocument -> CompletableFuture.completedFuture(documentCallback.doWith(searchDocument));
return searchDocument -> CompletableFuture.<T> completedFuture(documentCallback.doWith(searchDocument));
}
/**
@@ -752,6 +753,7 @@ public abstract class AbstractElasticsearchTemplate implements ElasticsearchOper
// region Document callbacks
protected interface DocumentCallback<T> {
@Contract("null -> null")
@Nullable
T doWith(@Nullable Document document);
}
@@ -815,6 +817,7 @@ public abstract class AbstractElasticsearchTemplate implements ElasticsearchOper
@Override
public SearchHits<T> doWith(SearchDocumentResponse response) {
// noinspection NullableProblems,DataFlowIssue
List<T> entities = response.getSearchDocuments().stream().map(delegate::doWith).collect(Collectors.toList());
return SearchHitMapping.mappingFor(type, elasticsearchConverter).mapHits(response, entities);
}
@@ -835,6 +838,7 @@ public abstract class AbstractElasticsearchTemplate implements ElasticsearchOper
@Override
public SearchScrollHits<T> doWith(SearchDocumentResponse response) {
// noinspection DataFlowIssue,NullableProblems
List<T> entities = response.getSearchDocuments().stream().map(delegate::doWith).collect(Collectors.toList());
return SearchHitMapping.mappingFor(type, elasticsearchConverter).mapScrollHits(response, entities);
}
@@ -766,7 +766,8 @@ abstract public class AbstractReactiveElasticsearchTemplate
/**
* Value class to capture client independent information from a response to an index request.
*/
public record IndexResponseMetaData(String id, String index, long seqNo, long primaryTerm, long version) {
public record IndexResponseMetaData(String id, String index, @Nullable Long seqNo, @Nullable Long primaryTerm,
long version) {
}
// endregion
@@ -17,7 +17,6 @@ package org.springframework.data.elasticsearch.core;
import java.util.Map;
import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.Nullable;
import org.springframework.core.convert.ConversionService;
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
@@ -370,7 +369,7 @@ public class EntityOperations {
* @see org.springframework.data.elasticsearch.core.EntityOperations.AdaptableEntity#initializeVersionProperty()
*/
@Override
public @NonNull T initializeVersionProperty() {
public T initializeVersionProperty() {
return map;
}
@@ -399,7 +398,7 @@ public class EntityOperations {
* @see org.springframework.data.elasticsearch.core.EntityOperations.AdaptableEntity#incrementVersion()
*/
@Override
public @NonNull T incrementVersion() {
public T incrementVersion() {
return map;
}
@@ -408,7 +407,7 @@ public class EntityOperations {
* @see org.springframework.data.elasticsearch.core.EntityOperations.Entity#getBean()
*/
@Override
public @NonNull T getBean() {
public T getBean() {
return map;
}
@@ -52,7 +52,7 @@ public interface IndexOperations {
* @param settings the index settings
* @return {@literal true} if the index was created
*/
boolean create(Map<String, Object> settings);
boolean create(Map<String, @Nullable Object> settings);
/**
* Create an index for given settings and mapping.
@@ -62,7 +62,7 @@ public interface IndexOperations {
* @return {@literal true} if the index was created
* @since 4.2
*/
boolean create(Map<String, Object> settings, Document mapping);
boolean create(Map<String, @Nullable Object> settings, Document mapping);
/**
* Create an index with the settings and mapping defined for the entity this IndexOperations is bound to.
@@ -142,7 +142,7 @@ public interface IndexOperations {
*
* @return the mapping
*/
Map<String, Object> getMapping();
Map<String, @Nullable Object> getMapping();
// endregion
@@ -46,12 +46,12 @@ public interface IndexOperationsAdapter extends IndexOperations {
}
@Override
public boolean create(Map<String, Object> settings) {
public boolean create(Map<String, @Nullable Object> settings) {
return Boolean.TRUE.equals(reactiveIndexOperations.create(settings).block());
}
@Override
public boolean create(Map<String, Object> settings, Document mapping) {
public boolean create(Map<String, @Nullable Object> settings, Document mapping) {
return Boolean.TRUE.equals(reactiveIndexOperations.create(settings, mapping).block());
}
@@ -92,7 +92,7 @@ public interface IndexOperationsAdapter extends IndexOperations {
}
@Override
public Map<String, Object> getMapping() {
public Map<String, @Nullable Object> getMapping() {
return Objects.requireNonNull(reactiveIndexOperations.getMapping().block());
}
@@ -36,7 +36,7 @@ public class MultiGetItem<T> {
}
public static <T> MultiGetItem<T> of(@Nullable T item, @Nullable Failure failure) {
return new MultiGetItem<>(item, failure);
return new MultiGetItem(item, failure);
}
public boolean hasItem() {
@@ -21,6 +21,7 @@ import reactor.core.publisher.Mono;
import java.util.Map;
import java.util.Set;
import org.jspecify.annotations.Nullable;
import org.springframework.data.elasticsearch.core.document.Document;
import org.springframework.data.elasticsearch.core.index.*;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
@@ -50,7 +51,7 @@ public interface ReactiveIndexOperations {
* @return a {@link Mono} signalling successful operation completion or an {@link Mono#error(Throwable) error} if eg.
* the index already exist.
*/
Mono<Boolean> create(Map<String, Object> settings);
Mono<Boolean> create(Map<String, @Nullable Object> settings);
/**
* Create an index for given settings and mapping.
@@ -61,7 +62,7 @@ public interface ReactiveIndexOperations {
* the index already exist.
* @since 4.2
*/
Mono<Boolean> create(Map<String, Object> settings, Document mapping);
Mono<Boolean> create(Map<String, @Nullable Object> settings, Document mapping);
/**
* Create an index with the settings and mapping defined for the entity this IndexOperations is bound to.
@@ -51,7 +51,7 @@ public class SearchHit<T> {
private final Map<String, Double> matchedQueries = new LinkedHashMap<>();
public SearchHit(@Nullable String index, @Nullable String id, @Nullable String routing, float score,
@Nullable Object[] sortValues, @Nullable Map<String, List<String>> highlightFields,
Object @Nullable [] sortValues, @Nullable Map<String, List<String>> highlightFields,
@Nullable Map<String, SearchHits<?>> innerHits, @Nullable NestedMetaData nestedMetaData,
@Nullable Explanation explanation, @Nullable Map<String, Double> matchedQueries, T content) {
this.index = index;
@@ -193,7 +193,6 @@ public class SearchHit<T> {
/**
* @return the matched queries for this SearchHit.
*/
@Nullable
public Map<String, Double> getMatchedQueries() {
return matchedQueries;
}
@@ -22,11 +22,11 @@ import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.jspecify.annotations.Nullable;
import org.springframework.data.core.ReactiveWrappers;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.util.CloseableIterator;
import org.springframework.lang.Contract;
/**
* Utility class with helper methods for working with {@link SearchHit}.
@@ -47,6 +47,7 @@ public final class SearchHitSupport {
* @return a corresponding object where the SearchHits are replaced by their content if possible, otherwise the
* original object
*/
@Contract("null -> null; !null -> !null")
@Nullable
public static Object unwrapSearchHits(@Nullable Object result) {
@@ -133,7 +133,7 @@ public class SearchHitsImpl<T> implements SearchScrollHits<T> {
}
@Override
public SearchShardStatistics getSearchShardStatistics() {
public @Nullable SearchShardStatistics getSearchShardStatistics() {
return searchShardStatistics;
}
@@ -1,5 +1,18 @@
/**
* Interfaces and classes related to Elasticsearch cluster information and management.
/*
* 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.
* 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.
*/
@org.jspecify.annotations.NullMarked
package org.springframework.data.elasticsearch.core.cluster;
@@ -29,7 +29,7 @@ import org.springframework.data.mapping.context.MappingContext;
* @author Christoph Strobl
* @since 3.2
*/
public interface ElasticsearchTypeMapper extends TypeMapper<Map<String, Object>> {
public interface ElasticsearchTypeMapper extends TypeMapper<Map<String, @Nullable Object>> {
String DEFAULT_TYPE_KEY = "_class";
@@ -47,7 +47,7 @@ public interface ElasticsearchTypeMapper extends TypeMapper<Map<String, Object>>
@Nullable
String getTypeKey();
default boolean containsTypeInformation(Map<String, Object> source) {
default boolean containsTypeInformation(Map<String, @Nullable Object> source) {
return readType(source) != null;
}
@@ -20,9 +20,9 @@ import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import org.jspecify.annotations.Nullable;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.convert.ReadingConverter;
import org.springframework.data.convert.WritingConverter;
@@ -167,7 +167,7 @@ public class GeoConverters {
INSTANCE;
@Override
public GeoJson<? extends Iterable<?>> convert(Map<String, Object> source) {
public GeoJson<? extends Iterable<?>> convert(Map<String, @Nullable Object> source) {
String type = GeoConverters.getGeoJsonType(source);
@@ -206,7 +206,7 @@ public class GeoConverters {
INSTANCE;
@Override
public GeoJsonPoint convert(Map<String, Object> source) {
public GeoJsonPoint convert(Map<String, @Nullable Object> source) {
String type = GeoConverters.getGeoJsonType(source);
Assert.isTrue(type.equalsIgnoreCase(GeoJsonPoint.TYPE), "does not contain a type 'Point'");
@@ -244,7 +244,7 @@ public class GeoConverters {
INSTANCE;
@Override
public GeoJsonMultiPoint convert(Map<String, Object> source) {
public GeoJsonMultiPoint convert(Map<String, @Nullable Object> source) {
String type = GeoConverters.getGeoJsonType(source);
Assert.isTrue(type.equalsIgnoreCase(GeoJsonMultiPoint.TYPE), "does not contain a type 'MultiPoint'");
@@ -279,7 +279,7 @@ public class GeoConverters {
INSTANCE;
@Override
public GeoJsonLineString convert(Map<String, Object> source) {
public GeoJsonLineString convert(Map<String, @Nullable Object> source) {
String type = GeoConverters.getGeoJsonType(source);
Assert.isTrue(type.equalsIgnoreCase(GeoJsonLineString.TYPE), "does not contain a type 'LineString'");
@@ -311,7 +311,7 @@ public class GeoConverters {
INSTANCE;
@Override
public GeoJsonMultiLineString convert(Map<String, Object> source) {
public GeoJsonMultiLineString convert(Map<String, @Nullable Object> source) {
String type = GeoConverters.getGeoJsonType(source);
Assert.isTrue(type.equalsIgnoreCase(GeoJsonMultiLineString.TYPE), "does not contain a type 'MultiLineString'");
@@ -339,7 +339,7 @@ public class GeoConverters {
INSTANCE;
@Override
public GeoJsonPolygon convert(Map<String, Object> source) {
public GeoJsonPolygon convert(Map<String, @Nullable Object> source) {
String type = GeoConverters.getGeoJsonType(source);
Assert.isTrue(type.equalsIgnoreCase(GeoJsonPolygon.TYPE), "does not contain a type 'Polygon'");
@@ -368,7 +368,6 @@ public class GeoConverters {
List<Object> coordinates = source.getCoordinates().stream() //
.map(GeoJsonPolygonToMapConverter.INSTANCE::convert) //
.filter(Objects::nonNull) //
.map(it -> it.get("coordinates")) //
.collect(Collectors.toList()); //
map.put("coordinates", coordinates);
@@ -383,7 +382,7 @@ public class GeoConverters {
INSTANCE;
@Override
public GeoJsonMultiPolygon convert(Map<String, Object> source) {
public GeoJsonMultiPolygon convert(Map<String, @Nullable Object> source) {
String type = GeoConverters.getGeoJsonType(source);
Assert.isTrue(type.equalsIgnoreCase(GeoJsonMultiPolygon.TYPE), "does not contain a type 'MultiPolygon'");
@@ -430,7 +429,7 @@ public class GeoConverters {
INSTANCE;
@Override
public GeoJsonGeometryCollection convert(Map<String, Object> source) {
public GeoJsonGeometryCollection convert(Map<String, @Nullable Object> source) {
String type = GeoConverters.getGeoJsonType(source);
Assert.isTrue(type.equalsIgnoreCase(GeoJsonGeometryCollection.TYPE),
@@ -448,7 +447,7 @@ public class GeoConverters {
// endregion
// region helper functions
private static String getGeoJsonType(Map<String, Object> source) {
private static String getGeoJsonType(Map<String, @Nullable Object> source) {
Object type = source.get("type");
Assert.notNull(type, "Document to convert does not contain a type");
@@ -485,7 +484,7 @@ public class GeoConverters {
return map;
}
private static List<GeoJsonLineString> geoJsonLineStringsFromMap(Map<String, Object> source) {
private static List<GeoJsonLineString> geoJsonLineStringsFromMap(Map<String, @Nullable Object> source) {
Object coordinates = source.get("coordinates");
Assert.notNull(coordinates, "Document to convert does not contain coordinates");
Assert.isTrue(coordinates instanceof List, "coordinates must be a List");
@@ -24,7 +24,6 @@ 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.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
@@ -63,16 +62,7 @@ import org.springframework.data.mapping.Parameter;
import org.springframework.data.mapping.PersistentPropertyAccessor;
import org.springframework.data.mapping.SimplePropertyHandler;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.mapping.model.CachingValueExpressionEvaluatorFactory;
import org.springframework.data.mapping.model.ConvertingPropertyAccessor;
import org.springframework.data.mapping.model.EntityInstantiator;
import org.springframework.data.mapping.model.EntityInstantiators;
import org.springframework.data.mapping.model.ParameterValueProvider;
import org.springframework.data.mapping.model.PersistentEntityParameterValueProvider;
import org.springframework.data.mapping.model.PropertyValueProvider;
import org.springframework.data.mapping.model.SpELContext;
import org.springframework.data.mapping.model.ValueExpressionEvaluator;
import org.springframework.data.mapping.model.ValueExpressionParameterValueProvider;
import org.springframework.data.mapping.model.*;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.format.datetime.DateFormatterRegistrar;
import org.springframework.util.Assert;
@@ -267,7 +257,7 @@ public class MappingElasticsearchConverter
@Nullable
@SuppressWarnings("unchecked")
private <R> R read(TypeInformation<R> typeInformation, Map<String, Object> source) {
private <R> R read(TypeInformation<R> typeInformation, Map<String, @Nullable Object> source) {
Assert.notNull(source, "Source must not be null!");
@@ -301,7 +291,7 @@ public class MappingElasticsearchConverter
}
@SuppressWarnings("unchecked")
private <R> R readMap(TypeInformation<?> type, Map<String, Object> source) {
private <R> R readMap(TypeInformation<?> type, Map<String, @Nullable Object> source) {
Assert.notNull(source, "Document must not be null!");
@@ -313,9 +303,10 @@ public class MappingElasticsearchConverter
Class<?> rawKeyType = keyType != null ? keyType.getType() : null;
Class<?> rawValueType = valueType != null ? valueType.getType() : null;
Map<Object, Object> map = CollectionFactory.createMap(mapType, rawKeyType, source.keySet().size());
Map<Object, @Nullable Object> map = (Map<Object, @Nullable Object>) CollectionFactory.createMap(mapType,
rawKeyType, source.keySet().size());
for (Entry<String, Object> entry : source.entrySet()) {
for (Entry<String, @Nullable Object> entry : source.entrySet()) {
if (typeMapper.isTypeKey(entry.getKey())) {
continue;
@@ -325,6 +316,7 @@ public class MappingElasticsearchConverter
if (rawKeyType != null && !rawKeyType.isAssignableFrom(key.getClass())) {
key = conversionService.convert(key, rawKeyType);
Assert.notNull(key, "converted key must not be null");
}
Object value = entry.getValue();
@@ -343,7 +335,7 @@ public class MappingElasticsearchConverter
return (R) map;
}
private <R> R readEntity(ElasticsearchPersistentEntity<?> entity, Map<String, Object> source) {
private <R> R readEntity(ElasticsearchPersistentEntity<?> entity, Map<String, @Nullable Object> source) {
ElasticsearchPersistentEntity<?> targetEntity = computeClosestEntity(entity, source);
ValueExpressionEvaluator evaluator = expressionEvaluatorFactory.create(source);
@@ -582,7 +574,7 @@ public class MappingElasticsearchConverter
: TypeInformation.OBJECT;
Class<?> rawComponentType = componentType.getType();
Collection<Object> items = targetType.getType().isArray() //
Collection<@Nullable Object> items = targetType.getType().isArray() //
? new ArrayList<>(source.size()) //
: CollectionFactory.createCollection(collectionType, rawComponentType, source.size());
@@ -672,7 +664,7 @@ public class MappingElasticsearchConverter
*/
private <T> void populateScriptedFields(ElasticsearchPersistentEntity<?> entity, T result,
SearchDocument searchDocument) {
Map<String, List<Object>> fields = searchDocument.getFields();
Map<String, List<@Nullable Object>> fields = searchDocument.getFields();
entity.doWithProperties((SimplePropertyHandler) property -> {
if (property.isAnnotationPresent(ScriptedField.class)) {
ScriptedField scriptedField = property.findAnnotation(ScriptedField.class);
@@ -695,7 +687,7 @@ public class MappingElasticsearchConverter
* Compute the type to use by checking the given entity against the store type;
*/
private ElasticsearchPersistentEntity<?> computeClosestEntity(ElasticsearchPersistentEntity<?> entity,
Map<String, Object> source) {
Map<String, @Nullable Object> source) {
TypeInformation<?> typeToUse = typeMapper.readType(source);
@@ -770,7 +762,7 @@ public class MappingElasticsearchConverter
INSTANCE;
@Override
public <T> T getParameterValue(Parameter<T, ElasticsearchPersistentProperty> parameter) {
public <T> @Nullable T getParameterValue(Parameter<T, ElasticsearchPersistentProperty> parameter) {
return null;
}
}
@@ -822,7 +814,7 @@ public class MappingElasticsearchConverter
* @param typeInformation type information for the source
*/
@SuppressWarnings("unchecked")
private void writeInternal(@Nullable Object source, Map<String, Object> sink,
private void writeInternal(@Nullable Object source, Map<String, @Nullable Object> sink,
@Nullable TypeInformation<?> typeInformation) {
if (null == source) {
@@ -833,7 +825,7 @@ public class MappingElasticsearchConverter
Optional<Class<?>> customTarget = conversions.getCustomWriteTarget(entityType, Map.class);
if (customTarget.isPresent()) {
Map<String, Object> result = conversionService.convert(source, Map.class);
Map<String, @Nullable Object> result = conversionService.convert(source, Map.class);
if (result != null) {
sink.putAll(result);
@@ -863,7 +855,7 @@ public class MappingElasticsearchConverter
* @param sink the destination
* @param entity entity for the source
*/
private void writeInternal(@Nullable Object source, Map<String, Object> sink,
private void writeInternal(@Nullable Object source, Map<String, @Nullable Object> sink,
@Nullable ElasticsearchPersistentEntity<?> entity) {
if (source == null) {
@@ -905,7 +897,7 @@ public class MappingElasticsearchConverter
* @param sink must not be {@literal null}.
* @param propertyType must not be {@literal null}.
*/
private Map<String, Object> writeMapInternal(Map<?, ?> source, Map<String, Object> sink,
private Map<String, @Nullable Object> writeMapInternal(Map<?, ?> source, Map<String, @Nullable Object> sink,
TypeInformation<?> propertyType) {
for (Map.Entry<?, ?> entry : source.entrySet()) {
@@ -922,7 +914,7 @@ public class MappingElasticsearchConverter
sink.put(simpleKey,
writeCollectionInternal(asCollection(value), propertyType.getMapValueType(), new ArrayList<>()));
} else {
Map<String, Object> document = Document.create();
Map<String, @Nullable Object> document = Document.create();
TypeInformation<?> valueTypeInfo = propertyType.isMap() ? propertyType.getMapValueType()
: TypeInformation.OBJECT;
writeInternal(value, document, valueTypeInfo);
@@ -966,7 +958,7 @@ public class MappingElasticsearchConverter
} else if (element instanceof Collection || elementType.isArray()) {
collection.add(writeCollectionInternal(asCollection(element), componentType, new ArrayList<>()));
} else {
Map<String, Object> document = Document.create();
Map<String, @Nullable Object> document = Document.create();
writeInternal(element, document, componentType);
collection.add(document);
}
@@ -1080,7 +1072,7 @@ public class MappingElasticsearchConverter
: mappingContext.getRequiredPersistentEntity(type);
Object existingValue = sink.get(property);
Map<String, Object> document = existingValue instanceof Map ? (Map<String, Object>) existingValue
Map<String, @Nullable Object> document = existingValue instanceof Map ? (Map<String, Object>) existingValue
: Document.create();
addCustomTypeKeyIfNecessary(value, document, TypeInformation.of(property.getRawType()));
@@ -1097,7 +1089,7 @@ public class MappingElasticsearchConverter
* @param sink must not be {@literal null}.
* @param type type to compare to
*/
private void addCustomTypeKeyIfNecessary(Object source, Map<String, Object> sink,
private void addCustomTypeKeyIfNecessary(Object source, Map<String, @Nullable Object> sink,
@Nullable TypeInformation<?> type) {
if (!writeTypeHints) {
@@ -1218,7 +1210,7 @@ public class MappingElasticsearchConverter
Assert.notNull(map, "Given map must not be null!");
Assert.notNull(property, "PersistentProperty must not be null!");
return writeMapInternal(map, new LinkedHashMap<>(map.size()), property.getTypeInformation());
return writeMapInternal(map, new LinkedHashMap(map.size()), property.getTypeInformation());
}
/**
@@ -1492,9 +1484,9 @@ public class MappingElasticsearchConverter
@SuppressWarnings("ClassCanBeRecord")
static class MapValueAccessor {
final Map<String, Object> target;
final Map<String, @Nullable Object> target;
MapValueAccessor(Map<String, Object> target) {
MapValueAccessor(Map<String, @Nullable Object> target) {
this.target = target;
}
@@ -1528,7 +1520,7 @@ public class MappingElasticsearchConverter
}
Iterator<String> parts = Arrays.asList(fieldName.split("\\.")).iterator();
Map<String, Object> source = target;
Map<String, @Nullable Object> source = target;
Object result = null;
while (parts.hasNext()) {
@@ -1559,11 +1551,11 @@ public class MappingElasticsearchConverter
target.put(property.getFieldName(), value);
}
private Map<String, Object> getAsMap(Object result) {
private Map<String, @Nullable Object> getAsMap(Object result) {
if (result instanceof Map) {
// noinspection unchecked
return (Map<String, Object>) result;
return (Map<String, @Nullable Object>) result;
}
throw new IllegalArgumentException(String.format("%s is not a Map.", result));
@@ -1,2 +1,18 @@
/*
* 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.
* 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.
*/
@org.jspecify.annotations.NullMarked
package org.springframework.data.elasticsearch.core.convert;
@@ -62,7 +62,7 @@ public class Explanation {
}
@Override
public boolean equals(Object o) {
public boolean equals(@Nullable Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
@@ -81,7 +81,7 @@ public class Explanation {
@Override
public int hashCode() {
int result = (match ? 1 : 0);
int result = (Boolean.TRUE.equals(match) ? 1 : 0);
result = 31 * result + value.hashCode();
result = 31 * result + (description != null ? description.hashCode() : 0);
result = 31 * result + details.hashCode();
@@ -215,7 +215,7 @@ class MapDocument implements Document {
* @see java.util.Map#containsKey(java.lang.Object)
*/
@Override
public boolean containsKey(Object key) {
public boolean containsKey(@Nullable Object key) {
return documentAsMap.containsKey(key);
}
@@ -224,7 +224,7 @@ class MapDocument implements Document {
* @see java.util.Map#containsValue(java.lang.Object)
*/
@Override
public boolean containsValue(Object value) {
public boolean containsValue(@Nullable Object value) {
return documentAsMap.containsValue(value);
}
@@ -233,7 +233,7 @@ class MapDocument implements Document {
* @see java.util.Map#get(java.lang.Object)
*/
@Override
public Object get(Object key) {
public Object get(@Nullable Object key) {
return documentAsMap.get(key);
}
@@ -242,7 +242,7 @@ class MapDocument implements Document {
* @see java.lang.Object#getOrDefault(java.lang.Object, java.lang.Object)
*/
@Override
public Object getOrDefault(Object key, Object defaultValue) {
public Object getOrDefault(@Nullable Object key, @Nullable Object defaultValue) {
return documentAsMap.getOrDefault(key, defaultValue);
}
@@ -251,7 +251,7 @@ class MapDocument implements Document {
* @see java.util.Map#put(java.lang.Object, java.lang.Object)
*/
@Override
public Object put(String key, Object value) {
public Object put(String key, @Nullable Object value) {
return documentAsMap.put(key, value);
}
@@ -260,7 +260,7 @@ class MapDocument implements Document {
* @see java.util.Map#remove(java.lang.Object)
*/
@Override
public Object remove(Object key) {
public Object remove(@Nullable Object key) {
return documentAsMap.remove(key);
}
@@ -314,7 +314,7 @@ class MapDocument implements Document {
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object o) {
public boolean equals(@Nullable Object o) {
return documentAsMap.equals(o);
}
@@ -332,7 +332,8 @@ class MapDocument implements Document {
* @see java.util.Map#forEach(java.util.function.BiConsumer)
*/
@Override
public void forEach(BiConsumer<? super String, ? super Object> action) {
public void forEach(
@SuppressWarnings("NullableProblems") BiConsumer<? super String, ? super @Nullable Object> action) {
documentAsMap.forEach(action);
}
@@ -41,7 +41,7 @@ public interface SearchDocument extends Document {
/**
* @return the fields for the search result, not {@literal null}
*/
Map<String, List<Object>> getFields();
Map<String, List<@Nullable Object>> getFields();
/**
* The first value of the given field.
@@ -50,7 +50,7 @@ public interface SearchDocument extends Document {
*/
@Nullable
default <V> V getFieldValue(final String name) {
List<Object> values = getFields().get(name);
List<@Nullable Object> values = getFields().get(name);
if (values == null || values.isEmpty()) {
return null;
}
@@ -64,7 +64,7 @@ public interface SearchDocument extends Document {
*/
@Nullable
default <V> List<V> getFieldValues(final String name) {
List<Object> values = getFields().get(name);
List<@Nullable Object> values = getFields().get(name);
if (values == null) {
return null;
}
@@ -74,8 +74,7 @@ public interface SearchDocument extends Document {
/**
* @return the sort values for the search hit
*/
@Nullable
default Object[] getSortValues() {
default Object @Nullable [] getSortValues() {
return null;
}
@@ -35,7 +35,7 @@ public class SearchDocumentAdapter implements SearchDocument {
private final float score;
private final Object[] sortValues;
private final Map<String, List<Object>> fields = new HashMap<>();
private final Map<String, List<@Nullable Object>> fields = new HashMap<>();
private final Document delegate;
private final Map<String, List<String>> highlightFields = new HashMap<>();
private final Map<String, SearchDocumentResponse> innerHits = new HashMap<>();
@@ -44,9 +44,11 @@ public class SearchDocumentAdapter implements SearchDocument {
@Nullable private final Map<String, Double> matchedQueries;
@Nullable private final String routing;
public SearchDocumentAdapter(Document delegate, float score, Object[] sortValues, Map<String, List<Object>> fields,
public SearchDocumentAdapter(Document delegate, float score, Object[] sortValues,
Map<String, List<@Nullable Object>> fields,
Map<String, List<String>> highlightFields, Map<String, SearchDocumentResponse> innerHits,
@Nullable NestedMetaData nestedMetaData, @Nullable Explanation explanation, @Nullable Map<String, Double> matchedQueries,
@Nullable NestedMetaData nestedMetaData, @Nullable Explanation explanation,
@Nullable Map<String, Double> matchedQueries,
@Nullable String routing) {
this.delegate = delegate;
@@ -74,7 +76,7 @@ public class SearchDocumentAdapter implements SearchDocument {
}
@Override
public Map<String, List<Object>> getFields() {
public Map<String, List<@Nullable Object>> getFields() {
return fields;
}
@@ -186,17 +188,17 @@ public class SearchDocumentAdapter implements SearchDocument {
}
@Override
public boolean containsKey(Object key) {
public boolean containsKey(@Nullable Object key) {
return delegate.containsKey(key);
}
@Override
public boolean containsValue(Object value) {
public boolean containsValue(@Nullable Object value) {
return delegate.containsValue(value);
}
@Override
public Object get(Object key) {
public Object get(@Nullable Object key) {
if (delegate.containsKey(key)) {
return delegate.get(key);
@@ -207,12 +209,12 @@ public class SearchDocumentAdapter implements SearchDocument {
}
@Override
public Object put(String key, Object value) {
public @Nullable Object put(String key, @Nullable Object value) {
return delegate.put(key, value);
}
@Override
public Object remove(Object key) {
public Object remove(@Nullable Object key) {
return delegate.remove(key);
}
@@ -232,12 +234,12 @@ public class SearchDocumentAdapter implements SearchDocument {
}
@Override
public Collection<Object> values() {
public Collection<@Nullable Object> values() {
return delegate.values();
}
@Override
public Set<Entry<String, Object>> entrySet() {
public Set<Entry<String, @Nullable Object>> entrySet() {
return delegate.entrySet();
}
@@ -254,7 +256,7 @@ public class SearchDocumentAdapter implements SearchDocument {
}
@Override
public boolean equals(Object o) {
public boolean equals(@Nullable Object o) {
if (this == o) {
return true;
}
@@ -270,17 +272,17 @@ public class SearchDocumentAdapter implements SearchDocument {
}
@Override
public void forEach(BiConsumer<? super String, ? super Object> action) {
public void forEach(@Nullable BiConsumer<? super String, ? super @Nullable Object> action) {
delegate.forEach(action);
}
@Override
public boolean remove(Object key, Object value) {
public boolean remove(@Nullable Object key, @Nullable Object value) {
return delegate.remove(key, value);
}
@Override
public String getRouting() {
public @Nullable String getRouting() {
return routing;
}
@@ -1,5 +1,18 @@
/**
* Classes related to the Document structure of Elasticsearch documents and search responses.
/*
* 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.
* 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.
*/
@org.jspecify.annotations.NullMarked
package org.springframework.data.elasticsearch.core.document;
@@ -31,10 +31,11 @@ import org.springframework.data.mapping.callback.EntityCallback;
public interface AfterLoadCallback<T> extends EntityCallback<Document> {
/**
* Entity callback method invoked after a domain object is materialized from a {@link Document}. Can return either the
* same or a modified instance of the {@link Document} object.
* Entity callback method invoked after a {@link Document} is read from Elasticsearch. Can return either the same or a
* modified instance of the {@link Document} object.
*
* @param document the document.
* @param type the type into which the document will be converted
* @param indexCoordinates of the index the document was read from.
* @return a possible modified or new {@link Document}.
*/
@@ -1,5 +1,18 @@
/**
* classes and interfaces related to Spring Data Elasticsearch events and callbacks.
/*
* 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.
* 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.
*/
@org.jspecify.annotations.NullMarked
package org.springframework.data.elasticsearch.core.event;
@@ -8,18 +8,27 @@ import tools.jackson.databind.SerializationContext;
import tools.jackson.databind.ValueDeserializer;
import tools.jackson.databind.ValueSerializer;
import org.jspecify.annotations.Nullable;
import org.springframework.data.geo.Point;
import org.springframework.util.Assert;
class PointSerializer extends ValueSerializer<Point> {
@Override
public void serialize(Point value, JsonGenerator gen, SerializationContext serializers) throws JacksonException {
public void serialize(Point value, @Nullable JsonGenerator gen, @Nullable SerializationContext serializers)
throws JacksonException {
Assert.notNull(gen, "gen must not be null");
gen.writePOJO(GeoPoint.fromPoint(value));
}
}
class PointDeserializer extends ValueDeserializer<Point> {
@Override
public Point deserialize(JsonParser p, DeserializationContext context) throws JacksonException {
public Point deserialize(@Nullable JsonParser p, @Nullable DeserializationContext context) throws JacksonException {
Assert.notNull(p, "p must not be null");
return GeoPoint.toPoint(p.readValueAs(GeoPoint.class));
}
}
@@ -19,6 +19,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.jspecify.annotations.Nullable;
import org.springframework.util.Assert;
/**
@@ -68,7 +69,7 @@ public class GeoJsonGeometryCollection implements GeoJson<Iterable<GeoJson<?>>>
}
@Override
public boolean equals(Object o) {
public boolean equals(@Nullable Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
@@ -21,6 +21,7 @@ import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import org.jspecify.annotations.Nullable;
import org.springframework.data.geo.Point;
import org.springframework.util.Assert;
@@ -122,7 +123,7 @@ public class GeoJsonLineString implements GeoJson<Iterable<Point>> {
}
@Override
public boolean equals(Object o) {
public boolean equals(@Nullable Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
@@ -21,6 +21,7 @@ import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import org.jspecify.annotations.Nullable;
import org.springframework.data.geo.Point;
import org.springframework.util.Assert;
@@ -81,7 +82,7 @@ public class GeoJsonMultiLineString implements GeoJson<Iterable<GeoJsonLineStrin
}
@Override
public boolean equals(Object o) {
public boolean equals(@Nullable Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
@@ -21,6 +21,7 @@ import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import org.jspecify.annotations.Nullable;
import org.springframework.data.geo.Point;
import org.springframework.util.Assert;
@@ -122,7 +123,7 @@ public class GeoJsonMultiPoint implements GeoJson<Iterable<Point>> {
}
@Override
public boolean equals(Object o) {
public boolean equals(@Nullable Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
@@ -19,6 +19,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.jspecify.annotations.Nullable;
import org.springframework.util.Assert;
/**
@@ -62,7 +63,7 @@ public class GeoJsonMultiPolygon implements GeoJson<Iterable<GeoJsonPolygon>> {
}
@Override
public boolean equals(Object o) {
public boolean equals(@Nullable Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
@@ -18,6 +18,7 @@ package org.springframework.data.elasticsearch.core.geo;
import java.util.Arrays;
import java.util.List;
import org.jspecify.annotations.Nullable;
import org.springframework.data.geo.Point;
/**
@@ -89,7 +90,7 @@ public class GeoJsonPoint implements GeoJson<List<Double>> {
}
@Override
public boolean equals(Object o) {
public boolean equals(@Nullable Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
@@ -21,6 +21,7 @@ import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import org.jspecify.annotations.Nullable;
import org.springframework.data.geo.Point;
import org.springframework.util.Assert;
@@ -207,7 +208,7 @@ public class GeoJsonPolygon implements GeoJson<Iterable<GeoJsonLineString>> {
}
@Override
public boolean equals(Object o) {
public boolean equals(@Nullable Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
@@ -17,6 +17,7 @@ package org.springframework.data.elasticsearch.core.geo;
import java.util.Objects;
import org.jspecify.annotations.Nullable;
import org.springframework.data.geo.Point;
/**
@@ -63,7 +64,7 @@ public class GeoPoint {
}
@Override
public boolean equals(Object o) {
public boolean equals(@Nullable Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
@@ -1,2 +1,18 @@
/*
* 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.
* 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.
*/
@org.jspecify.annotations.NullMarked
package org.springframework.data.elasticsearch.core.geo;
@@ -27,7 +27,7 @@ import org.springframework.util.Assert;
*/
public class AliasActionParameters {
private final String[] indices;
@Nullable private final String[] aliases;
private final String @Nullable [] aliases;
@Nullable private final Query filterQuery;
@Nullable private final Class<?> filterQueryClass;
@Nullable private final Boolean isHidden;
@@ -36,7 +36,7 @@ public class AliasActionParameters {
@Nullable private final String indexRouting;
@Nullable private final String searchRouting;
private AliasActionParameters(String[] indices, @Nullable String[] aliases, @Nullable Boolean isHidden,
private AliasActionParameters(String[] indices, String @Nullable [] aliases, @Nullable Boolean isHidden,
@Nullable Boolean isWriteIndex, @Nullable String routing, @Nullable String indexRouting,
@Nullable String searchRouting, @Nullable Query filterQuery, @Nullable Class<?> filterQueryClass) {
this.indices = indices;
@@ -66,7 +66,7 @@ public class AliasActionParameters {
return indices;
}
public String@Nullable[] getAliases() {
public String @Nullable [] getAliases() {
return aliases;
}
@@ -38,7 +38,7 @@ public class AliasActions {
*
* @param actions {@link AliasAction} elements
*/
public AliasActions(@Nullable AliasAction... actions) {
public AliasActions(AliasAction @Nullable... actions) {
add(actions);
}
@@ -52,10 +52,9 @@ public class AliasActions {
* @param actions elements to add
* @return this object
*/
public AliasActions add(@Nullable AliasAction... actions) {
public AliasActions add(AliasAction @Nullable... actions) {
if (actions != null) {
// noinspection NullableProblems
this.actions.addAll(Arrays.asList(actions));
}
@@ -40,7 +40,7 @@ public record ComponentTemplateRequestData(@Nullable Settings settings, @Nullabl
@Nullable private AliasActions aliasActions;
@Nullable private Boolean allowAutoCreate;
public Builder withSettings(Map<String, Object> settings) {
public Builder withSettings(Map<String, @Nullable Object> settings) {
this.settings = new Settings(settings);
return this;
}
@@ -36,9 +36,7 @@ import java.util.stream.Collectors;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.Nullable;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.annotation.Transient;
import org.springframework.data.core.TypeInformation;
@@ -112,9 +110,15 @@ public class MappingBuilder {
protected final ElasticsearchConverter elasticsearchConverter;
private final ObjectMapper objectMapper = new ObjectMapper();
private final MappingParametersCustomizer customizer;
public MappingBuilder(ElasticsearchConverter elasticsearchConverter) {
this(elasticsearchConverter, MappingParameters::from);
}
public MappingBuilder(ElasticsearchConverter elasticsearchConverter, MappingParametersCustomizer customizer) {
this.elasticsearchConverter = elasticsearchConverter;
this.customizer = customizer;
}
/**
@@ -275,7 +279,7 @@ public class MappingBuilder {
writeTypeHintMapping(propertiesNode);
if (entity != null) {
entity.doWithProperties((PropertyHandler<@NonNull ElasticsearchPersistentProperty>) property -> {
entity.doWithProperties((PropertyHandler<ElasticsearchPersistentProperty>) property -> {
try {
if (property.isAnnotationPresent(Transient.class) || isInIgnoreFields(property, parentFieldAnnotation)) {
return;
@@ -589,7 +593,7 @@ public class MappingBuilder {
private void addFieldMappingParameters(ObjectNode fieldNode, Annotation annotation, boolean nestedOrObjectField)
throws IOException {
MappingParameters mappingParameters = MappingParameters.from(annotation);
MappingParameters mappingParameters = customizer.from(annotation);
if (!nestedOrObjectField && mappingParameters.isStore()) {
fieldNode.put(FIELD_PARAM_STORE, true);
@@ -34,7 +34,9 @@ import org.springframework.util.StringUtils;
/**
* A class to hold the mapping parameters that might be set on
* {@link org.springframework.data.elasticsearch.annotations.Field } or
* {@link org.springframework.data.elasticsearch.annotations.InnerField} annotation.
* {@link org.springframework.data.elasticsearch.annotations.InnerField} annotation. The class allows extensibility
* (non-final) to simplify mapping parameters customization, provided by
* {@link org.springframework.data.elasticsearch.core.index.MappingParametersCustomizer}.
*
* @author Peter-Josef Meisch
* @author Aleksei Arsenev
@@ -42,9 +44,10 @@ import org.springframework.util.StringUtils;
* @author Morgan Lutz
* @author Sascha Woo
* @author Haibo Liu
* @author Andriy Redko
* @since 4.0
*/
public final class MappingParameters {
public class MappingParameters {
static final String FIELD_PARAM_COERCE = "coerce";
static final String FIELD_PARAM_COPY_TO = "copy_to";
@@ -86,7 +89,7 @@ public final class MappingParameters {
private final String analyzer;
private final boolean coerce;
@Nullable private final String[] copyTo;
private final String @Nullable [] copyTo;
private final DateFormat[] dateFormats;
private final String[] dateFormatPatterns;
private final boolean docValues;
@@ -137,7 +140,7 @@ public final class MappingParameters {
}
}
private MappingParameters(Field field) {
protected MappingParameters(Field field) {
index = field.index();
store = field.store();
fielddata = field.fielddata();
@@ -184,7 +187,7 @@ public final class MappingParameters {
eagerGlobalOrdinals = field.eagerGlobalOrdinals();
}
private MappingParameters(InnerField field) {
protected MappingParameters(InnerField field) {
index = field.index();
store = field.store();
fielddata = field.fielddata();
@@ -417,4 +420,132 @@ public final class MappingParameters {
objectNode.put(FIELD_PARAM_EAGER_GLOBAL_ORDINALS, eagerGlobalOrdinals);
}
}
protected String analyzer() {
return analyzer;
}
protected boolean coerce() {
return coerce;
}
protected String @Nullable [] copyTo() {
return copyTo;
}
protected DateFormat[] dateFormats() {
return dateFormats;
}
protected String[] dateFormatPatterns() {
return dateFormatPatterns;
}
protected boolean hasDocValues() {
return docValues;
}
protected boolean hasEagerGlobalOrdinals() {
return eagerGlobalOrdinals;
}
protected boolean isEnabled() {
return enabled;
}
protected boolean hasFielddata() {
return fielddata;
}
protected Integer ignoreAbove() {
return ignoreAbove;
}
protected boolean isIgnoreMalformed() {
return ignoreMalformed;
}
protected boolean isIndex() {
return index;
}
protected IndexOptions indexOptions() {
return indexOptions;
}
protected boolean isIndexPhrases() {
return indexPhrases;
}
protected IndexPrefixes indexPrefixes() {
return indexPrefixes;
}
protected String normalizer() {
return normalizer;
}
protected boolean hasNorms() {
return norms;
}
protected Integer maxShingleSize() {
return maxShingleSize;
}
protected String nullValue() {
return nullValue;
}
protected NullValueType nullValueType() {
return nullValueType;
}
protected Integer positionIncrementGap() {
return positionIncrementGap;
}
protected boolean positiveScoreImpact() {
return positiveScoreImpact;
}
protected Integer dims() {
return dims;
}
protected String elementType() {
return elementType;
}
protected KnnSimilarity knnSimilarity() {
return knnSimilarity;
}
protected KnnIndexOptions knnIndexOptions() {
return knnIndexOptions;
}
protected String searchAnalyzer() {
return searchAnalyzer;
}
protected double scalingFactor() {
return scalingFactor;
}
protected String similarity() {
return similarity;
}
protected TermVector termVector() {
return termVector;
}
protected FieldType type() {
return type;
}
protected String mappedTypeName() {
return mappedTypeName;
}
}
@@ -0,0 +1,36 @@
/*
* Copyright 2026-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.core.index;
import java.lang.annotation.Annotation;
/**
* Allows to customize {@link org.springframework.data.elasticsearch.core.index.MappingParameters} that are being
* emitted for each supported annotation. Needed by dependent projects like Spring-Data-Opensearch.
*
* @author Andriy Redko
* @since 6.1.0
*/
public interface MappingParametersCustomizer {
/**
* Customize @link org.springframework.data.elasticsearch.core.index.MappingParameters} for each supported annotation.
*
* @param annotation supported annotation
* @return customized @link org.springframework.data.elasticsearch.core.index.MappingParameters}
*/
MappingParameters from(Annotation annotation);
}
@@ -102,7 +102,7 @@ public class PutTemplateRequest {
this.indexPatterns = indexPatterns;
}
public TemplateRequestBuilder withSettings(Map<String, Object> settings) {
public TemplateRequestBuilder withSettings(Map<String, @Nullable Object> settings) {
this.settings = new Settings(settings);
return this;
}
@@ -31,6 +31,7 @@ import org.springframework.data.mapping.MappingException;
* Subclass of {@link MappingBuilder} with specialized methods To inhibit blocking calls
*
* @author Peter-Josef Meisch
* @author Andriy Redko
* @since 4.3
*/
public class ReactiveMappingBuilder extends MappingBuilder {
@@ -39,6 +40,10 @@ public class ReactiveMappingBuilder extends MappingBuilder {
super(elasticsearchConverter);
}
public ReactiveMappingBuilder(ElasticsearchConverter elasticsearchConverter, MappingParametersCustomizer customizer) {
super(elasticsearchConverter, customizer);
}
@Override
public String buildPropertyMapping(Class<?> clazz) throws MappingException {
throw new UnsupportedOperationException(
@@ -21,6 +21,7 @@ import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.jspecify.annotations.Nullable;
import org.springframework.data.elasticsearch.support.DefaultStringObjectMap;
import org.springframework.util.Assert;
@@ -34,7 +35,7 @@ public class Settings extends DefaultStringObjectMap<Settings> {
public Settings() {}
public Settings(Map<String, Object> map) {
public Settings(Map<String, @Nullable Object> map) {
super(map);
}
@@ -54,7 +55,7 @@ public class Settings extends DefaultStringObjectMap<Settings> {
}
@Override
public Object get(Object key) {
public Object get(@Nullable Object key) {
return containsKey(key) ? super.get(key) : path(key.toString());
}
@@ -75,11 +76,11 @@ public class Settings extends DefaultStringObjectMap<Settings> {
* taken from https://stackoverflow.com/a/29698326/4393565
*/
@SuppressWarnings("unchecked")
private static Map<?, ?> deepMerge(Map<String, Object> original, Map<String, Object> newMap) {
private static Map<?, ?> deepMerge(Map<String, @Nullable Object> original, Map<String, @Nullable Object> newMap) {
for (Object key : newMap.keySet()) {
if (newMap.get(key) instanceof Map && original.get(key) instanceof Map) {
Map<String, Object> originalChild = (Map<String, Object>) original.get(key);
Map<String, Object> newChild = (Map<String, Object>) newMap.get(key);
Map<String, @Nullable Object> originalChild = (Map<String, Object>) original.get(key);
Map<String, @Nullable Object> newChild = (Map<String, Object>) newMap.get(key);
original.put(key.toString(), deepMerge(originalChild, newChild));
} else if (newMap.get(key) instanceof List && original.get(key) instanceof List) {
List<Object> originalChild = (List<Object>) original.get(key);
@@ -112,9 +113,9 @@ public class Settings extends DefaultStringObjectMap<Settings> {
* flattens a Map<String, Object> to a stream of Map.Entry objects where the keys are the dot separated concatenated
* keys of sub map entries
*/
static private Stream<Map.Entry<String, Object>> doFlatten(Map.Entry<String, Object> entry) {
static private Stream<Map.Entry<String, @Nullable Object>> doFlatten(Map.Entry<String, @Nullable Object> entry) {
if (entry.getValue()instanceof Map<?, ?> nested) {
if (entry.getValue() instanceof Map<?, ?> nested) {
// noinspection unchecked
return nested.entrySet().stream() //
@@ -91,7 +91,7 @@ public class TemplateData {
return this;
}
public TemplateDataBuilder withSettings(Map<String, Object> settings) {
public TemplateDataBuilder withSettings(Map<String, @Nullable Object> settings) {
this.settings = new Settings(settings);
return this;
}
@@ -1,5 +1,18 @@
/**
* Classes related to Elasticsearch index management.
/*
* 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.
* 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.
*/
@org.jspecify.annotations.NullMarked
package org.springframework.data.elasticsearch.core.index;
@@ -64,7 +64,7 @@ public class JoinField<ID> {
}
@Override
public boolean equals(Object obj) {
public boolean equals(@Nullable Object obj) {
if (this == obj) {
return true;
}
@@ -0,0 +1,18 @@
/*
* 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.
* 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.
*/
@org.jspecify.annotations.NullMarked
package org.springframework.data.elasticsearch.core.join;
@@ -115,7 +115,7 @@ public class Alias {
}
@Override
public boolean equals(Object o) {
public boolean equals(@Nullable Object o) {
if (this == o)
return true;
if (!(o instanceof Alias that))
@@ -33,7 +33,7 @@ public class CreateIndexSettings {
private final IndexCoordinates indexCoordinates;
private final Set<Alias> aliases;
@Nullable private final Map<String, Object> settings;
@Nullable private final Map<String, @Nullable Object> settings;
@Nullable private final Document mapping;
@@ -58,7 +58,7 @@ public class CreateIndexSettings {
}
@Nullable
public Map<String, Object> getSettings() {
public Map<String, @Nullable Object> getSettings() {
return settings;
}
@@ -71,7 +71,7 @@ public class CreateIndexSettings {
private final IndexCoordinates indexCoordinates;
private final Set<Alias> aliases = new HashSet<>();
@Nullable private Map<String, Object> settings;
@Nullable private Map<String, @Nullable Object> settings;
@Nullable private Document mapping;
@@ -94,7 +94,7 @@ public class CreateIndexSettings {
return this;
}
public Builder withSettings(Map<String, Object> settings) {
public Builder withSettings(Map<String, @Nullable Object> settings) {
Assert.notNull(settings, "settings must not be null");
this.settings = settings;
@@ -17,6 +17,7 @@ package org.springframework.data.elasticsearch.core.mapping;
import java.util.Arrays;
import org.jspecify.annotations.Nullable;
import org.springframework.util.Assert;
/**
@@ -55,7 +56,7 @@ public class IndexCoordinates {
* @since 4.2
*/
@Override
public boolean equals(Object o) {
public boolean equals(@Nullable Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
@@ -23,9 +23,7 @@ import java.util.concurrent.atomic.AtomicReference;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.Nullable;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.core.TypeInformation;
@@ -263,6 +261,7 @@ public class SimpleElasticsearchPersistentEntity<T> extends BasicPersistentEntit
throw new MappingException("@IndexedIndexName annotation must be put on String property");
}
// noinspection VariableNotUsedInsideIf
if (indexedIndexNameProperty != null) {
throw new MappingException(
"@IndexedIndexName annotation can only be put on one property in an entity");
@@ -301,7 +300,7 @@ public class SimpleElasticsearchPersistentEntity<T> extends BasicPersistentEntit
return fieldNamePropertyCache.computeIfAbsent(fieldName, key -> {
AtomicReference<@Nullable ElasticsearchPersistentProperty> propertyRef = new AtomicReference<>();
doWithProperties((PropertyHandler<@NonNull ElasticsearchPersistentProperty>) property -> {
doWithProperties((PropertyHandler<ElasticsearchPersistentProperty>) property -> {
if (key.equals(property.getFieldName())) {
propertyRef.set(property);
}
@@ -425,8 +424,7 @@ public class SimpleElasticsearchPersistentEntity<T> extends BasicPersistentEntit
try {
Expression expression = routingExpressions.computeIfAbsent(routing, PARSER::parseExpression);
ExpressionDependencies expressionDependencies = expression != null ? ExpressionDependencies.discover(expression)
: ExpressionDependencies.none();
ExpressionDependencies expressionDependencies = ExpressionDependencies.discover(expression);
EvaluationContext context = getEvaluationContext(null, expressionDependencies);
context.setVariable("entity", bean);
@@ -1,2 +1,18 @@
/*
* 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.
* 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.
*/
@org.jspecify.annotations.NullMarked
package org.springframework.data.elasticsearch.core.mapping;
@@ -1,2 +1,18 @@
/*
* 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.
* 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.
*/
@org.jspecify.annotations.NullMarked
package org.springframework.data.elasticsearch.core;
@@ -602,6 +602,7 @@ public class BaseQuery implements Query {
// searchForStream to work correctly (#3098) as there the page size defines what is
// returned in a single request, and the max result determines the total number of
// documents returned.
// noinspection DataFlowIssue maxResults is not null here, this is checked with isLimiting()
requestSize = Math.min(pageable.getPageSize(), getMaxResults());
}
} else if (pageable == UNSET_PAGE) {
@@ -622,6 +623,7 @@ public class BaseQuery implements Query {
// searchForStream to work correctly (#3098) as there the page size defines what is
// returned in a single request, and the max result determines the total number of
// documents returned.
// noinspection DataFlowIssue maxResults is not null here, this is checked with isLimiting()
requestSize = Math.min(INDEX_MAX_RESULT_WINDOW, getMaxResults());
}
}
@@ -97,7 +97,6 @@ public abstract class BaseQueryBuilder<Q extends BaseQuery, SELF extends BaseQue
return maxResults;
}
@Nullable
public Collection<String> getIds() {
return ids;
}
@@ -182,7 +181,7 @@ public abstract class BaseQueryBuilder<Q extends BaseQuery, SELF extends BaseQue
* @since 6.1
*/
@Nullable
public Boolean getIncludeNamedQueriesScore(){
public Boolean getIncludeNamedQueriesScore() {
return includeNamedQueryScore;
}
@@ -393,7 +392,7 @@ public abstract class BaseQueryBuilder<Q extends BaseQuery, SELF extends BaseQue
/**
* @since 6.1
*/
public SELF withIncludeNamedQueryScore (@Nullable Boolean namedQueryScore) {
public SELF withIncludeNamedQueryScore(@Nullable Boolean namedQueryScore) {
this.includeNamedQueryScore = namedQueryScore;
return self();
}
@@ -61,16 +61,16 @@ public class Criteria {
private float boost = Float.NaN;
private boolean negating = false;
// we cash this and recalculate when properties used in equals change
// see https://github.com/spring-projects/spring-data-elasticsearch/issues/3083
private int hashCode;
// we cache this and recalculate when properties used in equals change
// see https://github.com/spring-projects/spring-data-elasticsearch/issues/3083
private int hashCode;
private final CriteriaChain criteriaChain = new CriteriaChain();
private final Set<CriteriaEntry> queryCriteriaEntries = new LinkedHashSet<>();
private final Set<CriteriaEntry> filterCriteriaEntries = new LinkedHashSet<>();
private final Set<Criteria> subCriteria = new LinkedHashSet<>();
private final CriteriaChain criteriaChain = new CriteriaChain();
private final Set<CriteriaEntry> queryCriteriaEntries = new LinkedHashSet<>();
private final Set<CriteriaEntry> filterCriteriaEntries = new LinkedHashSet<>();
private final Set<Criteria> subCriteria = new LinkedHashSet<>();
// region criteria creation
// region criteria creation
/**
* @return factory method to create an and-Criteria that is not bound to a field
@@ -89,8 +89,8 @@ public class Criteria {
}
public Criteria() {
recalculateHashCode();
}
recalculateHashCode();
}
/**
* Creates a new Criteria with provided field name
@@ -113,7 +113,7 @@ public class Criteria {
this.field = field;
this.criteriaChain.add(this);
recalculateHashCode();
recalculateHashCode();
}
/**
@@ -143,7 +143,7 @@ public class Criteria {
this.field = field;
this.criteriaChain.addAll(criteriaChain);
this.criteriaChain.add(this);
recalculateHashCode();
recalculateHashCode();
}
/**
@@ -197,7 +197,7 @@ public class Criteria {
*/
public Criteria not() {
this.negating = true;
recalculateHashCode();
recalculateHashCode();
return this;
}
@@ -216,7 +216,7 @@ public class Criteria {
Assert.isTrue(boost >= 0, "boost must not be negative");
this.boost = boost;
recalculateHashCode();
recalculateHashCode();
return this;
}
@@ -274,7 +274,7 @@ public class Criteria {
Assert.notNull(criteria, "Cannot chain 'null' criteria.");
this.criteriaChain.add(criteria);
recalculateHashCode();
recalculateHashCode();
return this;
}
@@ -289,7 +289,7 @@ public class Criteria {
Assert.notNull(criterias, "Cannot chain 'null' criterias.");
this.criteriaChain.addAll(Arrays.asList(criterias));
recalculateHashCode();
recalculateHashCode();
return this;
}
@@ -332,7 +332,7 @@ public class Criteria {
orCriteria.subCriteria.addAll(criteria.subCriteria);
orCriteria.boost = criteria.boost;
orCriteria.negating = criteria.isNegating();
orCriteria.recalculateHashCode();
orCriteria.recalculateHashCode();
return orCriteria;
}
@@ -348,7 +348,7 @@ public class Criteria {
Assert.notNull(criteria, "criteria must not be null");
subCriteria.add(criteria);
recalculateHashCode();
recalculateHashCode();
return this;
}
@@ -363,7 +363,7 @@ public class Criteria {
*/
public Criteria is(Object o) {
queryCriteriaEntries.add(new CriteriaEntry(OperationKey.EQUALS, o));
recalculateHashCode();
recalculateHashCode();
return this;
}
@@ -375,7 +375,7 @@ public class Criteria {
*/
public Criteria exists() {
queryCriteriaEntries.add(new CriteriaEntry(OperationKey.EXISTS));
recalculateHashCode();
recalculateHashCode();
return this;
}
@@ -394,7 +394,7 @@ public class Criteria {
}
queryCriteriaEntries.add(new CriteriaEntry(OperationKey.BETWEEN, new Object[] { lowerBound, upperBound }));
recalculateHashCode();
recalculateHashCode();
return this;
}
@@ -410,7 +410,7 @@ public class Criteria {
assertNoBlankInWildcardQuery(s, false, true);
queryCriteriaEntries.add(new CriteriaEntry(OperationKey.STARTS_WITH, s));
recalculateHashCode();
recalculateHashCode();
return this;
}
@@ -427,7 +427,7 @@ public class Criteria {
assertNoBlankInWildcardQuery(s, true, true);
queryCriteriaEntries.add(new CriteriaEntry(OperationKey.CONTAINS, s));
recalculateHashCode();
recalculateHashCode();
return this;
}
@@ -444,7 +444,7 @@ public class Criteria {
assertNoBlankInWildcardQuery(s, true, false);
queryCriteriaEntries.add(new CriteriaEntry(OperationKey.ENDS_WITH, s));
recalculateHashCode();
recalculateHashCode();
return this;
}
@@ -472,7 +472,7 @@ public class Criteria {
Assert.notNull(values, "Collection of 'in' values must not be null");
queryCriteriaEntries.add(new CriteriaEntry(OperationKey.IN, values));
recalculateHashCode();
recalculateHashCode();
return this;
}
@@ -499,7 +499,7 @@ public class Criteria {
Assert.notNull(values, "Collection of 'NotIn' values must not be null");
queryCriteriaEntries.add(new CriteriaEntry(OperationKey.NOT_IN, values));
recalculateHashCode();
recalculateHashCode();
return this;
}
@@ -512,7 +512,7 @@ public class Criteria {
*/
public Criteria expression(String s) {
queryCriteriaEntries.add(new CriteriaEntry(OperationKey.EXPRESSION, s));
recalculateHashCode();
recalculateHashCode();
return this;
}
@@ -524,7 +524,7 @@ public class Criteria {
*/
public Criteria fuzzy(String s) {
queryCriteriaEntries.add(new CriteriaEntry(OperationKey.FUZZY, s));
recalculateHashCode();
recalculateHashCode();
return this;
}
@@ -539,7 +539,7 @@ public class Criteria {
Assert.notNull(upperBound, "upperBound must not be null");
queryCriteriaEntries.add(new CriteriaEntry(OperationKey.LESS_EQUAL, upperBound));
recalculateHashCode();
recalculateHashCode();
return this;
}
@@ -554,7 +554,7 @@ public class Criteria {
Assert.notNull(upperBound, "upperBound must not be null");
queryCriteriaEntries.add(new CriteriaEntry(OperationKey.LESS, upperBound));
recalculateHashCode();
recalculateHashCode();
return this;
}
@@ -569,7 +569,7 @@ public class Criteria {
Assert.notNull(lowerBound, "lowerBound must not be null");
queryCriteriaEntries.add(new CriteriaEntry(OperationKey.GREATER_EQUAL, lowerBound));
recalculateHashCode();
recalculateHashCode();
return this;
}
@@ -584,7 +584,7 @@ public class Criteria {
Assert.notNull(lowerBound, "lowerBound must not be null");
queryCriteriaEntries.add(new CriteriaEntry(OperationKey.GREATER, lowerBound));
recalculateHashCode();
recalculateHashCode();
return this;
}
@@ -601,7 +601,7 @@ public class Criteria {
Assert.notNull(value, "value must not be null");
queryCriteriaEntries.add(new CriteriaEntry(OperationKey.MATCHES, value));
recalculateHashCode();
recalculateHashCode();
return this;
}
@@ -618,7 +618,7 @@ public class Criteria {
Assert.notNull(value, "value must not be null");
queryCriteriaEntries.add(new CriteriaEntry(OperationKey.MATCHES_ALL, value));
recalculateHashCode();
recalculateHashCode();
return this;
}
@@ -631,7 +631,7 @@ public class Criteria {
public Criteria empty() {
queryCriteriaEntries.add(new CriteriaEntry(OperationKey.EMPTY));
recalculateHashCode();
recalculateHashCode();
return this;
}
@@ -644,7 +644,7 @@ public class Criteria {
public Criteria notEmpty() {
queryCriteriaEntries.add(new CriteriaEntry(OperationKey.NOT_EMPTY));
recalculateHashCode();
recalculateHashCode();
return this;
}
@@ -660,7 +660,7 @@ public class Criteria {
Assert.notNull(value, "value must not be null");
queryCriteriaEntries.add(new CriteriaEntry(OperationKey.REGEXP, value));
recalculateHashCode();
recalculateHashCode();
return this;
}
@@ -679,7 +679,7 @@ public class Criteria {
Assert.notNull(boundingBox, "boundingBox value for boundedBy criteria must not be null");
filterCriteriaEntries.add(new CriteriaEntry(OperationKey.BBOX, new Object[] { boundingBox }));
recalculateHashCode();
recalculateHashCode();
return this;
}
@@ -696,7 +696,7 @@ public class Criteria {
filterCriteriaEntries
.add(new CriteriaEntry(OperationKey.BBOX, new Object[] { boundingBox.getFirst(), boundingBox.getSecond() }));
recalculateHashCode();
recalculateHashCode();
return this;
}
@@ -714,7 +714,7 @@ public class Criteria {
filterCriteriaEntries
.add(new CriteriaEntry(OperationKey.BBOX, new Object[] { topLeftGeohash, bottomRightGeohash }));
recalculateHashCode();
recalculateHashCode();
return this;
}
@@ -731,7 +731,7 @@ public class Criteria {
Assert.notNull(bottomRightPoint, "bottomRightPoint must not be null");
filterCriteriaEntries.add(new CriteriaEntry(OperationKey.BBOX, new Object[] { topLeftPoint, bottomRightPoint }));
recalculateHashCode();
recalculateHashCode();
return this;
}
@@ -749,7 +749,7 @@ public class Criteria {
filterCriteriaEntries.add(new CriteriaEntry(OperationKey.BBOX,
new Object[] { GeoPoint.fromPoint(topLeftPoint), GeoPoint.fromPoint(bottomRightPoint) }));
recalculateHashCode();
recalculateHashCode();
return this;
}
@@ -767,7 +767,7 @@ public class Criteria {
Assert.notNull(location, "Distance value for near criteria must not be null");
filterCriteriaEntries.add(new CriteriaEntry(OperationKey.WITHIN, new Object[] { location, distance }));
recalculateHashCode();
recalculateHashCode();
return this;
}
@@ -784,7 +784,7 @@ public class Criteria {
Assert.notNull(location, "Distance value for near criteria must not be null");
filterCriteriaEntries.add(new CriteriaEntry(OperationKey.WITHIN, new Object[] { location, distance }));
recalculateHashCode();
recalculateHashCode();
return this;
}
@@ -801,7 +801,7 @@ public class Criteria {
Assert.isTrue(StringUtils.hasLength(geoLocation), "geoLocation value must not be null");
filterCriteriaEntries.add(new CriteriaEntry(OperationKey.WITHIN, new Object[] { geoLocation, distance }));
recalculateHashCode();
recalculateHashCode();
return this;
}
@@ -816,7 +816,7 @@ public class Criteria {
Assert.notNull(geoShape, "geoShape must not be null");
filterCriteriaEntries.add(new CriteriaEntry(OperationKey.GEO_INTERSECTS, geoShape));
recalculateHashCode();
recalculateHashCode();
return this;
}
@@ -831,7 +831,7 @@ public class Criteria {
Assert.notNull(geoShape, "geoShape must not be null");
filterCriteriaEntries.add(new CriteriaEntry(OperationKey.GEO_IS_DISJOINT, geoShape));
recalculateHashCode();
recalculateHashCode();
return this;
}
@@ -845,7 +845,7 @@ public class Criteria {
Assert.notNull(geoShape, "geoShape must not be null");
filterCriteriaEntries.add(new CriteriaEntry(OperationKey.GEO_WITHIN, geoShape));
recalculateHashCode();
recalculateHashCode();
return this;
}
@@ -859,7 +859,7 @@ public class Criteria {
Assert.notNull(geoShape, "geoShape must not be null");
filterCriteriaEntries.add(new CriteriaEntry(OperationKey.GEO_CONTAINS, geoShape));
recalculateHashCode();
recalculateHashCode();
return this;
}
@@ -873,7 +873,7 @@ public class Criteria {
Assert.notNull(query, "has_child query must not be null.");
queryCriteriaEntries.add(new CriteriaEntry(OperationKey.HAS_CHILD, query));
recalculateHashCode();
recalculateHashCode();
return this;
}
@@ -887,7 +887,7 @@ public class Criteria {
Assert.notNull(query, "has_parent query must not be null.");
queryCriteriaEntries.add(new CriteriaEntry(OperationKey.HAS_PARENT, query));
recalculateHashCode();
recalculateHashCode();
return this;
}
// endregion
@@ -909,7 +909,7 @@ public class Criteria {
// region equals/hashcode
@Override
public boolean equals(Object o) {
public boolean equals(@Nullable Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
@@ -937,19 +937,19 @@ public class Criteria {
return hashCode;
}
private void recalculateHashCode() {
int result = field != null ? field.hashCode() : 0;
result = 31 * result + (boost != +0.0f ? Float.floatToIntBits(boost) : 0);
result = 31 * result + (negating ? 1 : 0);
// the criteriaChain contains "this" object, so we need to filter it out
// to avoid a stackoverflow here, because the hashcode implementation
// uses the element's hashcodes
result = 31 * result + criteriaChain.filter(this).hashCode();
result = 31 * result + queryCriteriaEntries.hashCode();
result = 31 * result + filterCriteriaEntries.hashCode();
result = 31 * result + subCriteria.hashCode();
this.hashCode = result;
}
private void recalculateHashCode() {
int result = field != null ? field.hashCode() : 0;
result = 31 * result + (boost != +0.0f ? Float.floatToIntBits(boost) : 0);
result = 31 * result + (negating ? 1 : 0);
// the criteriaChain contains "this" object, so we need to filter it out
// to avoid a stackoverflow here, because the hashcode implementation
// uses the element's hashcodes
result = 31 * result + criteriaChain.filter(this).hashCode();
result = 31 * result + queryCriteriaEntries.hashCode();
result = 31 * result + filterCriteriaEntries.hashCode();
result = 31 * result + subCriteria.hashCode();
this.hashCode = result;
}
// endregion
@Override
@@ -1141,7 +1141,7 @@ public class Criteria {
}
@Override
public boolean equals(Object o) {
public boolean equals(@Nullable Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
@@ -354,7 +354,6 @@ public class DeleteQuery {
return version;
}
@Nullable
public Query getQuery() {
return query;
}
@@ -648,6 +647,7 @@ public class DeleteQuery {
return this;
}
@SuppressWarnings("VariableNotUsedInsideIf")
public DeleteQuery build() {
if (luceneQuery == null) {
if (defaultField != null) {
@@ -29,14 +29,14 @@ import org.springframework.util.Assert;
public class FetchSourceFilter implements SourceFilter {
@Nullable private final Boolean fetchSource;
@Nullable private final String[] includes;
@Nullable private final String[] excludes;
private final String @Nullable [] includes;
private final String @Nullable [] excludes;
/**
* @since 5.2
*/
public static SourceFilter of(@Nullable Boolean fetchSource, @Nullable final String[] includes,
@Nullable final String[] excludes) {
public static SourceFilter of(@Nullable Boolean fetchSource, final String @Nullable [] includes,
final String @Nullable [] excludes) {
return new FetchSourceFilter(fetchSource, includes, excludes);
}
@@ -50,25 +50,25 @@ public class FetchSourceFilter implements SourceFilter {
return builderFunction.apply(new FetchSourceFilterBuilder()).build();
}
public FetchSourceFilter(@Nullable Boolean fetchSource, @Nullable final String[] includes,
@Nullable final String[] excludes) {
public FetchSourceFilter(@Nullable Boolean fetchSource, final String @Nullable [] includes,
final String @Nullable [] excludes) {
this.fetchSource = fetchSource;
this.includes = includes;
this.excludes = excludes;
}
@Override
public Boolean fetchSource() {
public @Nullable Boolean fetchSource() {
return fetchSource;
}
@Override
public @Nullable String[] getIncludes() {
public String @Nullable [] getIncludes() {
return includes;
}
@Override
public @Nullable String[] getExcludes() {
public String @Nullable [] getExcludes() {
return excludes;
}
}
@@ -43,7 +43,7 @@ public class GeoDistanceOrder extends Order {
}
private GeoDistanceOrder(String property, GeoPoint geoPoint, Sort.Direction direction, DistanceType distanceType,
Mode mode, String unit, Boolean ignoreUnmapped) {
@Nullable Mode mode, String unit, Boolean ignoreUnmapped) {
super(direction, property, mode);
this.geoPoint = geoPoint;
this.distanceType = distanceType;
@@ -59,7 +59,7 @@ public class GeoDistanceOrder extends Order {
return distanceType;
}
public Mode getMode() {
public @Nullable Mode getMode() {
return mode;
}
@@ -83,7 +83,7 @@ public class SimpleField implements Field {
}
@Override
public boolean equals(Object o) {
public boolean equals(@Nullable Object o) {
if (this == o)
return true;
if (!(o instanceof SimpleField that))
@@ -1,2 +1,18 @@
/*
* 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.
* 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.
*/
@org.jspecify.annotations.NullMarked
package org.springframework.data.elasticsearch.core.query;
@@ -1,2 +1,18 @@
/*
* 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.
* 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.
*/
@org.jspecify.annotations.NullMarked
package org.springframework.data.elasticsearch.core.query.types;
@@ -1,2 +1,18 @@
/*
* 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.
* 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.
*/
@org.jspecify.annotations.NullMarked
package org.springframework.data.elasticsearch.core.reindex;
@@ -37,7 +37,7 @@ public class DefaultRoutingResolver implements RoutingResolver {
}
@Override
public String getRouting() {
public @Nullable String getRouting() {
return null;
}
@@ -1,5 +1,18 @@
/**
* classes/interfaces for specification and implementation of Elasticsearch routing.
/*
* 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.
* 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.
*/
@org.jspecify.annotations.NullMarked
package org.springframework.data.elasticsearch.core.routing;
@@ -1,6 +1,18 @@
/**
* Classes and interfaces to access to script API of Elasticsearch
* (https://www.elastic.co/guide/en/elasticsearch/reference/8.5/script-apis.html).
/*
* 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.
* 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.
*/
@org.jspecify.annotations.NullMarked
package org.springframework.data.elasticsearch.core.script;
@@ -25,7 +25,6 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.Nullable;
/**
@@ -110,7 +109,6 @@ public class SqlResponse {
return new Builder();
}
@NonNull
@Override
public Iterator<Map.Entry<Column, JsonValue>> iterator() {
return row.entrySet().iterator();
@@ -1,5 +1,18 @@
/**
* Classes and interfaces to access to SQL API of Elasticsearch.
/*
* 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.
* 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.
*/
@org.jspecify.annotations.NullMarked
package org.springframework.data.elasticsearch.core.sql;
@@ -1,2 +1,18 @@
/*
* 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.
* 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.
*/
@org.jspecify.annotations.NullMarked
package org.springframework.data.elasticsearch.core.suggest.response;
@@ -1,2 +1,18 @@
/*
* 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.
* 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.
*/
@org.jspecify.annotations.NullMarked
package org.springframework.data.elasticsearch;
@@ -44,7 +44,7 @@ public interface ElasticsearchRepository<T, ID> extends PagingAndSortingReposito
* @param pageable , must not be {@literal null}
* @return
*/
Page<T> searchSimilar(T entity, @Nullable String[] fields, Pageable pageable);
Page<T> searchSimilar(T entity, String @Nullable [] fields, Pageable pageable);
/**
* @since 5.2
@@ -1,2 +1,18 @@
/*
* 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.
* 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.
*/
@org.jspecify.annotations.NullMarked
package org.springframework.data.elasticsearch.repository.aot;
@@ -1,2 +1,18 @@
/*
* 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.
* 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.
*/
@org.jspecify.annotations.NullMarked
package org.springframework.data.elasticsearch.repository.cdi;
@@ -1,2 +1,18 @@
/*
* 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.
* 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.
*/
@org.jspecify.annotations.NullMarked
package org.springframework.data.elasticsearch.repository.config;
@@ -1,5 +1,18 @@
/**
* infrastructure to define the Elasticsearch mapping for an index.
/*
* 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.
* 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.
*/
@org.jspecify.annotations.NullMarked
package org.springframework.data.elasticsearch.repository;
@@ -15,6 +15,8 @@
*/
package org.springframework.data.elasticsearch.repository.query;
import java.util.Objects;
import org.jspecify.annotations.Nullable;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
@@ -82,13 +84,17 @@ public abstract class AbstractElasticsearchRepositoryQuery implements Repository
protected abstract boolean isExistsQuery();
@Override
public Object execute(Object[] parameters) {
public Object execute(@Nullable Object[] parameters) {
ElasticsearchParametersParameterAccessor parameterAccessor = getParameterAccessor(parameters);
// need this additional var, otherwise the code analysis does not recognize
// that parameters is not null after the check
var parametersNN = Objects.requireNonNull(parameters, "parameters must not be null");
ElasticsearchParametersParameterAccessor parameterAccessor = getParameterAccessor(parametersNN);
ResultProcessor resultProcessor = queryMethod.getResultProcessor().withDynamicProjection(parameterAccessor);
Class<?> clazz = resultProcessor.getReturnedType().getDomainType();
Query query = createQuery(parameters);
Query query = createQuery(parametersNN);
IndexCoordinates index = parameterAccessor
.getIndexCoordinates(elasticsearchOperations.getIndexCoordinatesFor(clazz));
@@ -18,6 +18,9 @@ package org.springframework.data.elasticsearch.repository.query;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.util.Objects;
import org.jspecify.annotations.Nullable;
import org.reactivestreams.Publisher;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperations;
@@ -72,10 +75,12 @@ abstract class AbstractReactiveElasticsearchRepositoryQuery implements Repositor
* @see org.springframework.data.repository.query.RepositoryQuery#execute(java.lang.Object[])
*/
@Override
public Object execute(Object[] parameters) {
public Object execute(@Nullable Object[] parameters) {
Object result = queryMethod.hasReactiveWrapperParameter() ? executeDeferred(parameters)
: execute(new ReactiveElasticsearchParametersParameterAccessor(queryMethod, parameters));
var parametersNN = Objects.requireNonNull(parameters, "parameters must not be null");
Object result = queryMethod.hasReactiveWrapperParameter() ? executeDeferred(parametersNN)
: execute(new ReactiveElasticsearchParametersParameterAccessor(queryMethod, parametersNN));
return queryMethod.isNotSearchHitMethod() ? SearchHitSupport.unwrapSearchHits(result) : result;
}
@@ -98,7 +103,7 @@ abstract class AbstractReactiveElasticsearchRepositoryQuery implements Repositor
Class<?> domainType = returnedType.getDomainType();
Class<?> typeToRead = returnedType.getTypeToRead();
if (SearchHit.class.isAssignableFrom(typeToRead)) {
if (typeToRead != null && SearchHit.class.isAssignableFrom(typeToRead)) {
typeToRead = queryMethod.unwrappedReturnType;
}
@@ -145,9 +150,10 @@ abstract class AbstractReactiveElasticsearchRepositoryQuery implements Repositor
.map(count -> count > 0);
} else if (queryMethod.isCollectionQuery()) {
return (query, type, targetType, indexCoordinates) -> operations.search(query.setPageable(accessor.getPageable()),
type, targetType, indexCoordinates);
type, Objects.requireNonNull(targetType), indexCoordinates);
} else {
return operations::search;
return (query, type, targetType, index) -> operations.search(query, type, Objects.requireNonNull(targetType),
index);
}
}
@@ -1,2 +1,18 @@
/*
* 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.
* 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.
*/
@org.jspecify.annotations.NullMarked
package org.springframework.data.elasticsearch.repository.query;
@@ -1,2 +1,18 @@
/*
* 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.
* 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.
*/
@org.jspecify.annotations.NullMarked
package org.springframework.data.elasticsearch.repository.query.parser;

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