Compare commits

...

8 Commits

Author SHA1 Message Date
Peter-Josef Meisch
e49bb63df4
Fix handling of ResponseException from legacy client dependency.
Original Pull Request #3146
Closes #3144

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

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

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

Signed-off-by: Anton Buz <buzdalkin.a@vlprojects.pro>
2025-07-22 18:35:43 +02:00
Mark Paluch
55d470fc91
After release cleanups.
See #3115
2025-07-18 13:14:47 +02:00
Mark Paluch
b7290b5d9c
Prepare next development iteration.
See #3115
2025-07-18 13:14:46 +02:00
62 changed files with 565 additions and 387 deletions

24
pom.xml
View File

@ -5,12 +5,12 @@
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-elasticsearch</artifactId>
<version>6.0.0-M4</version>
<version>6.0.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.data.build</groupId>
<artifactId>spring-data-parent</artifactId>
<version>4.0.0-M4</version>
<version>4.0.0-SNAPSHOT</version>
</parent>
<name>Spring Data Elasticsearch</name>
@ -18,10 +18,10 @@
<url>https://github.com/spring-projects/spring-data-elasticsearch</url>
<properties>
<springdata.commons>4.0.0-M4</springdata.commons>
<springdata.commons>4.0.0-SNAPSHOT</springdata.commons>
<!-- version of the ElasticsearchClient -->
<elasticsearch-java>9.0.3</elasticsearch-java>
<elasticsearch-java>9.0.4</elasticsearch-java>
<hoverfly>0.19.0</hoverfly>
<log4j>2.23.1</log4j>
@ -471,8 +471,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>

View File

@ -389,6 +389,63 @@ ClientConfiguration.builder()
----
====
[[elasticsearch.clients.configurationcallbacks.connectionconfig]]
==== Configuration of the ConnectionConfig used by the low level Elasticsearch `Rest5Client`:
This callback provides a `org.apache.hc.client5.http.config.ConnectionConfig` to configure the connection that is
used by the `Rest5Client`.
====
[source,java]
----
ClientConfiguration.builder()
.connectedTo("localhost:9200", "localhost:9291")
.withClientConfigurer(Rest5Clients.ElasticsearchConnectionConfigurationCallback.from(connectionConfigBuilder -> {
// configure the connection
return connectionConfigBuilder;
}))
.build();
----
====
[[elasticsearch.clients.configurationcallbacks.connectioncmanager]]
==== Configuration of the ConnectionManager used by the low level Elasticsearch `Rest5Client`:
This callback provides a `org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManagerBuilder` to configure the connection manager that is
used by the `Rest5Client`.
====
[source,java]
----
ClientConfiguration.builder()
.connectedTo("localhost:9200", "localhost:9291")
.withClientConfigurer(Rest5Clients.ElasticsearchConnectionManagerCallback.from(connectionManagerBuilder -> {
// configure the connection manager
return connectionManagerBuilder;
}))
.build();
----
====
[[elasticsearch.clients.configurationcallbacks.requestconfig]]
==== Configuration of the RequestConfig used by the low level Elasticsearch `Rest5Client`:
This callback provides a `org.apache.hc.client5.http.config.RequestConfig` to configure the RequestConfig that is
used by the `Rest5Client`.
====
[source,java]
----
ClientConfiguration.builder()
.connectedTo("localhost:9200", "localhost:9291")
.withClientConfigurer(Rest5Clients.ElasticsearchRequestConfigCallback.from(requestConfigBuilder -> {
// configure the request config
return requestConfigBuilder;
}))
.build();
----
====
[[elasticsearch.clients.logging]]
== Client Logging

View File

@ -6,7 +6,7 @@
* Upgarde to Spring 7
* Switch to jspecify nullability annotations
* Upgrade to Elasticsearch 9.0.3
* Upgrade to Elasticsearch 9.0.4
* Use the new Elasticsearch Rest5Client as default

View File

@ -6,7 +6,7 @@ The following table shows the Elasticsearch and Spring versions that are used by
[cols="^,^,^,^",options="header"]
|===
| Spring Data Release Train | Spring Data Elasticsearch | Elasticsearch | Spring Framework
| 2025.1 (in development) | 6.0.x | 9.0.3 | 7.0.x
| 2025.1 (in development) | 6.0.x | 9.0.4 | 7.0.x
| 2025.0 | 5.5.x | 8.18.1 | 6.2.x
| 2024.1 | 5.4.x | 8.15.5 | 6.1.x
| 2024.0 | 5.3.xfootnote:oom[Out of maintenance] | 8.13.4 | 6.1.x

View File

@ -8,6 +8,8 @@ This section describes breaking changes from version 5.5.x to 6.0.x and how remo
From version 6.0 on, Spring Data Elasticsearch uses the Elasticsearch 9 libraries and as default the new `Rest5Client` provided by these libraries. It is still possible to use the old `RestClient`, check xref:elasticsearch/clients.adoc[Elasticsearch clients] for information. The configuration callbacks for this `RestClient` have been moved from `org.springframework.data.elasticsearch.client.elc.ElasticsearchClients` to the `org.springframework.data.elasticsearch.client.elc.rest_client.RestClients` class.
In the `org.springframework.data.elasticsearch.core.query.UpdateQuery` class the type of the two fields `ifSeqNo` and `ifPrimaryTerm` has changed from `Integer` to `Long` to align with the normal query and the underlying Elasticsearch client.
[[elasticsearch-migration-guide-5.5-6.0.deprecations]]
== Deprecations

View File

@ -24,6 +24,7 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.elasticsearch.client.ResponseException;
import org.jspecify.annotations.Nullable;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.dao.DataIntegrityViolationException;
@ -33,6 +34,7 @@ import org.springframework.data.elasticsearch.NoSuchIndexException;
import org.springframework.data.elasticsearch.ResourceNotFoundException;
import org.springframework.data.elasticsearch.UncategorizedElasticsearchException;
import org.springframework.data.elasticsearch.VersionConflictException;
import org.springframework.util.ClassUtils;
/**
* Simple {@link PersistenceExceptionTranslator} for Elasticsearch. Convert the given runtime exception to an
@ -45,6 +47,9 @@ import org.springframework.data.elasticsearch.VersionConflictException;
*/
public class ElasticsearchExceptionTranslator implements PersistenceExceptionTranslator {
public static final boolean LEGACY_RESTCLIENT_PRESENT = ClassUtils
.isPresent("org.elasticsearch.client.ResponseException", ElasticsearchExceptionTranslator.class.getClassLoader());
private final JsonpMapper jsonpMapper;
public ElasticsearchExceptionTranslator(JsonpMapper jsonpMapper) {
@ -68,7 +73,7 @@ public class ElasticsearchExceptionTranslator implements PersistenceExceptionTra
}
@Override
public DataAccessException translateExceptionIfPossible(RuntimeException ex) {
public @Nullable DataAccessException translateExceptionIfPossible(RuntimeException ex) {
checkForConflictException(ex);
@ -118,7 +123,7 @@ public class ElasticsearchExceptionTranslator implements PersistenceExceptionTra
Integer status = null;
String message = null;
if (exception instanceof ResponseException responseException) {
if (LEGACY_RESTCLIENT_PRESENT && exception instanceof ResponseException responseException) {
// this code is for the old RestClient
status = responseException.getResponse().getStatusLine().getStatusCode();
message = responseException.getMessage();

View File

@ -658,7 +658,7 @@ public class ElasticsearchTemplate extends AbstractElasticsearchTemplate {
QueryResponse response = sqlClient.query(requestConverter.sqlQueryRequest(query));
return responseConverter.sqlResponse(response);
} catch (IOException e) {
} catch (Exception e) {
throw exceptionTranslator.translateException(e);
}
}

View File

@ -25,6 +25,7 @@ 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 org.jspecify.annotations.NonNull;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.util.function.Tuple2;
@ -162,7 +163,7 @@ public class ReactiveElasticsearchTemplate extends AbstractReactiveElasticsearch
ExistsRequest existsRequest = requestConverter.documentExistsRequest(id, routingResolver.getRouting(), index);
return Mono.from(execute(
((ClientCallback<Publisher<BooleanResponse>>) client -> client.exists(existsRequest))))
((ClientCallback<@NonNull Publisher<BooleanResponse>>) client -> client.exists(existsRequest))))
.map(BooleanResponse::value) //
.onErrorReturn(NoSuchIndexException.class, false);
}

View File

@ -723,12 +723,11 @@ class RequestConverter extends AbstractQueryProcessor {
return a;
});
uob //
.routing(query.getRouting()) //
.ifSeqNo(query.getIfSeqNo() != null ? Long.valueOf(query.getIfSeqNo()) : null) //
.ifPrimaryTerm(query.getIfPrimaryTerm() != null ? Long.valueOf(query.getIfPrimaryTerm()) : null) //
.retryOnConflict(query.getRetryOnConflict()) //
;
uob
.routing(query.getRouting())
.ifSeqNo(query.getIfSeqNo())
.ifPrimaryTerm(query.getIfPrimaryTerm())
.retryOnConflict(query.getRetryOnConflict());
// no refresh, timeout, waitForActiveShards on UpdateOperation or UpdateAction
@ -1095,17 +1094,16 @@ 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() != null ? Long.valueOf(query.getIfSeqNo()) : null) //
.ifPrimaryTerm(query.getIfPrimaryTerm() != null ? Long.valueOf(query.getIfPrimaryTerm()) : null) //
.refresh(query.getRefreshPolicy() != null ? refresh(query.getRefreshPolicy()) : refresh(refreshPolicy)) //
.retryOnConflict(query.getRetryOnConflict()) //
;
uqb
.doc(query.getDocument())
.upsert(query.getUpsert())
.routing(query.getRouting() != null ? query.getRouting() : routing)
.scriptedUpsert(query.getScriptedUpsert())
.docAsUpsert(query.getDocAsUpsert())
.ifSeqNo(query.getIfSeqNo())
.ifPrimaryTerm(query.getIfPrimaryTerm())
.refresh(query.getRefreshPolicy() != null ? refresh(query.getRefreshPolicy()) : refresh(refreshPolicy))
.retryOnConflict(query.getRetryOnConflict());
if (query.getFetchSource() != null) {
uqb.source(sc -> sc.fetch(query.getFetchSource()));
@ -1293,7 +1291,7 @@ class RequestConverter extends AbstractQueryProcessor {
.timeout(timeStringMs(query.getTimeout())) //
;
bb.from((int) (query.getPageable().isPaged() ? query.getPageable().getOffset() : 0))
bb.from((int) (query.getPageable().isPaged() ? query.getPageable().getOffset() : 0))
.size(query.getRequestSize());
if (!isEmpty(query.getFields())) {
@ -1466,7 +1464,7 @@ class RequestConverter extends AbstractQueryProcessor {
builder.seqNoPrimaryTerm(true);
}
builder.from((int) (query.getPageable().isPaged() ? query.getPageable().getOffset() : 0))
builder.from((int) (query.getPageable().isPaged() ? query.getPageable().getOffset() : 0))
.size(query.getRequestSize());
if (!isEmpty(query.getFields())) {

View File

@ -13,20 +13,14 @@ import java.net.URISyntaxException;
import java.security.NoSuchAlgorithmException;
import java.time.Duration;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Function;
import javax.net.ssl.SSLContext;
import org.apache.hc.client5.http.config.ConnectionConfig;
import org.apache.hc.client5.http.config.RequestConfig;
import org.apache.hc.client5.http.impl.DefaultAuthenticationStrategy;
import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient;
import org.apache.hc.client5.http.impl.async.HttpAsyncClientBuilder;
import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManager;
import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManagerBuilder;
import org.apache.hc.client5.http.impl.routing.DefaultProxyRoutePlanner;
import org.apache.hc.core5.http.Header;
@ -38,7 +32,6 @@ import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.Nullable;
import org.springframework.data.elasticsearch.client.ClientConfiguration;
import org.springframework.data.elasticsearch.support.HttpHeaders;
import org.springframework.data.elasticsearch.support.VersionInfo;
import org.springframework.util.Assert;
/**
@ -49,11 +42,8 @@ import org.springframework.util.Assert;
public final class Rest5Clients {
// values copied from Rest5ClientBuilder
public static final int DEFAULT_CONNECT_TIMEOUT_MILLIS = 1000;
public static final int DEFAULT_SOCKET_TIMEOUT_MILLIS = 30000;
public static final int DEFAULT_RESPONSE_TIMEOUT_MILLIS = 0; // meaning infinite
public static final int DEFAULT_MAX_CONN_PER_ROUTE = 10;
public static final int DEFAULT_MAX_CONN_TOTAL = 30;
private Rest5Clients() {}
@ -82,11 +72,7 @@ public final class Rest5Clients {
builder.setDefaultHeaders(toHeaderArray(headers));
}
// we need to provide our own HttpClient, as the Rest5ClientBuilder
// does not provide a callback for configuration the http client as the old RestClientBuilder.
var httpClient = createHttpClient(clientConfiguration);
builder.setHttpClient(httpClient);
// RestClientBuilder configuration callbacks from the consumer
for (ClientConfiguration.ClientConfigurationCallback<?> clientConfigurationCallback : clientConfiguration
.getClientConfigurers()) {
if (clientConfigurationCallback instanceof ElasticsearchRest5ClientConfigurationCallback configurationCallback) {
@ -94,6 +80,104 @@ public final class Rest5Clients {
}
}
Duration connectTimeout = clientConfiguration.getConnectTimeout();
Duration socketTimeout = clientConfiguration.getSocketTimeout();
builder.setHttpClientConfigCallback(httpAsyncClientBuilder -> {
if (clientConfiguration.getProxy().isPresent()) {
var proxy = clientConfiguration.getProxy().get();
try {
var proxyRoutePlanner = new DefaultProxyRoutePlanner(HttpHost.create(proxy));
httpAsyncClientBuilder.setRoutePlanner(proxyRoutePlanner);
} catch (URISyntaxException e) {
throw new RuntimeException(e);
}
}
httpAsyncClientBuilder.addRequestInterceptorFirst((request, entity, context) -> {
clientConfiguration.getHeadersSupplier().get().forEach((header, values) -> {
// The accept and content-type headers are already put on the request, despite this being the first
// interceptor.
if ("Accept".equalsIgnoreCase(header) || " Content-Type".equalsIgnoreCase(header)) {
request.removeHeaders(header);
}
values.forEach(value -> request.addHeader(header, value));
});
});
// add httpclient configurator callbacks provided by the configuration
for (ClientConfiguration.ClientConfigurationCallback<?> clientConfigurer : clientConfiguration
.getClientConfigurers()) {
if (clientConfigurer instanceof ElasticsearchHttpClientConfigurationCallback httpClientConfigurer) {
httpAsyncClientBuilder = httpClientConfigurer.configure(httpAsyncClientBuilder);
}
}
});
builder.setConnectionConfigCallback(connectionConfigBuilder -> {
if (!connectTimeout.isNegative()) {
connectionConfigBuilder.setConnectTimeout(
Timeout.of(Math.toIntExact(connectTimeout.toMillis()), TimeUnit.MILLISECONDS));
}
if (!socketTimeout.isNegative()) {
var soTimeout = Timeout.of(Math.toIntExact(socketTimeout.toMillis()), TimeUnit.MILLISECONDS);
connectionConfigBuilder.setSocketTimeout(soTimeout);
} else {
connectionConfigBuilder.setSocketTimeout(Timeout.of(DEFAULT_SOCKET_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS));
}
// add connectionConfig configurator callbacks provided by the configuration
for (ClientConfiguration.ClientConfigurationCallback<?> clientConfigurer : clientConfiguration
.getClientConfigurers()) {
if (clientConfigurer instanceof ElasticsearchConnectionConfigurationCallback connectionConfigurationCallback) {
connectionConfigBuilder = connectionConfigurationCallback.configure(connectionConfigBuilder);
}
}
});
builder.setConnectionManagerCallback(poolingAsyncClientConnectionManagerBuilder -> {
SSLContext sslContext = null;
try {
sslContext = clientConfiguration.getCaFingerprint().isPresent()
? TransportUtils.sslContextFromCaFingerprint(clientConfiguration.getCaFingerprint().get())
: (clientConfiguration.getSslContext().isPresent()
? clientConfiguration.getSslContext().get()
: SSLContext.getDefault());
} catch (NoSuchAlgorithmException e) {
throw new IllegalStateException("could not create the default ssl context", e);
}
poolingAsyncClientConnectionManagerBuilder.setTlsStrategy(new BasicClientTlsStrategy(sslContext));
// add connectionManager configurator callbacks provided by the configuration
for (ClientConfiguration.ClientConfigurationCallback<?> clientConfigurer : clientConfiguration
.getClientConfigurers()) {
if (clientConfigurer instanceof ElasticsearchConnectionManagerCallback connectionManagerCallback) {
poolingAsyncClientConnectionManagerBuilder = connectionManagerCallback
.configure(poolingAsyncClientConnectionManagerBuilder);
}
}
});
builder.setRequestConfigCallback(requestConfigBuilder -> {
if (!socketTimeout.isNegative()) {
var soTimeout = Timeout.of(Math.toIntExact(socketTimeout.toMillis()), TimeUnit.MILLISECONDS);
requestConfigBuilder.setConnectionRequestTimeout(soTimeout);
} else {
requestConfigBuilder
.setConnectionRequestTimeout(Timeout.of(DEFAULT_RESPONSE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS));
}
// add connectionConfig configurator callbacks provided by the configuration
for (ClientConfiguration.ClientConfigurationCallback<?> clientConfigurer : clientConfiguration
.getClientConfigurers()) {
if (clientConfigurer instanceof ElasticsearchRequestConfigCallback requestConfigCallback) {
requestConfigBuilder = requestConfigCallback.configure(requestConfigBuilder);
}
}
});
return builder;
}
@ -114,109 +198,23 @@ public final class Rest5Clients {
.toList().toArray(new Header[0]);
}
// the basic logic to create the http client is copied from the Rest5ClientBuilder class, this is taken from the
// Elasticsearch code, as there is no public usable instance in that
private static CloseableHttpAsyncClient createHttpClient(ClientConfiguration clientConfiguration) {
var requestConfigBuilder = RequestConfig.custom();
var connectionConfigBuilder = ConnectionConfig.custom();
Duration connectTimeout = clientConfiguration.getConnectTimeout();
if (!connectTimeout.isNegative()) {
connectionConfigBuilder.setConnectTimeout(
Timeout.of(Math.toIntExact(connectTimeout.toMillis()), TimeUnit.MILLISECONDS));
}
Duration socketTimeout = clientConfiguration.getSocketTimeout();
if (!socketTimeout.isNegative()) {
var soTimeout = Timeout.of(Math.toIntExact(socketTimeout.toMillis()), TimeUnit.MILLISECONDS);
connectionConfigBuilder.setSocketTimeout(soTimeout);
requestConfigBuilder.setConnectionRequestTimeout(soTimeout);
} else {
connectionConfigBuilder.setSocketTimeout(Timeout.of(DEFAULT_SOCKET_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS));
requestConfigBuilder
.setConnectionRequestTimeout(Timeout.of(DEFAULT_RESPONSE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS));
}
try {
SSLContext sslContext = clientConfiguration.getCaFingerprint().isPresent()
? TransportUtils.sslContextFromCaFingerprint(clientConfiguration.getCaFingerprint().get())
: (clientConfiguration.getSslContext().isPresent()
? clientConfiguration.getSslContext().get()
: SSLContext.getDefault());
ConnectionConfig connectionConfig = connectionConfigBuilder.build();
PoolingAsyncClientConnectionManager defaultConnectionManager = PoolingAsyncClientConnectionManagerBuilder.create()
.setDefaultConnectionConfig(connectionConfig)
.setMaxConnPerRoute(DEFAULT_MAX_CONN_PER_ROUTE)
.setMaxConnTotal(DEFAULT_MAX_CONN_TOTAL)
.setTlsStrategy(new BasicClientTlsStrategy(sslContext))
.build();
var requestConfig = requestConfigBuilder.build();
var immutableRefToHttpClientBuilder = new Object() {
HttpAsyncClientBuilder httpClientBuilder = HttpAsyncClientBuilder.create()
.setDefaultRequestConfig(requestConfig)
.setConnectionManager(defaultConnectionManager)
.setUserAgent(VersionInfo.clientVersions())
.setTargetAuthenticationStrategy(new DefaultAuthenticationStrategy())
.setThreadFactory(new RestClientThreadFactory());
};
clientConfiguration.getProxy().ifPresent(proxy -> {
try {
var proxyRoutePlanner = new DefaultProxyRoutePlanner(HttpHost.create(proxy));
immutableRefToHttpClientBuilder.httpClientBuilder.setRoutePlanner(proxyRoutePlanner);
} catch (URISyntaxException e) {
throw new RuntimeException(e);
}
});
immutableRefToHttpClientBuilder.httpClientBuilder.addRequestInterceptorFirst((request, entity, context) -> {
clientConfiguration.getHeadersSupplier().get().forEach((header, values) -> {
// The accept and content-type headers are already put on the request, despite this being the first
// interceptor.
if ("Accept".equalsIgnoreCase(header) || " Content-Type".equalsIgnoreCase(header)) {
request.removeHeaders(header);
}
values.forEach(value -> request.addHeader(header, value));
});
});
for (ClientConfiguration.ClientConfigurationCallback<?> clientConfigurer : clientConfiguration
.getClientConfigurers()) {
if (clientConfigurer instanceof ElasticsearchHttpClientConfigurationCallback httpClientConfigurer) {
immutableRefToHttpClientBuilder.httpClientBuilder = httpClientConfigurer.configure(immutableRefToHttpClientBuilder.httpClientBuilder);
}
}
return immutableRefToHttpClientBuilder.httpClientBuilder.build();
} catch (NoSuchAlgorithmException e) {
throw new IllegalStateException("could not create the default ssl context", e);
}
}
/*
* Copied from the Elasticsearch code as this class is not public there.
/**
* {@link ClientConfiguration.ClientConfigurationCallback} to configure the Rest5Client client with a
* {@link Rest5ClientBuilder}
*
* @since 6.0
*/
private static class RestClientThreadFactory implements ThreadFactory {
private static final AtomicLong CLIENT_THREAD_POOL_ID_GENERATOR = new AtomicLong();
private final long clientThreadPoolId;
private final AtomicLong clientThreadId;
public interface ElasticsearchRest5ClientConfigurationCallback
extends ClientConfiguration.ClientConfigurationCallback<Rest5ClientBuilder> {
private RestClientThreadFactory() {
this.clientThreadPoolId = CLIENT_THREAD_POOL_ID_GENERATOR.getAndIncrement();
this.clientThreadId = new AtomicLong();
static ElasticsearchRest5ClientConfigurationCallback from(
Function<Rest5ClientBuilder, Rest5ClientBuilder> rest5ClientBuilderCallback) {
Assert.notNull(rest5ClientBuilderCallback, "rest5ClientBuilderCallback must not be null");
return rest5ClientBuilderCallback::apply;
}
public Thread newThread(Runnable runnable) {
return new Thread(runnable, String.format(Locale.ROOT, "elasticsearch-rest-client-%d-thread-%d",
this.clientThreadPoolId, this.clientThreadId.incrementAndGet()));
}
}
/**
@ -238,20 +236,56 @@ public final class Rest5Clients {
}
/**
* {@link ClientConfiguration.ClientConfigurationCallback} to configure the Rest5Client client with a
* {@link Rest5ClientBuilder}
* {@link org.springframework.data.elasticsearch.client.ClientConfiguration.ClientConfigurationCallback} to configure
* the Elasticsearch Rest5Client's connection with a {@link ConnectionConfig.Builder}
*
* @since 6.0
*/
public interface ElasticsearchRest5ClientConfigurationCallback
extends ClientConfiguration.ClientConfigurationCallback<Rest5ClientBuilder> {
public interface ElasticsearchConnectionConfigurationCallback
extends ClientConfiguration.ClientConfigurationCallback<ConnectionConfig.Builder> {
static ElasticsearchRest5ClientConfigurationCallback from(
Function<Rest5ClientBuilder, Rest5ClientBuilder> rest5ClientBuilderCallback) {
static ElasticsearchConnectionConfigurationCallback from(
Function<ConnectionConfig.Builder, ConnectionConfig.Builder> connectionConfigBuilderCallback) {
Assert.notNull(rest5ClientBuilderCallback, "rest5ClientBuilderCallback must not be null");
Assert.notNull(connectionConfigBuilderCallback, "connectionConfigBuilderCallback must not be null");
return rest5ClientBuilderCallback::apply;
return connectionConfigBuilderCallback::apply;
}
}
/**
* {@link org.springframework.data.elasticsearch.client.ClientConfiguration.ClientConfigurationCallback} to configure
* the Elasticsearch Rest5Client's connection manager with a {@link PoolingAsyncClientConnectionManagerBuilder}
*
* @since 6.0
*/
public interface ElasticsearchConnectionManagerCallback
extends ClientConfiguration.ClientConfigurationCallback<PoolingAsyncClientConnectionManagerBuilder> {
static ElasticsearchConnectionManagerCallback from(
Function<PoolingAsyncClientConnectionManagerBuilder, PoolingAsyncClientConnectionManagerBuilder> connectionManagerBuilderCallback) {
Assert.notNull(connectionManagerBuilderCallback, "connectionManagerBuilderCallback must not be null");
return connectionManagerBuilderCallback::apply;
}
}
/**
* {@link org.springframework.data.elasticsearch.client.ClientConfiguration.ClientConfigurationCallback} to configure
* the Elasticsearch Rest5Client's connection manager with a {@link RequestConfig.Builder}
*
* @since 6.0
*/
public interface ElasticsearchRequestConfigCallback
extends ClientConfiguration.ClientConfigurationCallback<RequestConfig.Builder> {
static ElasticsearchRequestConfigCallback from(
Function<RequestConfig.Builder, RequestConfig.Builder> requestConfigBuilderCallback) {
Assert.notNull(requestConfigBuilderCallback, "requestConfigBuilderCallback must not be null");
return requestConfigBuilderCallback::apply;
}
}

View File

@ -17,6 +17,7 @@ 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;
@ -369,7 +370,7 @@ public class EntityOperations {
* @see org.springframework.data.elasticsearch.core.EntityOperations.AdaptableEntity#initializeVersionProperty()
*/
@Override
public T initializeVersionProperty() {
public @NonNull T initializeVersionProperty() {
return map;
}
@ -389,7 +390,7 @@ public class EntityOperations {
}
@Override
public SeqNoPrimaryTerm getSeqNoPrimaryTerm() {
public @Nullable SeqNoPrimaryTerm getSeqNoPrimaryTerm() {
return null;
}
@ -398,7 +399,7 @@ public class EntityOperations {
* @see org.springframework.data.elasticsearch.core.EntityOperations.AdaptableEntity#incrementVersion()
*/
@Override
public T incrementVersion() {
public @NonNull T incrementVersion() {
return map;
}
@ -407,7 +408,7 @@ public class EntityOperations {
* @see org.springframework.data.elasticsearch.core.EntityOperations.Entity#getBean()
*/
@Override
public T getBean() {
public @NonNull T getBean() {
return map;
}
@ -425,12 +426,12 @@ public class EntityOperations {
* @see org.springframework.data.elasticsearch.core.EntityOperations.Entity#getPersistentEntity()
*/
@Override
public ElasticsearchPersistentEntity<?> getPersistentEntity() {
public @Nullable ElasticsearchPersistentEntity<?> getPersistentEntity() {
return null;
}
@Override
public String getRouting() {
public @Nullable String getRouting() {
return null;
}
}
@ -650,7 +651,7 @@ public class EntityOperations {
}
@Override
public String getRouting() {
public @Nullable String getRouting() {
String routing = routingResolver.getRouting(propertyAccessor.getBean());

View File

@ -714,7 +714,7 @@ public class MappingElasticsearchConverter
}
@Override
public <T> T getPropertyValue(ElasticsearchPersistentProperty property) {
public <T> @Nullable T getPropertyValue(ElasticsearchPersistentProperty property) {
String expression = property.getSpelExpression();
Object value = expression != null ? evaluator.evaluate(expression) : accessor.get(property);

View File

@ -66,8 +66,7 @@ public class AliasActionParameters {
return indices;
}
@Nullable
public String[] getAliases() {
public String@Nullable[] getAliases() {
return aliases;
}
@ -107,8 +106,8 @@ public class AliasActionParameters {
}
public static final class Builder {
@Nullable private String[] indices;
@Nullable private String[] aliases;
private String @Nullable [] indices;
private String @Nullable [] aliases;
@Nullable private Query filterQuery;
@Nullable private Class<?> filterQueryClass;
@Nullable private Boolean isHidden;

View File

@ -55,6 +55,7 @@ public class AliasActions {
public AliasActions add(@Nullable AliasAction... actions) {
if (actions != null) {
// noinspection NullableProblems
this.actions.addAll(Arrays.asList(actions));
}

View File

@ -29,6 +29,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;
@ -273,7 +274,7 @@ public class MappingBuilder {
writeTypeHintMapping(propertiesNode);
if (entity != null) {
entity.doWithProperties((PropertyHandler<ElasticsearchPersistentProperty>) property -> {
entity.doWithProperties((PropertyHandler<@NonNull ElasticsearchPersistentProperty>) property -> {
try {
if (property.isAnnotationPresent(Transient.class) || isInIgnoreFields(property, parentFieldAnnotation)) {
return;

View File

@ -35,7 +35,7 @@ public record PutIndexTemplateRequest(String name, String[] indexPatterns, @Null
public static class Builder {
@Nullable private String name;
@Nullable private String[] indexPatterns;
private String @Nullable [] indexPatterns;
@Nullable private Settings settings;
@Nullable private Document mapping;
@Nullable AliasActions aliasActions;

View File

@ -81,7 +81,7 @@ public class TemplateData {
@Nullable Document mapping;
int order;
@Nullable Integer version;
@Nullable private String[] indexPatterns;
@Nullable private String@Nullable [] indexPatterns;
@Nullable private Map<String, AliasData> aliases;
private TemplateDataBuilder() {}

View File

@ -65,7 +65,7 @@ public interface ElasticsearchPersistentEntity<T> extends PersistentEntity<T, El
String getIndexStoreType();
@Override
ElasticsearchPersistentProperty getVersionProperty();
@Nullable ElasticsearchPersistentProperty getVersionProperty();
@Nullable
String settingPath();

View File

@ -23,6 +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;
@ -298,7 +299,7 @@ public class SimpleElasticsearchPersistentEntity<T> extends BasicPersistentEntit
return fieldNamePropertyCache.computeIfAbsent(fieldName, key -> {
AtomicReference<ElasticsearchPersistentProperty> propertyRef = new AtomicReference<>();
doWithProperties((PropertyHandler<ElasticsearchPersistentProperty>) property -> {
doWithProperties((PropertyHandler<@NonNull ElasticsearchPersistentProperty>) property -> {
if (key.equals(property.getFieldName())) {
propertyRef.set(property);
}
@ -552,10 +553,10 @@ public class SimpleElasticsearchPersistentEntity<T> extends BasicPersistentEntit
short replicas;
@Nullable String refreshIntervall;
@Nullable String indexStoreType;
@Nullable private String[] sortFields;
private Setting.@Nullable SortOrder[] sortOrders;
private Setting.@Nullable SortMode[] sortModes;
private Setting.@Nullable SortMissing[] sortMissingValues;
private String @Nullable [] sortFields;
private Setting.@Nullable SortOrder @Nullable [] sortOrders;
private Setting.@Nullable SortMode @Nullable [] sortModes;
private Setting.@Nullable SortMissing @Nullable [] sortMissingValues;
Settings toSettings() {

View File

@ -200,7 +200,7 @@ public abstract class BaseQueryBuilder<Q extends BaseQuery, SELF extends BaseQue
/**
* @since 5.1
*/
public Integer getReactiveBatchSize() {
public @Nullable Integer getReactiveBatchSize() {
return reactiveBatchSize;
}

View File

@ -344,8 +344,8 @@ public class ByQueryResponse {
*
* @return a new {@link SearchFailureBuilder} to build {@link SearchFailure}
*/
public static SearchFailureBuilder builder() {
return new SearchFailureBuilder();
public static SearchFailureBuilder builder(Throwable reason) {
return new SearchFailureBuilder(reason);
}
/**
@ -358,7 +358,9 @@ public class ByQueryResponse {
@Nullable private Integer shardId;
@Nullable private String nodeId;
private SearchFailureBuilder() {}
private SearchFailureBuilder(Throwable reason) {
this.reason = reason;
}
public SearchFailureBuilder withReason(Throwable reason) {
this.reason = reason;

View File

@ -63,12 +63,12 @@ public class FetchSourceFilter implements SourceFilter {
}
@Override
public String[] getIncludes() {
public @Nullable String[] getIncludes() {
return includes;
}
@Override
public String[] getExcludes() {
public @Nullable String[] getExcludes() {
return excludes;
}
}

View File

@ -26,8 +26,8 @@ import org.jspecify.annotations.Nullable;
public class FetchSourceFilterBuilder {
@Nullable private Boolean fetchSource;
@Nullable private String[] includes;
@Nullable private String[] excludes;
private String @Nullable [] includes;
private String @Nullable [] excludes;
public FetchSourceFilterBuilder withIncludes(String... includes) {
this.includes = includes;

View File

@ -15,6 +15,7 @@
*/
package org.springframework.data.elasticsearch.core.query;
import org.jspecify.annotations.Nullable;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.core.geo.GeoPoint;
@ -92,7 +93,7 @@ public class GeoDistanceOrder extends Order {
getIgnoreUnmapped());
}
public GeoDistanceOrder with(Mode mode) {
public GeoDistanceOrder with(@Nullable Mode mode) {
return new GeoDistanceOrder(getProperty(), getGeoPoint(), getDirection(), getDistanceType(), mode, getUnit(),
getIgnoreUnmapped());
}

View File

@ -121,7 +121,7 @@ public class HasChildQuery {
public static final class Builder {
private final String type;
private Query query;
@Nullable private Query query;
@Nullable private Boolean ignoreUnmapped;

View File

@ -92,7 +92,7 @@ public class HasParentQuery {
public static class Builder {
private final String parentType;
private Query query;
@Nullable private Query query;
@Nullable private Boolean score;
@Nullable private Boolean ignoreUnmapped;

View File

@ -32,14 +32,14 @@ public interface SourceFilter {
/**
* @return the name of the fields to include in a response.
*/
@Nullable
String[] getIncludes();
String@Nullable[] getIncludes();
/**
* @return the names of the fields to exclude from a response.
*/
@Nullable
String[] getExcludes();
String@Nullable[] getExcludes();
/**
* Flag to set the _source parameter in a query to true or false. If this is not null, the values returned from

View File

@ -42,8 +42,8 @@ public class UpdateQuery {
@Nullable private final Boolean fetchSource;
@Nullable private final List<String> fetchSourceIncludes;
@Nullable private final List<String> fetchSourceExcludes;
@Nullable private final Integer ifSeqNo;
@Nullable private final Integer ifPrimaryTerm;
@Nullable private final Long ifSeqNo;
@Nullable private final Long ifPrimaryTerm;
@Nullable private final RefreshPolicy refreshPolicy;
@Nullable private final Integer retryOnConflict;
@Nullable private final String timeout;
@ -71,8 +71,8 @@ public class UpdateQuery {
private UpdateQuery(String id, @Nullable String script, @Nullable Map<String, Object> params,
@Nullable Document document, @Nullable Document upsert, @Nullable String lang, @Nullable String routing,
@Nullable Boolean scriptedUpsert, @Nullable Boolean docAsUpsert, @Nullable Boolean fetchSource,
@Nullable List<String> fetchSourceIncludes, @Nullable List<String> fetchSourceExcludes, @Nullable Integer ifSeqNo,
@Nullable Integer ifPrimaryTerm, @Nullable RefreshPolicy refreshPolicy, @Nullable Integer retryOnConflict,
@Nullable List<String> fetchSourceIncludes, @Nullable List<String> fetchSourceExcludes, @Nullable Long ifSeqNo,
@Nullable Long ifPrimaryTerm, @Nullable RefreshPolicy refreshPolicy, @Nullable Integer retryOnConflict,
@Nullable String timeout, @Nullable String waitForActiveShards, @Nullable Query query,
@Nullable Boolean abortOnVersionConflict, @Nullable Integer batchSize, @Nullable Integer maxDocs,
@Nullable Integer maxRetries, @Nullable String pipeline, @Nullable Float requestsPerSecond,
@ -172,12 +172,12 @@ public class UpdateQuery {
}
@Nullable
public Integer getIfSeqNo() {
public Long getIfSeqNo() {
return ifSeqNo;
}
@Nullable
public Integer getIfPrimaryTerm() {
public Long getIfPrimaryTerm() {
return ifPrimaryTerm;
}
@ -268,7 +268,7 @@ public class UpdateQuery {
}
public static final class Builder {
private String id;
private String id = "";
@Nullable private String script = null;
@Nullable private Map<String, Object> params;
@Nullable private Document document = null;
@ -278,8 +278,8 @@ public class UpdateQuery {
@Nullable private Boolean scriptedUpsert;
@Nullable private Boolean docAsUpsert;
@Nullable private Boolean fetchSource;
@Nullable private Integer ifSeqNo;
@Nullable private Integer ifPrimaryTerm;
@Nullable private Long ifSeqNo;
@Nullable private Long ifPrimaryTerm;
@Nullable private RefreshPolicy refreshPolicy;
@Nullable private Integer retryOnConflict;
@Nullable private String timeout;
@ -351,12 +351,12 @@ public class UpdateQuery {
return this;
}
public Builder withIfSeqNo(Integer ifSeqNo) {
public Builder withIfSeqNo(Long ifSeqNo) {
this.ifSeqNo = ifSeqNo;
return this;
}
public Builder withIfPrimaryTerm(Integer ifPrimaryTerm) {
public Builder withIfPrimaryTerm(Long ifPrimaryTerm) {
this.ifPrimaryTerm = ifPrimaryTerm;
return this;
}

View File

@ -18,6 +18,7 @@ package org.springframework.data.elasticsearch.repository.query;
import java.util.LinkedHashMap;
import java.util.Map;
import org.jspecify.annotations.Nullable;
import org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperations;
import org.springframework.data.elasticsearch.core.query.BaseQuery;
import org.springframework.data.elasticsearch.core.query.SearchTemplateQuery;
@ -33,7 +34,7 @@ import org.springframework.util.Assert;
public class ReactiveRepositorySearchTemplateQuery extends AbstractReactiveElasticsearchRepositoryQuery {
private String id;
private Map<String, Object> params;
private Map<String, Object> params = Map.of();
public ReactiveRepositorySearchTemplateQuery(ReactiveElasticsearchQueryMethod queryMethod,
ReactiveElasticsearchOperations elasticsearchOperations,

View File

@ -33,7 +33,7 @@ import org.springframework.util.Assert;
public class RepositorySearchTemplateQuery extends AbstractElasticsearchRepositoryQuery {
private String id;
private Map<String, Object> params;
private Map<String, Object> params = Map.of();
public RepositorySearchTemplateQuery(ElasticsearchQueryMethod queryMethod,
ElasticsearchOperations elasticsearchOperations, ValueExpressionDelegate valueExpressionDelegate,

View File

@ -82,7 +82,7 @@ class ExampleCriteriaMapper {
Object propertyValue = propertyAccessor.getProperty(property);
if (property.isMap() && propertyValue != null) {
for (Map.Entry<String, Object> entry : ((Map<String, Object>) propertyValue).entrySet()) {
for (Map.Entry<String, @Nullable Object> entry : ((Map<String, @Nullable Object>) propertyValue).entrySet()) {
String key = entry.getKey();
Object value = entry.getValue();
criteria = applyPropertySpec(propertyPath + "." + key, value, exampleSpecAccessor, property, matchMode,
@ -96,7 +96,7 @@ class ExampleCriteriaMapper {
return criteria;
}
private Criteria applyPropertySpec(String path, Object propertyValue, ExampleMatcherAccessor exampleSpecAccessor,
private Criteria applyPropertySpec(String path, @Nullable Object propertyValue, ExampleMatcherAccessor exampleSpecAccessor,
ElasticsearchPersistentProperty property, ExampleMatcher.MatchMode matchMode, Criteria criteria) {
if (exampleSpecAccessor.isIgnoreCaseForPath(path)) {

View File

@ -47,13 +47,14 @@ public class QueryByExampleElasticsearchExecutor<T> implements QueryByExampleExe
@Override
public <S extends T> Optional<S> findOne(Example<S> example) {
CriteriaQuery criteriaQuery = CriteriaQuery.builder(exampleCriteriaMapper.criteria(example)).withMaxResults(2).build();
CriteriaQuery criteriaQuery = CriteriaQuery.builder(exampleCriteriaMapper.criteria(example)).withMaxResults(2)
.build();
SearchHits<S> searchHits = operations.search(criteriaQuery, example.getProbeType(),
operations.getIndexCoordinatesFor(example.getProbeType()));
if (searchHits.getTotalHits() > 1) {
throw new org.springframework.dao.IncorrectResultSizeDataAccessException(1);
}
return Optional.ofNullable(searchHits).filter(SearchHits::hasSearchHits)
return Optional.of(searchHits).filter(SearchHits::hasSearchHits)
.map(result -> (List<S>) SearchHitSupport.unwrapSearchHits(result)).map(s -> s.get(0));
}

View File

@ -39,11 +39,11 @@ import org.springframework.util.MultiValueMapAdapter;
* @author Peter-Josef Meisch
* @since 5.0
*/
public class HttpHeaders implements MultiValueMap<String, String> {
public class HttpHeaders implements MultiValueMap<String, @Nullable String> {
public static final String AUTHORIZATION = "Authorization";
private final MultiValueMap<String, String> delegate;
private final MultiValueMap<String, @Nullable String> delegate;
public HttpHeaders() {
this.delegate = new MultiValueMapAdapter<>(new LinkedCaseInsensitiveMap<>(Locale.ENGLISH));
@ -62,12 +62,12 @@ public class HttpHeaders implements MultiValueMap<String, String> {
}
@Override
public void addAll(String key, List<? extends String> values) {
public void addAll(String key, List<? extends @Nullable String> values) {
delegate.addAll(key, values);
}
@Override
public void addAll(MultiValueMap<String, String> values) {
public void addAll(MultiValueMap<String, @Nullable String> values) {
delegate.addAll(values);
}
@ -77,12 +77,12 @@ public class HttpHeaders implements MultiValueMap<String, String> {
}
@Override
public void setAll(Map<String, String> values) {
public void setAll(Map<String, @Nullable String> values) {
delegate.setAll(values);
}
@Override
public Map<String, String> toSingleValueMap() {
public Map<String, @Nullable String> toSingleValueMap() {
return delegate.toSingleValueMap();
}
// endregion
@ -110,18 +110,18 @@ public class HttpHeaders implements MultiValueMap<String, String> {
@Override
@Nullable
public List<String> get(Object key) {
public List<@Nullable String> get(Object key) {
return delegate.get(key);
}
@Nullable
@Override
public List<String> put(String key, List<String> value) {
public List<@Nullable String> put(String key, List<@Nullable String> value) {
return delegate.put(key, value);
}
@Override
public List<String> remove(Object key) {
public List<@Nullable String> remove(Object key) {
return delegate.remove(key);
}

View File

@ -47,7 +47,6 @@ import org.springframework.data.elasticsearch.support.HttpHeaders;
import com.github.tomakehurst.wiremock.WireMockServer;
import com.github.tomakehurst.wiremock.client.WireMock;
import com.github.tomakehurst.wiremock.common.ConsoleNotifier;
import com.github.tomakehurst.wiremock.matching.AnythingPattern;
import com.github.tomakehurst.wiremock.matching.EqualToPattern;
import com.github.tomakehurst.wiremock.stubbing.StubMapping;
@ -104,8 +103,11 @@ public class RestClientsTest {
defaultHeaders.add("def2", "def2-1");
AtomicInteger supplierCount = new AtomicInteger(1);
AtomicInteger httpClientConfigurerCount = new AtomicInteger(0);
AtomicInteger restClientConfigurerCount = new AtomicInteger(0);
AtomicInteger httpClientConfigurerCount = new AtomicInteger(0);
AtomicInteger connectionConfigurerCount = new AtomicInteger(0);
AtomicInteger connectionManagerConfigurerCount = new AtomicInteger(0);
AtomicInteger requestConfigurerCount = new AtomicInteger(0);
ClientConfigurationBuilder configurationBuilder = new ClientConfigurationBuilder();
configurationBuilder //
@ -120,17 +122,31 @@ public class RestClientsTest {
});
if (clientUnderTestFactory instanceof ELCRest5ClientUnderTestFactory) {
configurationBuilder.withClientConfigurer(
Rest5Clients.ElasticsearchRest5ClientConfigurationCallback.from(rest5ClientBuilder -> {
restClientConfigurerCount.incrementAndGet();
return rest5ClientBuilder;
}));
configurationBuilder.withClientConfigurer(
Rest5Clients.ElasticsearchHttpClientConfigurationCallback.from(httpClientBuilder -> {
httpClientConfigurerCount.incrementAndGet();
return httpClientBuilder;
}));
configurationBuilder.withClientConfigurer(
Rest5Clients.ElasticsearchRest5ClientConfigurationCallback.from(rest5ClientBuilder -> {
restClientConfigurerCount.incrementAndGet();
return rest5ClientBuilder;
Rest5Clients.ElasticsearchConnectionConfigurationCallback.from(connectionConfigBuilder -> {
connectionConfigurerCount.incrementAndGet();
return connectionConfigBuilder;
}));
configurationBuilder.withClientConfigurer(
Rest5Clients.ElasticsearchConnectionManagerCallback.from(connectionManagerBuilder -> {
connectionManagerConfigurerCount.incrementAndGet();
return connectionManagerBuilder;
}));
configurationBuilder.withClientConfigurer(
Rest5Clients.ElasticsearchRequestConfigCallback.from(requestConfigBuilder -> {
requestConfigurerCount.incrementAndGet();
return requestConfigBuilder;
}));
} else if (clientUnderTestFactory instanceof ELCRestClientUnderTestFactory) {
configurationBuilder.withClientConfigurer(
RestClients.ElasticsearchHttpClientConfigurationCallback.from(httpClientBuilder -> {
@ -177,8 +193,12 @@ public class RestClientsTest {
;
}
assertThat(restClientConfigurerCount).hasValue(clientUnderTestFactory.getExpectedRestClientConfigurerCalls());
assertThat(httpClientConfigurerCount).hasValue(1);
assertThat(restClientConfigurerCount).hasValue(clientUnderTestFactory.getExpectedRestClientConfigCalls());
assertThat(connectionConfigurerCount).hasValue(clientUnderTestFactory.getExpectedConnectionConfigurerCalls());
assertThat(connectionManagerConfigurerCount)
.hasValue(clientUnderTestFactory.getExpectedConnectionManagerConfigurerCalls());
assertThat(requestConfigurerCount).hasValue(clientUnderTestFactory.getExpectedRequestConfigurerCalls());
});
}
@ -404,11 +424,23 @@ public class RestClientsTest {
protected abstract String getDisplayName();
protected Integer getExpectedRestClientConfigCalls() {
protected Integer getExpectedRestClientConfigurerCalls() {
return 0;
}
protected abstract int getElasticsearchMajorVersion();
public Integer getExpectedConnectionConfigurerCalls() {
return 0;
}
public Integer getExpectedConnectionManagerConfigurerCalls() {
return 0;
}
public Integer getExpectedRequestConfigurerCalls() {
return 0;
}
}
/**
@ -423,7 +455,22 @@ public class RestClientsTest {
}
@Override
protected Integer getExpectedRestClientConfigCalls() {
protected Integer getExpectedRestClientConfigurerCalls() {
return 1;
}
@Override
public Integer getExpectedConnectionConfigurerCalls() {
return 1;
}
@Override
public Integer getExpectedConnectionManagerConfigurerCalls() {
return 1;
}
@Override
public Integer getExpectedRequestConfigurerCalls() {
return 1;
}
@ -467,7 +514,7 @@ public class RestClientsTest {
}
@Override
protected Integer getExpectedRestClientConfigCalls() {
protected Integer getExpectedRestClientConfigurerCalls() {
return 1;
}
@ -511,7 +558,7 @@ public class RestClientsTest {
}
@Override
protected Integer getExpectedRestClientConfigCalls() {
protected Integer getExpectedRestClientConfigurerCalls() {
return 1;
}

View File

@ -17,6 +17,7 @@ package org.springframework.data.elasticsearch.config.configuration;
import static org.assertj.core.api.Assertions.*;
import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.Nullable;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
@ -49,7 +50,7 @@ public class ReactiveElasticsearchConfigurationELCTests {
static class Config extends ReactiveElasticsearchConfiguration {
@Override
public ClientConfiguration clientConfiguration() {
public @NonNull ClientConfiguration clientConfiguration() {
return ClientConfiguration.builder() //
.connectedTo("localhost:9200") //
.build();

View File

@ -71,10 +71,10 @@ public abstract class EnableNestedRepositoriesIntegrationTests {
@Field(type = Text, store = true, fielddata = true) private String type;
@Nullable
@Field(type = Text, store = true, fielddata = true) private String message;
@Nullable private int rate;
private int rate;
@Nullable
@ScriptedField private Double scriptedRate;
@Nullable private boolean available;
private boolean available;
@Nullable private String highlightedMessage;
@Nullable private GeoPoint location;
@Nullable

View File

@ -114,10 +114,10 @@ public abstract class EnableRepositoriesIntegrationTests implements ApplicationC
@Field(type = Text, store = true, fielddata = true) private String type;
@Nullable
@Field(type = Text, store = true, fielddata = true) private String message;
@Nullable private int rate;
private int rate;
@Nullable
@ScriptedField private Double scriptedRate;
@Nullable private boolean available;
private boolean available;
@Nullable private String highlightedMessage;
@Nullable private GeoPoint location;
@Nullable
@ -208,10 +208,10 @@ public abstract class EnableRepositoriesIntegrationTests implements ApplicationC
@Nullable private String type;
@Nullable
@Field(type = FieldType.Text, fielddata = true) private String message;
@Nullable private int rate;
private int rate;
@Nullable
@ScriptedField private Long scriptedRate;
@Nullable private boolean available;
private boolean available;
@Nullable private String highlightedMessage;
@Nullable private GeoPoint location;
@Nullable

View File

@ -3900,10 +3900,10 @@ public abstract class ElasticsearchIntegrationTests {
@Field(type = Text, store = true, fielddata = true) private String type;
@Nullable
@Field(type = Text, store = true, fielddata = true) private String message;
@Nullable private int rate;
private int rate;
@Nullable
@ScriptedField private Double scriptedRate;
@Nullable private boolean available;
private boolean available;
@Nullable private GeoPoint location;
@Nullable
@Version private Long version;
@ -3918,7 +3918,7 @@ public abstract class ElasticsearchIntegrationTests {
@Nullable private String type;
@Nullable private String message;
@Nullable private Long version;
@Nullable private int rate;
private int rate;
@Nullable private GeoPoint location;
public Builder id(String id) {
@ -4115,10 +4115,10 @@ public abstract class ElasticsearchIntegrationTests {
@Nullable private String type;
@Nullable
@Field(type = FieldType.Text, fielddata = true) private String message;
@Nullable private int rate;
private int rate;
@Nullable
@ScriptedField private Long scriptedRate;
@Nullable private boolean available;
private boolean available;
@Nullable private GeoPoint location;
@Nullable
@Version private Long version;
@ -4806,8 +4806,7 @@ public abstract class ElasticsearchIntegrationTests {
@Document(indexName = "#{@indexNameProvider.indexName()}-immutable-scripted")
public static final class ImmutableWithScriptedEntity {
@Id private final String id;
@Field(type = Integer)
@Nullable private final int rate;
@Field(type = Integer) private final int rate;
@Nullable
@ScriptedField private final Double scriptedRate;
@ -4863,9 +4862,11 @@ public abstract class ElasticsearchIntegrationTests {
@Document(indexName = "#{@indexNameProvider.indexName()}-readonly-id")
static class ReadonlyIdEntity {
@Field(type = FieldType.Keyword) private String part1;
@Field(type = FieldType.Keyword)
@Nullable private String part1;
@Field(type = FieldType.Keyword) private String part2;
@Field(type = FieldType.Keyword)
@Nullable private String part2;
@Id
@WriteOnlyProperty
@ -4874,7 +4875,7 @@ public abstract class ElasticsearchIntegrationTests {
return part1 + '-' + part2;
}
public String getPart1() {
public @Nullable String getPart1() {
return part1;
}
@ -4882,7 +4883,7 @@ public abstract class ElasticsearchIntegrationTests {
this.part1 = part1;
}
public String getPart2() {
public @Nullable String getPart2() {
return part2;
}
@ -5006,9 +5007,11 @@ public abstract class ElasticsearchIntegrationTests {
private static class RootEntity {
@Id private String id;
@Field(type = FieldType.Object) private Child child;
@Field(type = FieldType.Object)
@Nullable private Child child;
@Field(type = FieldType.Object) private Parent parent;
@Field(type = FieldType.Object)
@Nullable private Parent parent;
@JoinTypeRelations(relations = {
@JoinTypeRelation(parent = "parent", children = { "child" })
@ -5030,7 +5033,7 @@ public abstract class ElasticsearchIntegrationTests {
this.id = id;
}
public Child getChild() {
public @Nullable Child getChild() {
return child;
}
@ -5038,7 +5041,7 @@ public abstract class ElasticsearchIntegrationTests {
this.child = child;
}
public Parent getParent() {
public @Nullable Parent getParent() {
return parent;
}

View File

@ -245,7 +245,7 @@ class EntityOperationsUnitTests {
@IndexedIndexName
@Nullable private String indexName;
public String getId() {
public @Nullable String getId() {
return id;
}

View File

@ -134,7 +134,7 @@ public abstract class LogEntityIntegrationTests {
@Nullable
@Id private String id;
@Nullable private String action;
@Nullable private long sequenceCode;
private long sequenceCode;
@Nullable
@Field(type = Ip) private String ip;
@Field(type = Date, format = DateFormat.date_time) private java.util.@Nullable Date date;
@ -149,7 +149,7 @@ public abstract class LogEntityIntegrationTests {
return format;
}
public String getId() {
public @Nullable String getId() {
return id;
}
@ -157,7 +157,7 @@ public abstract class LogEntityIntegrationTests {
this.id = id;
}
public String getAction() {
public @Nullable String getAction() {
return action;
}
@ -173,7 +173,7 @@ public abstract class LogEntityIntegrationTests {
this.sequenceCode = sequenceCode;
}
public String getIp() {
public @Nullable String getIp() {
return ip;
}
@ -181,7 +181,7 @@ public abstract class LogEntityIntegrationTests {
this.ip = ip;
}
public java.util.Date getDate() {
public java.util.@Nullable Date getDate() {
return date;
}

View File

@ -1298,7 +1298,7 @@ public abstract class ReactiveElasticsearchIntegrationTests {
@Id private String id;
@Nullable
@Field(type = Text, store = true, fielddata = true) private String message;
@Nullable private int rate;
private int rate;
@Nullable
@Version private Long version;
@ -1568,9 +1568,9 @@ public abstract class ReactiveElasticsearchIntegrationTests {
@Document(indexName = "#{@indexNameProvider.indexName()}-readonly-id")
static class ReadonlyIdEntity {
@Field(type = FieldType.Keyword) private String part1;
@Field(type = FieldType.Keyword) private @Nullable String part1;
@Field(type = FieldType.Keyword) private String part2;
@Field(type = FieldType.Keyword) private @Nullable String part2;
@Id
@WriteOnlyProperty
@ -1579,7 +1579,7 @@ public abstract class ReactiveElasticsearchIntegrationTests {
return part1 + '-' + part2;
}
public String getPart1() {
public @Nullable String getPart1() {
return part1;
}
@ -1587,7 +1587,7 @@ public abstract class ReactiveElasticsearchIntegrationTests {
this.part1 = part1;
}
public String getPart2() {
public @Nullable String getPart2() {
return part2;
}

View File

@ -164,7 +164,7 @@ public abstract class AggregationIntegrationTests {
@Nullable
@Field(type = Integer, store = true) private List<Integer> publishedYears = new ArrayList<>();
@Nullable private int score;
private int score;
public ArticleEntity(@Nullable String id) {
this.id = id;

View File

@ -25,7 +25,15 @@ import java.time.LocalTime;
import java.time.OffsetTime;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import org.intellij.lang.annotations.Language;
@ -128,7 +136,7 @@ public class MappingElasticsearchConverterUnitTests {
public void init() {
SimpleElasticsearchMappingContext mappingContext = new SimpleElasticsearchMappingContext();
mappingContext.setInitialEntitySet(Collections.singleton(Rifle.class));
mappingContext.setInitialEntitySet(singleton(Rifle.class));
mappingContext.afterPropertiesSet();
mappingElasticsearchConverter = new MappingElasticsearchConverter(mappingContext, new GenericConversionService());
@ -389,7 +397,7 @@ public class MappingElasticsearchConverterUnitTests {
@Test // DATAES-530
public void readListOfConcreteTypesCorrectly() {
sarahAsMap.put("coWorkers", Collections.singletonList(kyleAsMap));
sarahAsMap.put("coWorkers", singletonList(kyleAsMap));
Person target = mappingElasticsearchConverter.read(Person.class, sarahAsMap);
@ -414,7 +422,7 @@ public class MappingElasticsearchConverterUnitTests {
Map<String, Object> target = writeToMap(sarahConnor);
assertThat(target.get("shippingAddresses")).isInstanceOf(Map.class);
assertThat(target.get("shippingAddresses")).isEqualTo(Collections.singletonMap("home", gratiotAveAsMap));
assertThat(target.get("shippingAddresses")).isEqualTo(singletonMap("home", gratiotAveAsMap));
}
@Test // DATAES-530
@ -433,7 +441,7 @@ public class MappingElasticsearchConverterUnitTests {
@Test // DATAES-530
public void readConcreteMapCorrectly() {
sarahAsMap.put("shippingAddresses", Collections.singletonMap("home", gratiotAveAsMap));
sarahAsMap.put("shippingAddresses", singletonMap("home", gratiotAveAsMap));
Person target = mappingElasticsearchConverter.read(Person.class, sarahAsMap);
@ -443,7 +451,7 @@ public class MappingElasticsearchConverterUnitTests {
@Test // DATAES-530
public void readInterfaceMapCorrectly() {
sarahAsMap.put("inventoryMap", Collections.singletonMap("glock19", gunAsMap));
sarahAsMap.put("inventoryMap", singletonMap("glock19", gunAsMap));
Person target = mappingElasticsearchConverter.read(Person.class, sarahAsMap);
@ -490,7 +498,7 @@ public class MappingElasticsearchConverterUnitTests {
public void readGenericListList() {
Document source = Document.create();
source.put("objectList", Collections.singletonList(Arrays.asList(t800AsMap, gunAsMap)));
source.put("objectList", singletonList(Arrays.asList(t800AsMap, gunAsMap)));
Skynet target = mappingElasticsearchConverter.read(Skynet.class, source);
@ -515,7 +523,7 @@ public class MappingElasticsearchConverterUnitTests {
public void readGenericMap() {
Document source = Document.create();
source.put("objectMap", Collections.singletonMap("glock19", gunAsMap));
source.put("objectMap", singletonMap("glock19", gunAsMap));
Skynet target = mappingElasticsearchConverter.read(Skynet.class, source);
@ -527,23 +535,23 @@ public class MappingElasticsearchConverterUnitTests {
Skynet skynet = new Skynet();
skynet.objectMap = new LinkedHashMap<>();
skynet.objectMap.put("inventory", Collections.singletonMap("glock19", gun));
skynet.objectMap.put("inventory", singletonMap("glock19", gun));
Map<String, Object> target = writeToMap(skynet);
assertThat((Map<String, Object>) target.get("objectMap")).containsEntry("inventory",
Collections.singletonMap("glock19", gunAsMap));
singletonMap("glock19", gunAsMap));
}
@Test // DATAES-530
public void readGenericMapMap() {
Document source = Document.create();
source.put("objectMap", Collections.singletonMap("inventory", Collections.singletonMap("glock19", gunAsMap)));
source.put("objectMap", singletonMap("inventory", singletonMap("glock19", gunAsMap)));
Skynet target = mappingElasticsearchConverter.read(Skynet.class, source);
assertThat(target.getObjectMap()).containsEntry("inventory", Collections.singletonMap("glock19", gun));
assertThat(target.getObjectMap()).containsEntry("inventory", singletonMap("glock19", gun));
}
@Test // DATAES-530
@ -575,7 +583,7 @@ public class MappingElasticsearchConverterUnitTests {
@Test // DATAES-530
public void writesNestedAliased() {
t800.inventoryList = Collections.singletonList(rifle);
t800.inventoryList = singletonList(rifle);
Map<String, Object> target = writeToMap(t800);
assertThat((List<Document>) target.get("inventoryList")).contains(rifleAsMap);
@ -589,7 +597,7 @@ public class MappingElasticsearchConverterUnitTests {
@Test // DATAES-530
public void readsNestedAliased() {
t800AsMap.put("inventoryList", Collections.singletonList(rifleAsMap));
t800AsMap.put("inventoryList", singletonList(rifleAsMap));
assertThat(mappingElasticsearchConverter.read(Person.class, t800AsMap).getInventoryList()).containsExactly(rifle);
}
@ -911,12 +919,12 @@ public class MappingElasticsearchConverterUnitTests {
void shouldWriteMapContainingCollectionContainingMap() throws JSONException {
class EntityWithMapCollectionMap {
Map<String, Object> map;
Map<String, Object> map = Map.of();
}
class InnerEntity {
String prop1;
@Nullable String prop1;
String prop2;
@Nullable String prop2;
public InnerEntity() {}
@ -928,8 +936,8 @@ public class MappingElasticsearchConverterUnitTests {
}
var entity = new EntityWithMapCollectionMap();
entity.map = Collections.singletonMap("collection",
Collections.singletonList(Collections.singletonMap("destination", new InnerEntity("prop1", "prop2"))));
entity.map = singletonMap("collection",
singletonList(singletonMap("destination", new InnerEntity("prop1", "prop2"))));
var expected = """
{
@ -1069,67 +1077,79 @@ public class MappingElasticsearchConverterUnitTests {
class RangeEntity {
@Id private String id;
@Field(type = FieldType.Integer_Range) private Range<Integer> integerRange;
@Field(type = FieldType.Float_Range) private Range<Float> floatRange;
@Field(type = FieldType.Long_Range) private Range<Long> longRange;
@Field(type = FieldType.Double_Range) private Range<Double> doubleRange;
@Field(type = FieldType.Date_Range) private Range<Date> dateRange;
@Field(type = FieldType.Date_Range, format = DateFormat.year_month_day) private Range<LocalDate> localDateRange;
@Field(type = FieldType.Integer_Range)
@Nullable private Range<Integer> integerRange;
@Field(type = FieldType.Float_Range)
@Nullable private Range<Float> floatRange;
@Field(type = FieldType.Long_Range)
@Nullable private Range<Long> longRange;
@Field(type = FieldType.Double_Range)
@Nullable private Range<Double> doubleRange;
@Field(type = FieldType.Date_Range)
@Nullable private Range<Date> dateRange;
@Field(type = FieldType.Date_Range, format = DateFormat.year_month_day)
@Nullable private Range<LocalDate> localDateRange;
@Field(type = FieldType.Date_Range,
format = DateFormat.hour_minute_second_millis) private Range<LocalTime> localTimeRange;
format = DateFormat.hour_minute_second_millis)
@Nullable private Range<LocalTime> localTimeRange;
@Field(type = FieldType.Date_Range,
format = DateFormat.date_hour_minute_second_millis) private Range<LocalDateTime> localDateTimeRange;
@Field(type = FieldType.Date_Range, format = DateFormat.time) private Range<OffsetTime> offsetTimeRange;
@Field(type = FieldType.Date_Range) private Range<ZonedDateTime> zonedDateTimeRange;
@Field(type = FieldType.Date_Range, storeNullValue = true) private Range<ZonedDateTime> nullRange;
format = DateFormat.date_hour_minute_second_millis)
@Nullable private Range<LocalDateTime> localDateTimeRange;
@Field(type = FieldType.Date_Range, format = DateFormat.time)
@Nullable private Range<OffsetTime> offsetTimeRange;
@Field(type = FieldType.Date_Range)
@Nullable private Range<ZonedDateTime> zonedDateTimeRange;
@Field(type = FieldType.Date_Range, storeNullValue = true)
@Nullable private Range<ZonedDateTime> nullRange;
@Field(type = FieldType.Integer_Range) private List<Range<Integer>> integerRangeList;
@Field(type = FieldType.Integer_Range)
@Nullable private List<Range<Integer>> integerRangeList;
public String getId() {
return id;
}
public Range<Integer> getIntegerRange() {
public @Nullable Range<Integer> getIntegerRange() {
return integerRange;
}
public Range<Float> getFloatRange() {
public @Nullable Range<Float> getFloatRange() {
return floatRange;
}
public Range<Long> getLongRange() {
public @Nullable Range<Long> getLongRange() {
return longRange;
}
public Range<Double> getDoubleRange() {
public @Nullable Range<Double> getDoubleRange() {
return doubleRange;
}
public Range<Date> getDateRange() {
public @Nullable Range<Date> getDateRange() {
return dateRange;
}
public Range<LocalDate> getLocalDateRange() {
public @Nullable Range<LocalDate> getLocalDateRange() {
return localDateRange;
}
public Range<LocalTime> getLocalTimeRange() {
public @Nullable Range<LocalTime> getLocalTimeRange() {
return localTimeRange;
}
public Range<LocalDateTime> getLocalDateTimeRange() {
public @Nullable Range<LocalDateTime> getLocalDateTimeRange() {
return localDateTimeRange;
}
public Range<OffsetTime> getOffsetTimeRange() {
public @Nullable Range<OffsetTime> getOffsetTimeRange() {
return offsetTimeRange;
}
public Range<ZonedDateTime> getZonedDateTimeRange() {
public @Nullable Range<ZonedDateTime> getZonedDateTimeRange() {
return zonedDateTimeRange;
}
public Range<ZonedDateTime> getNullRange() {
public @Nullable Range<ZonedDateTime> getNullRange() {
return nullRange;
}
@ -1181,7 +1201,7 @@ public class MappingElasticsearchConverterUnitTests {
this.nullRange = nullRange;
}
public List<Range<Integer>> getIntegerRangeList() {
public @Nullable List<Range<Integer>> getIntegerRangeList() {
return integerRangeList;
}
@ -2639,8 +2659,7 @@ public class MappingElasticsearchConverterUnitTests {
@Nullable private GeoPoint pointB;
@Nullable
@GeoPointField private String pointC;
@Nullable
@GeoPointField private double[] pointD;
@GeoPointField private double @Nullable [] pointD;
@Nullable
public String getId() {
@ -2705,12 +2724,11 @@ public class MappingElasticsearchConverterUnitTests {
this.pointC = pointC;
}
@Nullable
public double[] getPointD() {
public double @Nullable [] getPointD() {
return pointD;
}
public void setPointD(@Nullable double[] pointD) {
public void setPointD(double @Nullable [] pointD) {
this.pointD = pointD;
}
}
@ -3259,7 +3277,8 @@ public class MappingElasticsearchConverterUnitTests {
@Id
@Nullable private String id;
@Field(type = FieldType.Nested, name = "level-one") private List<Level1> level1Entries;
@Field(type = FieldType.Nested, name = "level-one")
@Nullable private List<Level1> level1Entries;
@Nullable
public String getId() {
@ -3270,7 +3289,7 @@ public class MappingElasticsearchConverterUnitTests {
this.id = id;
}
public List<Level1> getLevel1Entries() {
public @Nullable List<Level1> getLevel1Entries() {
return level1Entries;
}
@ -3279,9 +3298,10 @@ public class MappingElasticsearchConverterUnitTests {
}
static class Level1 {
@Field(type = FieldType.Nested, name = "level-two") private List<Level2> level2Entries;
@Field(type = FieldType.Nested, name = "level-two")
@Nullable private List<Level2> level2Entries;
public List<Level2> getLevel2Entries() {
public @Nullable List<Level2> getLevel2Entries() {
return level2Entries;
}
@ -3291,9 +3311,10 @@ public class MappingElasticsearchConverterUnitTests {
}
static class Level2 {
@Field(type = FieldType.Keyword, name = "key-word") private String keyWord;
@Field(type = FieldType.Keyword, name = "key-word")
@Nullable private String keyWord;
public String getKeyWord() {
public @Nullable String getKeyWord() {
return keyWord;
}

View File

@ -424,12 +424,11 @@ public abstract class GeoIntegrationTests {
@Nullable private String name;
@Nullable
@GeoPointField private String locationAsString;
@Nullable
@GeoPointField private double[] locationAsArray;
@GeoPointField private double @Nullable [] locationAsArray;
@Nullable
@GeoPointField private String locationAsGeoHash;
public String getId() {
public @Nullable String getId() {
return id;
}
@ -437,7 +436,7 @@ public abstract class GeoIntegrationTests {
this.id = id;
}
public String getName() {
public @Nullable String getName() {
return name;
}
@ -445,7 +444,7 @@ public abstract class GeoIntegrationTests {
this.name = name;
}
public String getLocationAsString() {
public @Nullable String getLocationAsString() {
return locationAsString;
}
@ -461,7 +460,7 @@ public abstract class GeoIntegrationTests {
this.locationAsArray = locationAsArray;
}
public String getLocationAsGeoHash() {
public @Nullable String getLocationAsGeoHash() {
return locationAsGeoHash;
}

View File

@ -724,8 +724,7 @@ public abstract class MappingBuilderIntegrationTests extends MappingContextBaseT
static class DenseVectorEntity {
@Nullable
@Id private String id;
@Nullable
@Field(type = Dense_Vector, dims = 3) private float[] dense_vector;
@Field(type = Dense_Vector, dims = 3) private float @Nullable [] dense_vector;
@Nullable
public String getId() {
@ -736,12 +735,11 @@ public abstract class MappingBuilderIntegrationTests extends MappingContextBaseT
this.id = id;
}
@Nullable
public float[] getDense_vector() {
public float @Nullable [] getDense_vector() {
return dense_vector;
}
public void setDense_vector(@Nullable float[] dense_vector) {
public void setDense_vector(float @Nullable [] dense_vector) {
this.dense_vector = dense_vector;
}
}
@ -915,7 +913,8 @@ public abstract class MappingBuilderIntegrationTests extends MappingContextBaseT
@Nullable
@Id private String id;
@Field(type = FieldType.Dense_Vector, dims = 42, knnSimilarity = KnnSimilarity.COSINE) private double[] denseVector;
@Field(type = FieldType.Dense_Vector, dims = 42,
knnSimilarity = KnnSimilarity.COSINE) private double @Nullable [] denseVector;
}
@Mapping(aliases = {

View File

@ -1398,7 +1398,7 @@ public class MappingBuilderUnitTests extends MappingContextBaseTests {
@Field("mapping-property")
@Mapping(mappingPath = "/mappings/test-field-analyzed-mappings.json") //
@Nullable private byte[] mappingProperty;
private byte @Nullable [] mappingProperty;
}
@SuppressWarnings("unused")
@ -1820,8 +1820,7 @@ public class MappingBuilderUnitTests extends MappingContextBaseTests {
@Nullable private GeoPoint pointB;
@Nullable
@GeoPointField private String pointC;
@Nullable
@GeoPointField private double[] pointD;
@GeoPointField private double @Nullable [] pointD;
@Nullable
@GeoShapeField private String shape1;
@ -1892,12 +1891,11 @@ public class MappingBuilderUnitTests extends MappingContextBaseTests {
this.pointC = pointC;
}
@Nullable
public double[] getPointD() {
public double @Nullable [] getPointD() {
return pointD;
}
public void setPointD(@Nullable double[] pointD) {
public void setPointD(double @Nullable [] pointD) {
this.pointD = pointD;
}
@ -2171,8 +2169,7 @@ public class MappingBuilderUnitTests extends MappingContextBaseTests {
static class DenseVectorEntity {
@Nullable
@Id private String id;
@Nullable
@Field(type = FieldType.Dense_Vector, dims = 16) private float[] my_vector;
@Field(type = FieldType.Dense_Vector, dims = 16) private float @Nullable [] my_vector;
@Nullable
public String getId() {
@ -2183,12 +2180,11 @@ public class MappingBuilderUnitTests extends MappingContextBaseTests {
this.id = id;
}
@Nullable
public float[] getMy_vector() {
public float @Nullable [] getMy_vector() {
return my_vector;
}
public void setMy_vector(@Nullable float[] my_vector) {
public void setMy_vector(float @Nullable [] my_vector) {
this.my_vector = my_vector;
}
}
@ -2198,10 +2194,9 @@ public class MappingBuilderUnitTests extends MappingContextBaseTests {
@Nullable
@Id private String id;
@Nullable
@Field(type = FieldType.Dense_Vector, dims = 16, elementType = FieldElementType.FLOAT,
knnIndexOptions = @KnnIndexOptions(type = KnnAlgorithmType.HNSW, m = 16, efConstruction = 100),
knnSimilarity = KnnSimilarity.DOT_PRODUCT) private float[] my_vector;
knnSimilarity = KnnSimilarity.DOT_PRODUCT) private float @Nullable [] my_vector;
@Nullable
public String getId() {
@ -2212,12 +2207,11 @@ public class MappingBuilderUnitTests extends MappingContextBaseTests {
this.id = id;
}
@Nullable
public float[] getMy_vector() {
public float @Nullable [] getMy_vector() {
return my_vector;
}
public void setMy_vector(@Nullable float[] my_vector) {
public void setMy_vector(float @Nullable [] my_vector) {
this.my_vector = my_vector;
}
}
@ -2277,7 +2271,7 @@ public class MappingBuilderUnitTests extends MappingContextBaseTests {
static class DenseVectorMisMatchConfidenceIntervalClass {
@Field(type = Dense_Vector, dims = 16, elementType = FieldElementType.FLOAT,
knnIndexOptions = @KnnIndexOptions(type = KnnAlgorithmType.HNSW, m = 16, confidenceInterval = 0.95F),
knnSimilarity = KnnSimilarity.DOT_PRODUCT) private float[] dense_vector;
knnSimilarity = KnnSimilarity.DOT_PRODUCT) private float @Nullable [] dense_vector;
}
static class DisabledMappingProperty {

View File

@ -110,10 +110,10 @@ public class MappingParametersTest extends MappingContextBaseTests {
}
static class DenseVectorInvalidDimsClass {
@Field(type = Dense_Vector, dims = 4097) private float[] dense_vector;
@Field(type = Dense_Vector, dims = 4097) private float @Nullable [] dense_vector;
}
static class DenseVectorMissingDimsClass {
@Field(type = Dense_Vector) private float[] dense_vector;
@Field(type = Dense_Vector) private float @Nullable [] dense_vector;
}
}

View File

@ -444,7 +444,8 @@ public abstract class ReactiveIndexOperationsIntegrationTests {
})
private static class EntityWithAliases {
@Nullable private @Id String id;
@Field(type = Text) private String type;
@Field(type = Text)
@Nullable private String type;
@Nullable
public String getId() {
@ -455,7 +456,7 @@ public abstract class ReactiveIndexOperationsIntegrationTests {
this.id = id;
}
public String getType() {
public @Nullable String getType() {
return type;
}

View File

@ -325,7 +325,7 @@ public class SimpleElasticsearchPersistentPropertyUnitTests {
static class FieldNamingStrategyEntity {
@Nullable private String withoutCustomFieldName;
@Field(name = "CUStomFIEldnAME") private String withCustomFieldName;
@Field(name = "CUStomFIEldnAME") @Nullable private String withCustomFieldName;
@Nullable
public String getWithoutCustomFieldName() {
@ -336,7 +336,7 @@ public class SimpleElasticsearchPersistentPropertyUnitTests {
this.withoutCustomFieldName = withoutCustomFieldName;
}
public String getWithCustomFieldName() {
public @Nullable String getWithCustomFieldName() {
return withCustomFieldName;
}

View File

@ -715,7 +715,7 @@ public abstract class CriteriaQueryIntegrationTests {
@Field(type = Text, store = true, fielddata = true) private String type;
@Nullable
@Field(type = Text, store = true, fielddata = true) private String message;
@Nullable private int rate;
private int rate;
@Nullable
@Version private Long version;

View File

@ -27,7 +27,6 @@ import java.util.Properties;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jspecify.annotations.Nullable;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testcontainers.elasticsearch.ElasticsearchContainer;
@ -41,7 +40,7 @@ import org.testcontainers.utility.DockerImageName;
*
* @author Peter-Josef Meisch
*/
public class ClusterConnection implements ExtensionContext.Store.CloseableResource {
public class ClusterConnection implements AutoCloseable {
private static final Log LOGGER = LogFactory.getLog(ClusterConnection.class);
@ -106,7 +105,7 @@ public class ClusterConnection implements ExtensionContext.Store.CloseableResour
LOGGER.warn("DATAES_ELASTICSEARCH_PORT does not contain a number");
}
return ClusterConnectionInfo.builder().withIntegrationtestEnvironment(IntegrationtestEnvironment.get())
return ClusterConnectionInfo.builder(IntegrationtestEnvironment.get())
.withHostAndPort(host, port).build();
}
@ -138,11 +137,10 @@ public class ClusterConnection implements ExtensionContext.Store.CloseableResour
.withEnv(testcontainersProperties).withStartupTimeout(Duration.ofMinutes(2)).withReuse(true);
elasticsearchContainer.start();
return ClusterConnectionInfo.builder() //
.withIntegrationtestEnvironment(integrationtestEnvironment)
return ClusterConnectionInfo.builder(integrationtestEnvironment)
.withHostAndPort(elasticsearchContainer.getHost(),
elasticsearchContainer.getMappedPort(ELASTICSEARCH_DEFAULT_PORT)) //
.withElasticsearchContainer(elasticsearchContainer) //
elasticsearchContainer.getMappedPort(ELASTICSEARCH_DEFAULT_PORT))
.withElasticsearchContainer(elasticsearchContainer)
.build();
} catch (Exception e) {
LOGGER.error("Could not start Elasticsearch container", e);

View File

@ -24,7 +24,7 @@ import org.testcontainers.elasticsearch.ElasticsearchContainer;
* The {@link #host}, {@link #httpPort} and {@link #useSsl} values specify the values needed to connect to the cluster
* with a rest client for both a local started cluster and for one defined by the cluster URL when creating the
* {@link ClusterConnection}.<br/>
* The object must be created by using a {@link ClusterConnectionInfo.Builder}.
* The object must be created by using a {@link Builder}.
*
* @author Peter-Josef Meisch
*/
@ -36,8 +36,8 @@ public final class ClusterConnectionInfo {
private final String clusterName;
@Nullable private final ElasticsearchContainer elasticsearchContainer;
public static Builder builder() {
return new Builder();
public static Builder builder(IntegrationtestEnvironment integrationtestEnvironment) {
return new Builder(integrationtestEnvironment);
}
private ClusterConnectionInfo(IntegrationtestEnvironment integrationtestEnvironment, String host, int httpPort,
@ -84,13 +84,12 @@ public final class ClusterConnectionInfo {
public static class Builder {
private IntegrationtestEnvironment integrationtestEnvironment;
private boolean useSsl = false;
private String host;
private String host = "";
private int httpPort;
@Nullable private ElasticsearchContainer elasticsearchContainer;
public Builder withIntegrationtestEnvironment(IntegrationtestEnvironment integrationtestEnvironment) {
public Builder(IntegrationtestEnvironment integrationtestEnvironment) {
this.integrationtestEnvironment = integrationtestEnvironment;
return this;
}
public Builder withHostAndPort(String host, int httpPort) {

View File

@ -176,7 +176,7 @@ public class CdiRepositoryTests {
@Nullable
@Field(type = FieldType.Float) private Float price;
@Nullable private Integer popularity;
@Nullable private boolean available;
private boolean available;
@Nullable private String location;
@Nullable private Date lastModified;
@ -293,11 +293,12 @@ public class CdiRepositoryTests {
@Id private String id;
private String name;
@Nullable private String name;
@Field(type = FieldType.Nested) private List<Car> car;
@Field(type = FieldType.Nested)
@Nullable private List<Car> car;
@Field(type = FieldType.Nested, includeInParent = true) private List<Book> books;
@Field(type = FieldType.Nested, includeInParent = true) private @Nullable List<Book> books;
}

View File

@ -2443,8 +2443,8 @@ public abstract class CustomMethodRepositoryIntegrationTests {
@Field(type = Text, store = true, fielddata = true) private String message;
@Nullable
@Field(type = Keyword) private String keyword;
@Nullable private int rate;
@Nullable private boolean available;
private int rate;
private boolean available;
@Nullable private GeoPoint location;
@Nullable
@Version private Long version;

View File

@ -116,8 +116,7 @@ public abstract class GeoRepositoryIntegrationTests {
@Nullable private GeoPoint pointB;
@Nullable
@GeoPointField private String pointC;
@Nullable
@GeoPointField private double[] pointD;
@GeoPointField private double @Nullable [] pointD;
@Nullable
public String getId() {
@ -182,12 +181,11 @@ public abstract class GeoRepositoryIntegrationTests {
this.pointC = pointC;
}
@Nullable
public double[] getPointD() {
public double @Nullable [] getPointD() {
return pointD;
}
public void setPointD(@Nullable double[] pointD) {
public void setPointD(double @Nullable [] pointD) {
this.pointD = pointD;
}
}

View File

@ -165,12 +165,11 @@ public abstract class KnnSearchIntegrationTests {
this.message = message;
}
@Nullable
public float[] getVector() {
public float @Nullable [] getVector() {
return vector;
}
public void setVector(@Nullable float[] vector) {
public void setVector(float @Nullable [] vector) {
this.vector = vector;
}
}

View File

@ -510,7 +510,7 @@ public class RepositoryStringQueryUnitTests extends RepositoryStringQueryUnitTes
@Document(indexName = "test-index-person-query-unittest")
static class Person {
@Nullable public int age;
public int age;
@Nullable
@Id private String id;
@Nullable private String name;
@ -519,7 +519,6 @@ public class RepositoryStringQueryUnitTests extends RepositoryStringQueryUnitTes
@Nullable
@Field(type = FieldType.Nested, includeInParent = true) private List<Book> books;
@Nullable
public int getAge() {
return age;
}

View File

@ -296,7 +296,7 @@ abstract class QueryKeywordsIntegrationTests {
@Field(type = FieldType.Keyword) private String text;
@Nullable
@Field(type = FieldType.Float) private Float price;
@Nullable private boolean available;
private boolean available;
@Nullable
@Field(name = "sort-name", type = FieldType.Keyword) private String sortName;

View File

@ -15,6 +15,7 @@
*/
package org.springframework.data.elasticsearch.repository.query.valueconverter;
import org.jspecify.annotations.NonNull;
import reactor.core.publisher.Flux;
import reactor.test.StepVerifier;
@ -125,12 +126,12 @@ public abstract class ReactiveValueConverterIntegrationTests {
public static final String PREFIX = "text-";
@Override
public Object write(Object value) {
public @NonNull Object write(@NonNull Object value) {
return PREFIX + value.toString();
}
@Override
public Object read(Object value) {
public @NonNull Object read(@NonNull Object value) {
String valueString = value.toString();

View File

@ -17,6 +17,7 @@ package org.springframework.data.elasticsearch.repository.query.valueconverter;
import static org.assertj.core.api.Assertions.*;
import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.Nullable;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
@ -121,12 +122,12 @@ abstract class ValueConverterIntegrationTests {
public static final String PREFIX = "text-";
@Override
public Object write(Object value) {
public Object write(@NonNull Object value) {
return PREFIX + value.toString();
}
@Override
public Object read(Object value) {
public Object read(@NonNull Object value) {
String valueString = value.toString();

View File

@ -664,8 +664,8 @@ abstract class ElasticsearchRepositoryIntegrationTests {
@Field(type = FieldType.Text, store = true, fielddata = true) private String type;
@Nullable
@Field(type = FieldType.Text, store = true, fielddata = true) private String message;
@Nullable private int rate;
@Nullable private boolean available;
private int rate;
private boolean available;
@Nullable
@Version private Long version;

View File

@ -15,7 +15,7 @@
#
#
sde.testcontainers.image-name=docker.elastic.co/elasticsearch/elasticsearch
sde.testcontainers.image-version=9.0.3
sde.testcontainers.image-version=9.0.4
#
#
# needed as we do a DELETE /* at the end of the tests, will be required from 8.0 on, produces a warning since 7.13