Remove deprecated code.

Original Pull Request #2564
Closes #2563
This commit is contained in:
Peter-Josef Meisch 2023-05-13 13:29:06 +02:00 committed by GitHub
parent 34b0181014
commit 5b02364384
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 26 additions and 1089 deletions

View File

@ -8,7 +8,3 @@ Do not submit a Pull Request before having created an issue and having discussed
== Running the test locally
In order to run the tests locally with `./mvnw test` you need to have docker running because Spring Data Elasticsearch uses https://www.testcontainers.org/[Testcontainers] to start a local running Elasticsearch instance.
== Class names of the test classes
Test classes that do depend on the client have either `ERHLC` (when using the deprecated Elasticsearch `RestHighLevelClient`) or `ELC` (the new `ElasticsearchClient`) in their name.

View File

@ -5,13 +5,13 @@ image:https://spring.io/badges/spring-data-elasticsearch/ga.svg[Spring Data Elas
The primary goal of the https://projects.spring.io/spring-data[Spring Data] project is to make it easier to build Spring-powered applications that use new data access technologies such as non-relational databases, map-reduce frameworks, and cloud based data services.
The Spring Data Elasticsearch project provides integration with the https://www.elastic.co/[Elasticsearch] search engine.
Key functional areas of Spring Data Elasticsearch are a POJO centric model for interacting with a Elasticsearch Documents and easily writing a Repository style data access layer.
Key functional areas of Spring Data Elasticsearch are a POJO centric model for interacting with Elasticsearch Documents and easily writing a Repository style data access layer.
This project is lead and maintained by the community.
== Features
* Spring configuration support using Java based `@Configuration` classes or an XML namespace for a ES clients instances.
* Spring configuration support using Java based `@Configuration` classes or an XML namespace for an ES client instances.
* `ElasticsearchOperations` class and implementations that increases productivity performing common ES operations.
Includes integrated object mapping between documents and POJOs.
* Feature Rich Object Mapping integrated with Spring’s Conversion Service
@ -19,28 +19,6 @@ Includes integrated object mapping between documents and POJOs.
* Automatic implementation of `Repository` interfaces including support for custom search methods.
* CDI support for repositories
== About Elasticsearch versions and clients
=== Elasticsearch 7.17 client libraries
At the end of 2021 Elasticsearch with version 7.17 released the new version of their Java client and deprecated the `RestHighLevelCLient` which was the default way to access Elasticsearch up to then.
Spring Data Elasticsearch will in version 4.4 offer the possibility to optionally use the new client as an alternative to the existing setup using the `RestHighLevelCLient`.
The default client that is used still is the `RestHighLevelCLient`, first because the integration of the new client is not yet complete, the new client still has features missing and bugs which will hopefully be resolved soon.
Second, and more important, the new Elasticsearch client forces users to switch from using `javax.json.spi.JsonProvider` to `jakarta.json.spi.JsonProvider`.
Spring Data Elasticsearch cannot enforce this switch; Spring Boot will switch to `jakarta` with version 3 and then it's safe for Spring Data Elasticsearch to switch to the new client.
So for version 4.4 Spring Data Elasticsearch will keep using the `RestHighLevelCLient` in version 7.17.x (as long as this will be available).
=== Elasticsearch 8 client libraries
In Elasticsearch 8, the `RestHighLevelCLient` has been removed.
This means that a switch to this client version can only be done with the next major upgrade which will be Spring Data Elasticsearch 5, based on Spring Data 3, used by Spring Boot 3, based on Spring 6 and Java 17.
=== Elasticsearch 8 cluster
It should be possible to use the Elasticsearch 7 client to access a cluster running version 8 by setting the appropriate compatibility headers (see the documentation at https://docs.spring.io/spring-data/elasticsearch/docs/current/reference/html/#elasticsearch.clients.configuration). but I encountered and heard of cases where the response from the server is not parseable by the client although the headers are set, so use with care.
== Code of Conduct
This project is governed by the https://github.com/spring-projects/.github/blob/e3cc2ff230d8f1dca06535aa6b5a4a23815861d4/CODE_OF_CONDUCT.md[Spring Code of Conduct].
@ -86,25 +64,7 @@ public class MyService {
=== Using the RestClient
Provide a configuration like this:
[source,java]
----
@Configuration
public class RestClientConfig extends AbstractElasticsearchConfiguration {
@Override
@Bean
public RestHighLevelClient elasticsearchClient() {
final ClientConfiguration clientConfiguration = ClientConfiguration.builder()
.connectedTo("localhost:9200")
.build();
return RestClients.create(clientConfiguration).rest();
}
}
----
Please check the [official documentation](https://docs.spring.io/spring-data/elasticsearch/docs/current/reference/html/#elasticsearch.clients.configuration).
=== Maven configuration
@ -119,9 +79,6 @@ Add the Maven dependency:
</dependency>
----
// NOTE: since Github does not support include directives, the content of
// the src/main/asciidoc/reference/preface.adoc file is duplicated here
// Always change both files!
**Compatibility Matrix**
The compatibility between Spring Data Elasticsearch, Elasticsearch client drivers and Spring Boot versions can be found in the https://docs.spring.io/spring-data/elasticsearch/docs/current/reference/html/#preface.versions[reference documentation].

View File

@ -105,98 +105,6 @@ This is a reactive implementation based on the Elasticsearch client implementati
Basically one should just use the `ReactiveElasticsearchOperations` to interact with the Elasticsearch cluster.
When using repositories, this instance is used under the hood as well.
[[elasticsearch.clients.resthighlevelclient]]
== High Level REST Client (deprecated)
[CAUTION]
====
The Elasticsearch Java RestHighLevelClient is deprecated, but still can be configured like shown (make sure to read
<<elasticsearch-migration-guide-4.4-5.0.old-client>> as well).
It should only be used to access an Elasticsearch cluster running version 7, even with the compatibility headers set
there are cases where the `RestHighLevelClient` cannot read the responses sent from a version 8 cluster.
====
.RestHighLevelClient
====
[source,java]
----
import org.springframework.data.elasticsearch.client.erhlc.AbstractElasticsearchConfiguration;
@Configuration
public class RestClientConfig extends AbstractElasticsearchConfiguration {
@Override
@Bean
public RestHighLevelClient elasticsearchClient() {
final ClientConfiguration clientConfiguration = ClientConfiguration.builder() <1>
.connectedTo("localhost:9200")
.build();
return RestClients.create(clientConfiguration).rest(); <2>
}
}
// ...
@Autowired
RestHighLevelClient highLevelClient;
RestClient lowLevelClient = highLevelClient.lowLevelClient(); <3>
----
<1> Use the builder to provide cluster addresses, set default `HttpHeaders` or enable SSL.
<2> Create the RestHighLevelClient.
<3> It is also possible to obtain the `lowLevelRest()` client.
====
[[elasticsearch.clients.reactive]]
== Reactive Client (deprecated)
The `org.springframework.data.elasticsearch.client.erhlc.ReactiveElasticsearchClient` is a non official driver based on `WebClient`.
It uses the request/response objects provided by the Elasticsearch core project.
Calls are directly operated on the reactive stack, **not** wrapping async (thread pool bound) responses into reactive types.
[CAUTION]
====
This was the first reactive implementation Spring Data Elasticsearch provided, but now is deprecated in favour
of the `org.springframework.data.elasticsearch.client.elc.ReactiveElasticsearchClient`
which uses the functionality offered by the new Elasticsearch client libraries.
====
.Reactive REST Client (deprecated)
====
[source,java]
----
import org.springframework.data.elasticsearch.client.erhlc.AbstractReactiveElasticsearchConfiguration;
@Configuration
public class ReactiveRestClientConfig extends AbstractReactiveElasticsearchConfiguration {
@Override
@Bean
public ReactiveElasticsearchClient reactiveElasticsearchClient() {
final ClientConfiguration clientConfiguration = ClientConfiguration.builder() <.>
.connectedTo("localhost:9200") //
.build();
return ReactiveRestClients.create(clientConfiguration);
}
}
// ...
Mono<IndexResponse> response = client.index(request ->
request.index("spring-data")
.id(randomID())
.source(singletonMap("feature", "reactive-client"));
);
----
<.> Use the builder to provide cluster addresses, set default `HttpHeaders` or enable SSL.
====
[[elasticsearch.clients.configuration]]
== Client Configuration
@ -298,38 +206,6 @@ ClientConfiguration.builder()
----
====
[[elasticsearch.clients.configuration.headers]]
=== Elasticsearch 7 compatibility headers
When using the deprecated `RestHighLevelClient` and accessing an Elasticsearch cluster that is running on version 8, it is necessary to set the compatibility headers
https://www.elastic.co/guide/en/elasticsearch/reference/8.0/rest-api-compatibility.html[see Elasticsearch
documentation].
For the imperative client this must be done by setting the default headers, for the reactive code this must be done using a header supplier:
CAUTION: Even when these headers are set, there are cases where the response returned from the cluster cannot be
parsed with the client. This is not an error in Spring Data Elasticsearch.
====
[source,java]
----
HttpHeaders compatibilityHeaders = new HttpHeaders();
compatibilityHeaders.add("Accept", "application/vnd.elasticsearch+json;compatible-with=7");
compatibilityHeaders.add("Content-Type", "application/vnd.elasticsearch+json;"
+ "compatible-with=7");
ClientConfiguration clientConfiguration = ClientConfiguration.builder()
.connectedTo("localhost:9200")
.withProxy("localhost:8080")
.withBasicAuth("elastic","hcraescitsale")
.withDefaultHeaders(compatibilityHeaders) // this variant for imperative code
.withHeaders(() -> compatibilityHeaders) // this variant for reactive code
.build();
----
====
[[elasticsearch.clients.logging]]
== Client Logging

View File

@ -6,6 +6,16 @@ This section describes breaking changes from version 5.1.x to 5.2.x and how remo
[[elasticsearch-migration-guide-5.1-5.2.breaking-changes]]
== Breaking Changes
[[elasticsearch-migration-guide-5.1-5.2.deprecations]]
== Deprecations
=== Removal of deprecated code
* All the code using the old deprecated `RestHighLevelClient` has been removed.
The default Elasticsearch client used since version 5.0 is the (not so) new Elasticsearch Java client.
* The `org.springframework.data.elasticsearch.client.ClientLogger` class has been removed.
This logger was configured with the `org.springframework.data.elasticsearch.client.WIRE` setting, but was not working with all clients.
From version 5 on, use the trace logger available in the Elasticsearch Java client, see <<elasticsearch.clients.logging>>.
* The method `org.springframework.data.elasticsearch.core.ElasticsearchOperations.stringIdRepresentation(Object)` has been removed, use the `convertId(Object)` method defined in the same interface instead.
* The class `org.springframework.data.elasticsearch.core.Range` has been removed, use `org.springframework.data.domain.Range` instead.
* The methods `org.springframework.data.elasticsearch.core.query.IndexQuery.getParentId() and `setParentId(String)` have been removed, they werent used anymore and were no-ops. It has been removed from the `org.springframework.data.elasticsearch.core.query.IndexQuery` class as well.

View File

@ -59,7 +59,6 @@ class ClientConfigurationBuilder
@Nullable private String pathPrefix;
@Nullable private String proxy;
private Supplier<HttpHeaders> headersSupplier = HttpHeaders::new;
@Deprecated private final HttpClientConfigCallback httpClientConfigurer = httpClientBuilder -> httpClientBuilder;
private final List<ClientConfiguration.ClientConfigurationCallback<?>> clientConfigurers = new ArrayList<>();
/*
@ -242,7 +241,7 @@ class ClientConfigurationBuilder
}
return new DefaultClientConfiguration(hosts, headers, useSsl, sslContext, caFingerprint, soTimeout, connectTimeout,
pathPrefix, hostnameVerifier, proxy, httpClientConfigurer, clientConfigurers, headersSupplier);
pathPrefix, hostnameVerifier, proxy, clientConfigurers, headersSupplier);
}
private static InetSocketAddress parse(String hostAndPort) {

View File

@ -1,195 +0,0 @@
/*
* Copyright 2018-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.elasticsearch.client;
import java.util.function.Supplier;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.lang.Nullable;
import org.springframework.util.ObjectUtils;
/**
* Logging Utility to log client requests and responses. Logs client requests and responses to Elasticsearch to a
* dedicated logger: {@code org.springframework.data.elasticsearch.client.WIRE} on trace level.
*
* @author Mark Paluch
* @author Christoph Strobl
* @author Peter-Josef Meisch
* @author Oliver Drotbohm
* @since 3.2
* @deprecated since 5.0, Elasticsearch's RestClient has a trace level logging available.
*/
@Deprecated
public abstract class ClientLogger {
private static final Log WIRE_LOGGER = LogFactory.getLog("org.springframework.data.elasticsearch.client.WIRE");
private ClientLogger() {}
/**
* Returns {@literal true} if the logger is enabled.
*
* @return {@literal true} if the logger is enabled.
*/
public static boolean isEnabled() {
return WIRE_LOGGER.isTraceEnabled();
}
/**
* Log an outgoing HTTP request.
*
* @param logId the correlation id, see {@link #newLogId()}.
* @param method HTTP method
* @param endpoint URI
* @param parameters optional parameters.
*/
public static void logRequest(String logId, String method, String endpoint, Object parameters) {
if (isEnabled()) {
WIRE_LOGGER.trace(String.format("[%s] Sending request %s %s with parameters: %s", logId, method.toUpperCase(),
endpoint, parameters));
}
}
/**
* Log an outgoing HTTP request.
*
* @param logId the correlation id, see {@link #newLogId()}.
* @param method HTTP method
* @param endpoint URI
* @param parameters optional parameters.
* @param headers a String containing the headers
* @since 4.4
*/
public static void logRequest(String logId, String method, String endpoint, Object parameters, String headers) {
if (isEnabled()) {
WIRE_LOGGER.trace(String.format("[%s] Sending request%n%s %s%nParameters: %s%nHeaders: %s", logId,
method.toUpperCase(), endpoint, parameters, headers));
}
}
/**
* Log an outgoing HTTP request with a request body.
*
* @param logId the correlation id, see {@link #newLogId()}.
* @param method HTTP method
* @param endpoint URI
* @param parameters optional parameters.
* @param body body content supplier.
*/
public static void logRequest(String logId, String method, String endpoint, Object parameters,
Supplier<Object> body) {
if (isEnabled()) {
WIRE_LOGGER.trace(String.format("[%s] Sending request %s %s with parameters: %s%nRequest body: %s", logId,
method.toUpperCase(), endpoint, parameters, body.get()));
}
}
/**
* Log an outgoing HTTP request with a request body.
*
* @param logId the correlation id, see {@link #newLogId()}.
* @param method HTTP method
* @param endpoint URI
* @param parameters optional parameters.
* @param headers a String containing the headers
* @param body body content supplier.
* @since 4.4
*/
public static void logRequest(String logId, String method, String endpoint, Object parameters, String headers,
Supplier<Object> body) {
if (isEnabled()) {
WIRE_LOGGER.trace(String.format("[%s] Sending request%n%s %s%nParameters: %s%nHeaders: %s%nRequest body: %s",
logId, method.toUpperCase(), endpoint, parameters, headers, body.get()));
}
}
/**
* Log a raw HTTP response without logging the body.
*
* @param logId the correlation id, see {@link #newLogId()}.
* @param statusCode the HTTP status code.
*/
public static void logRawResponse(String logId, @Nullable Integer statusCode) {
if (isEnabled()) {
WIRE_LOGGER.trace(String.format("[%s] Received raw response: %d", logId, statusCode));
}
}
/**
* Log a raw HTTP response without logging the body.
*
* @param logId the correlation id, see {@link #newLogId()}.
* @param statusCode the HTTP status code.
* @param headers a String containing the headers
*/
public static void logRawResponse(String logId, @Nullable Integer statusCode, String headers) {
if (isEnabled()) {
WIRE_LOGGER.trace(String.format("[%s] Received response: %d%n%s", logId, statusCode, headers));
}
}
/**
* Log a raw HTTP response along with the body.
*
* @param logId the correlation id, see {@link #newLogId()}.
* @param statusCode the HTTP status code.
* @param body body content.
*/
public static void logResponse(String logId, Integer statusCode, String body) {
if (isEnabled()) {
WIRE_LOGGER.trace(String.format("[%s] Received response: %d%nResponse body: %s", logId, statusCode, body));
}
}
/**
* Log a raw HTTP response along with the body.
*
* @param logId the correlation id, see {@link #newLogId()}.
* @param statusCode the HTTP status code.
* @param headers a String containing the headers
* @param body body content.
* @since 4.4
*/
public static void logResponse(String logId, @Nullable Integer statusCode, String headers, String body) {
if (isEnabled()) {
WIRE_LOGGER.trace(String.format("[%s] Received response: %d%nHeaders: %s%nResponse body: %s", logId, statusCode,
headers, body));
}
}
/**
* Creates a new, unique correlation id to improve tracing across log events.
*
* @return a new, unique correlation id.
*/
public static String newLogId() {
if (!isEnabled()) {
return "-";
}
return ObjectUtils.getIdentityHexString(new Object());
}
}

View File

@ -49,15 +49,13 @@ class DefaultClientConfiguration implements ClientConfiguration {
@Nullable private final String pathPrefix;
@Nullable private final HostnameVerifier hostnameVerifier;
@Nullable private final String proxy;
private final HttpClientConfigCallback httpClientConfigurer;
private final Supplier<HttpHeaders> headersSupplier;
private final List<ClientConfigurationCallback<?>> clientConfigurers;
DefaultClientConfiguration(List<InetSocketAddress> hosts, HttpHeaders headers, boolean useSsl,
@Nullable SSLContext sslContext, @Nullable String caFingerprint, Duration soTimeout, Duration connectTimeout,
@Nullable String pathPrefix, @Nullable HostnameVerifier hostnameVerifier, @Nullable String proxy,
HttpClientConfigCallback httpClientConfigurer, List<ClientConfigurationCallback<?>> clientConfigurers,
Supplier<HttpHeaders> headersSupplier) {
List<ClientConfigurationCallback<?>> clientConfigurers, Supplier<HttpHeaders> headersSupplier) {
this.hosts = List.copyOf(hosts);
this.headers = headers;
@ -69,7 +67,6 @@ class DefaultClientConfiguration implements ClientConfiguration {
this.pathPrefix = pathPrefix;
this.hostnameVerifier = hostnameVerifier;
this.proxy = proxy;
this.httpClientConfigurer = httpClientConfigurer;
this.clientConfigurers = clientConfigurers;
this.headersSupplier = headersSupplier;
}

View File

@ -37,7 +37,6 @@ import java.util.stream.Collectors;
import org.apache.http.*;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.entity.ContentType;
import org.apache.http.impl.nio.client.HttpAsyncClientBuilder;
import org.apache.http.message.BasicHeader;
@ -47,7 +46,6 @@ import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.springframework.data.elasticsearch.client.ClientConfiguration;
import org.springframework.data.elasticsearch.client.ClientLogger;
import org.springframework.data.elasticsearch.support.HttpHeaders;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
@ -200,13 +198,6 @@ public final class ElasticsearchClients {
clientConfiguration.getHostNameVerifier().ifPresent(clientBuilder::setSSLHostnameVerifier);
clientBuilder.addInterceptorLast(new CustomHeaderInjector(clientConfiguration.getHeadersSupplier()));
if (ClientLogger.isEnabled()) {
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
clientBuilder.addInterceptorLast((HttpRequestInterceptor) interceptor);
clientBuilder.addInterceptorLast((HttpResponseInterceptor) interceptor);
}
RequestConfig.Builder requestConfigBuilder = RequestConfig.custom();
Duration connectTimeout = clientConfiguration.getConnectTimeout();
@ -284,66 +275,6 @@ public final class ElasticsearchClients {
.toArray(org.apache.http.Header[]::new);
}
/**
* Logging interceptors for Elasticsearch client logging.
*
* @see ClientLogger
* @since 4.4
* @deprecated since 5.0
*/
@Deprecated
private static class HttpLoggingInterceptor implements HttpResponseInterceptor, HttpRequestInterceptor {
@Override
public void process(HttpRequest request, HttpContext context) throws IOException {
String logId = (String) context.getAttribute(LOG_ID_ATTRIBUTE);
if (logId == null) {
logId = ClientLogger.newLogId();
context.setAttribute(LOG_ID_ATTRIBUTE, logId);
}
String headers = Arrays.stream(request.getAllHeaders())
.map(header -> header.getName()
+ ((header.getName().equals("Authorization")) ? ": *****" : ": " + header.getValue()))
.collect(Collectors.joining(", ", "[", "]"));
if (request instanceof HttpEntityEnclosingRequest entityRequest
&& ((HttpEntityEnclosingRequest) request).getEntity() != null) {
HttpEntity entity = ((HttpEntityEnclosingRequest) request).getEntity();
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
entity.writeTo(buffer);
if (!entity.isRepeatable()) {
entityRequest.setEntity(new ByteArrayEntity(buffer.toByteArray()));
}
ClientLogger.logRequest(logId, request.getRequestLine().getMethod(), request.getRequestLine().getUri(), "",
headers, buffer::toString);
} else {
ClientLogger.logRequest(logId, request.getRequestLine().getMethod(), request.getRequestLine().getUri(), "",
headers);
}
}
@Override
public void process(HttpResponse response, HttpContext context) throws IOException {
String logId = (String) context.getAttribute(LOG_ID_ATTRIBUTE);
String headers = Arrays.stream(response.getAllHeaders())
.map(header -> header.getName()
+ ((header.getName().equals("Authorization")) ? ": *****" : ": " + header.getValue()))
.collect(Collectors.joining(", ", "[", "]"));
// no way of logging the body, in this callback, it is not read yet, later there is no callback possibility in
// RestClient or RestClientTransport
ClientLogger.logRawResponse(logId, response.getStatusLine().getStatusCode(), headers);
}
}
/**
* Interceptor to inject custom supplied headers.
*

View File

@ -65,9 +65,9 @@ import org.springframework.util.StringUtils;
/**
* This class contains methods that are common to different implementations of the {@link ElasticsearchOperations}
* interface that use different clients, like RestHighLevelClient and the next Java client from Elasticsearch or some
* external implementation that might use a different client. This class must not contain imports or use classes that
* are specific to one of these implementations.
* interface that use different clients, like the different Java clients from Elasticsearch or some external
* implementation that might use a different client. This class must not contain imports or use classes that are
* specific to one of these implementations.
* <p>
* <strong>Note:</strong> Although this class is public, it is not considered to be part of the official Spring Data
* Elasticsearch API and so might change at any time.
@ -418,8 +418,7 @@ public abstract class AbstractElasticsearchTemplate implements ElasticsearchOper
ElasticsearchPersistentProperty seqNoPrimaryTermProperty = persistentEntity.getSeqNoPrimaryTermProperty();
// noinspection ConstantConditions
propertyAccessor.setProperty(seqNoPrimaryTermProperty,
new SeqNoPrimaryTerm(indexedObjectInformation.seqNo(),
indexedObjectInformation.primaryTerm()));
new SeqNoPrimaryTerm(indexedObjectInformation.seqNo(), indexedObjectInformation.primaryTerm()));
}
if (indexedObjectInformation.version() != null && persistentEntity.hasVersionProperty()) {

View File

@ -77,20 +77,6 @@ public interface ElasticsearchOperations extends DocumentOperations, SearchOpera
String getEntityRouting(Object entity);
// region helper
/**
* gets the String representation for an id.
*
* @param id
* @return String representation
* @since 4.0
* @deprecated since 5.0, use {@link ElasticsearchOperations#convertId(Object)}.
*/
@Deprecated
@Nullable
default String stringIdRepresentation(@Nullable Object id) {
return Objects.toString(id, null);
}
/**
* Converts an idValue to a String representation. The default implementation calls
* {@link ElasticsearchConverter#convertId(Object)}

View File

@ -1,439 +0,0 @@
/*
* Copyright 2021-2023 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;
import java.util.Optional;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
/**
* Simple value object to work with ranges and boundaries.
*
* @author Sascha Woo
* @since 4.3
* @deprecated use {org.springframework.data.domain.Range} instead.
*/
@Deprecated(since = "5.0", forRemoval = true)
public class Range<T> {
private final static Range<?> UNBOUNDED = Range.of(Bound.unbounded(), Bound.UNBOUNDED);
/**
* The lower bound of the range.
*/
private final Bound<T> lowerBound;
/**
* The upper bound of the range.
*/
private final Bound<T> upperBound;
/**
* Creates a new {@link Range} with inclusive bounds for both values.
*
* @param <T>
* @param from must not be {@literal null}.
* @param to must not be {@literal null}.
* @return
*/
public static <T> Range<T> closed(T from, T to) {
return new Range<>(Bound.inclusive(from), Bound.inclusive(to));
}
/**
* Creates a new Range with the given value as sole member.
*
* @param <T>
* @param value must not be {@literal null}.
* @return
* @see Range#closed(Object, Object)
*/
public static <T> Range<T> just(T value) {
return Range.closed(value, value);
}
/**
* Creates a new left-open {@link Range}, i.e. left exclusive, right inclusive.
*
* @param <T>
* @param from must not be {@literal null}.
* @param to must not be {@literal null}.
* @return
*/
public static <T> Range<T> leftOpen(T from, T to) {
return new Range<>(Bound.exclusive(from), Bound.inclusive(to));
}
/**
* Creates a left-unbounded {@link Range} (the left bound set to {@link Bound#unbounded()}) with the given right
* bound.
*
* @param <T>
* @param to the right {@link Bound}, must not be {@literal null}.
* @return
*/
public static <T> Range<T> leftUnbounded(Bound<T> to) {
return new Range<>(Bound.unbounded(), to);
}
/**
* Creates a new {@link Range} with the given lower and upper bound.
*
* @param lowerBound must not be {@literal null}.
* @param upperBound must not be {@literal null}.
*/
public static <T> Range<T> of(Bound<T> lowerBound, Bound<T> upperBound) {
return new Range<>(lowerBound, upperBound);
}
/**
* Creates a new {@link Range} with exclusive bounds for both values.
*
* @param <T>
* @param from must not be {@literal null}.
* @param to must not be {@literal null}.
* @return
*/
public static <T> Range<T> open(T from, T to) {
return new Range<>(Bound.exclusive(from), Bound.exclusive(to));
}
/**
* Creates a new right-open {@link Range}, i.e. left inclusive, right exclusive.
*
* @param <T>
* @param from must not be {@literal null}.
* @param to must not be {@literal null}.
* @return
*/
public static <T> Range<T> rightOpen(T from, T to) {
return new Range<>(Bound.inclusive(from), Bound.exclusive(to));
}
/**
* Creates a right-unbounded {@link Range} (the right bound set to {@link Bound#unbounded()}) with the given left
* bound.
*
* @param <T>
* @param from the left {@link Bound}, must not be {@literal null}.
* @return
*/
public static <T> Range<T> rightUnbounded(Bound<T> from) {
return new Range<>(from, Bound.unbounded());
}
/**
* Returns an unbounded {@link Range}.
*
* @return
*/
@SuppressWarnings("unchecked")
public static <T> Range<T> unbounded() {
return (Range<T>) UNBOUNDED;
}
private Range(Bound<T> lowerBound, Bound<T> upperBound) {
Assert.notNull(lowerBound, "Lower bound must not be null!");
Assert.notNull(upperBound, "Upper bound must not be null!");
this.lowerBound = lowerBound;
this.upperBound = upperBound;
}
/**
* Returns whether the {@link Range} contains the given value.
*
* @param value must not be {@literal null}.
* @return
*/
@SuppressWarnings("unchecked")
public boolean contains(T value) {
Assert.notNull(value, "Reference value must not be null!");
Assert.isInstanceOf(Comparable.class, value, "value must implements Comparable!");
boolean greaterThanLowerBound = lowerBound.getValue() //
.map(it -> lowerBound.isInclusive() ? ((Comparable<? super T>) it).compareTo(value) <= 0
: ((Comparable<? super T>) it).compareTo(value) < 0) //
.orElse(true);
boolean lessThanUpperBound = upperBound.getValue() //
.map(it -> upperBound.isInclusive() ? ((Comparable<? super T>) it).compareTo(value) >= 0
: ((Comparable<? super T>) it).compareTo(value) > 0) //
.orElse(true);
return greaterThanLowerBound && lessThanUpperBound;
}
/*
* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof Range<?> range)) {
return false;
}
if (!ObjectUtils.nullSafeEquals(lowerBound, range.lowerBound)) {
return false;
}
return ObjectUtils.nullSafeEquals(upperBound, range.upperBound);
}
public Range.Bound<T> getLowerBound() {
return this.lowerBound;
}
public Range.Bound<T> getUpperBound() {
return this.upperBound;
}
/*
* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
int result = ObjectUtils.nullSafeHashCode(lowerBound);
result = 31 * result + ObjectUtils.nullSafeHashCode(upperBound);
return result;
}
/*
* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return String.format("%s-%s", lowerBound.toPrefixString(), upperBound.toSuffixString());
}
/**
* Value object representing a boundary. A boundary can either be {@link #unbounded() unbounded},
* {@link #inclusive(Object)} including its value} or {@link #exclusive(Object)} its value}.
*/
public static final class Bound<T> {
@SuppressWarnings({ "rawtypes", "unchecked" }) //
private static final Bound<?> UNBOUNDED = new Bound(Optional.empty(), true);
@SuppressWarnings("OptionalUsedAsFieldOrParameterType") private final Optional<T> value;
private final boolean inclusive;
/**
* Creates a boundary excluding {@code value}.
*
* @param value must not be {@literal null}.
* @return
*/
public static Bound<Double> exclusive(double value) {
return exclusive((Double) value);
}
/**
* Creates a boundary excluding {@code value}.
*
* @param value must not be {@literal null}.
* @return
*/
public static Bound<Float> exclusive(float value) {
return exclusive((Float) value);
}
/**
* Creates a boundary excluding {@code value}.
*
* @param value must not be {@literal null}.
* @return
*/
public static Bound<Integer> exclusive(int value) {
return exclusive((Integer) value);
}
/**
* Creates a boundary excluding {@code value}.
*
* @param value must not be {@literal null}.
* @return
*/
public static Bound<Long> exclusive(long value) {
return exclusive((Long) value);
}
/**
* Creates a boundary excluding {@code value}.
*
* @param value must not be {@literal null}.
* @return
*/
public static <T> Bound<T> exclusive(T value) {
Assert.notNull(value, "Value must not be null!");
Assert.isInstanceOf(Comparable.class, value, "value must implements Comparable!");
return new Bound<>(Optional.of(value), false);
}
/**
* Creates a boundary including {@code value}.
*
* @param value must not be {@literal null}.
* @return
*/
public static Bound<Double> inclusive(double value) {
return inclusive((Double) value);
}
/**
* Creates a boundary including {@code value}.
*
* @param value must not be {@literal null}.
* @return
*/
public static Bound<Float> inclusive(float value) {
return inclusive((Float) value);
}
/**
* Creates a boundary including {@code value}.
*
* @param value must not be {@literal null}.
* @return
*/
public static Bound<Integer> inclusive(int value) {
return inclusive((Integer) value);
}
/**
* Creates a boundary including {@code value}.
*
* @param value must not be {@literal null}.
* @return
*/
public static Bound<Long> inclusive(long value) {
return inclusive((Long) value);
}
/**
* Creates a boundary including {@code value}.
*
* @param value must not be {@literal null}.
* @return
*/
public static <T> Bound<T> inclusive(T value) {
Assert.notNull(value, "Value must not be null!");
Assert.isInstanceOf(Comparable.class, value, "value must implements Comparable!");
return new Bound<>(Optional.of(value), true);
}
/**
* Creates an unbounded {@link Bound}.
*/
@SuppressWarnings("unchecked")
public static <T> Bound<T> unbounded() {
return (Bound<T>) UNBOUNDED;
}
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
private Bound(Optional<T> value, boolean inclusive) {
this.value = value;
this.inclusive = inclusive;
}
/*
* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof Bound<?> bound)) {
return false;
}
if (inclusive != bound.inclusive)
return false;
return ObjectUtils.nullSafeEquals(value, bound.value);
}
public Optional<T> getValue() {
return this.value;
}
/*
* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
int result = ObjectUtils.nullSafeHashCode(value);
result = 31 * result + (inclusive ? 1 : 0);
return result;
}
/**
* Returns whether this boundary is bounded.
*
* @return
*/
public boolean isBounded() {
return value.isPresent();
}
public boolean isInclusive() {
return this.inclusive;
}
/*
* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return value.map(Object::toString).orElse("unbounded");
}
String toPrefixString() {
return getValue() //
.map(Object::toString) //
.map(it -> isInclusive() ? "[".concat(it) : "(".concat(it)) //
.orElse("unbounded");
}
String toSuffixString() {
return getValue() //
.map(Object::toString) //
.map(it -> isInclusive() ? it.concat("]") : it.concat(")")) //
.orElse("unbounded");
}
}
}

View File

@ -76,7 +76,6 @@ public class MappingBuilder {
private static final String FIELD_INDEX = "index";
private static final String FIELD_PROPERTIES = "properties";
@Deprecated private static final String FIELD_PARENT = "_parent";
private static final String FIELD_CONTEXT_NAME = "name";
private static final String FIELD_CONTEXT_TYPE = "type";
private static final String FIELD_CONTEXT_PATH = "path";
@ -279,7 +278,7 @@ public class MappingBuilder {
if (property.isSeqNoPrimaryTermProperty()) {
if (property.isAnnotationPresent(Field.class)) {
LOGGER.warn(String.format("Property %s of %s is annotated for inclusion in mapping, but its type is " + //
"SeqNoPrimaryTerm that is never mapped, so it is skipped", //
"SeqNoPrimaryTerm that is never mapped, so it is skipped", //
property.getFieldName(), entity.getType()));
}
return;

View File

@ -20,8 +20,7 @@ import java.util.Arrays;
import org.springframework.util.Assert;
/**
* Immutable Value object encapsulating index name(s) and index type(s). Type names are supported but deprecated as
* Elasticsearch does not support types anymore.
* Immutable Value object encapsulating index name(s) and index type(s).
*
* @author Mark Paluch
* @author Christoph Strobl

View File

@ -32,8 +32,6 @@ public class IndexQuery {
@Nullable private Object object;
@Nullable private Long version;
@Nullable private String source;
@Deprecated
@Nullable private String parentId;
@Nullable private Long seqNo;
@Nullable private Long primaryTerm;
@Nullable private String routing;
@ -43,13 +41,12 @@ public class IndexQuery {
public IndexQuery() {}
public IndexQuery(@Nullable String id, @Nullable Object object, @Nullable Long version, @Nullable String source,
@Nullable String parentId, @Nullable Long seqNo, @Nullable Long primaryTerm, @Nullable String routing,
@Nullable OpType opType, @Nullable String indexName) {
@Nullable Long seqNo, @Nullable Long primaryTerm, @Nullable String routing, @Nullable OpType opType,
@Nullable String indexName) {
this.id = id;
this.object = object;
this.version = version;
this.source = source;
this.parentId = parentId;
this.seqNo = seqNo;
this.primaryTerm = primaryTerm;
this.routing = routing;
@ -93,25 +90,6 @@ public class IndexQuery {
this.source = source;
}
/**
* @deprecated from 4.0. Elasticsearch 7 does not support the parent id in an index request. parent/child relations
* must be modeled using the join datatype. Setting it here will have no effect.
*/
@Nullable
@Deprecated
public String getParentId() {
return parentId;
}
/**
* @deprecated from 4.0. Elasticsearch 7 does not support the parent id in an index request. parent/child relations
* must be modeled using the join datatype. Setting it here will have no effect.
*/
@Deprecated
public void setParentId(String parentId) {
this.parentId = parentId;
}
@Nullable
public Long getSeqNo() {
return seqNo;

View File

@ -33,8 +33,6 @@ public class IndexQueryBuilder {
@Nullable private Object object;
@Nullable private Long version;
@Nullable private String source;
@Deprecated
@Nullable private String parentId;
@Nullable private Long seqNo;
@Nullable private Long primaryTerm;
@Nullable private String routing;
@ -64,12 +62,6 @@ public class IndexQueryBuilder {
return this;
}
@Deprecated
public IndexQueryBuilder withParentId(String parentId) {
this.parentId = parentId;
return this;
}
public IndexQueryBuilder withSeqNoPrimaryTerm(SeqNoPrimaryTerm seqNoPrimaryTerm) {
this.seqNo = seqNoPrimaryTerm.sequenceNumber();
this.primaryTerm = seqNoPrimaryTerm.primaryTerm();
@ -90,7 +82,7 @@ public class IndexQueryBuilder {
}
public IndexQuery build() {
return new IndexQuery(id, object, version, source, parentId, seqNo, primaryTerm, routing, opType, indexName);
return new IndexQuery(id, object, version, source, seqNo, primaryTerm, routing, opType, indexName);
}
/**

View File

@ -2921,7 +2921,7 @@ public abstract class ElasticsearchIntegrationTests {
List<Object> sortValues = searchHit.getSortValues();
assertThat(sortValues).hasSize(2);
assertThat(sortValues.get(0)).isInstanceOf(String.class).isEqualTo("thousands");
// transport client returns Long, RestHighlevelClient Integer, new ElasticsearchClient String
// different Java clients return this in different types
java.lang.Object o = sortValues.get(1);
if (o instanceof Integer i) {
assertThat(o).isInstanceOf(Integer.class).isEqualTo(1000);

View File

@ -1,148 +0,0 @@
/*
* Copyright 2021-2023 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;
import static org.assertj.core.api.Assertions.*;
import java.time.LocalDate;
import java.util.Collections;
import org.junit.jupiter.api.Test;
/**
* @author Sascha Woo
* @since 4.3
*/
@Deprecated(since = "5.0", forRemoval = true)
public class RangeUnitTests {
@Test
public void shouldContainsLocalDate() {
assertThat(Range.open(LocalDate.of(2021, 1, 1), LocalDate.of(2021, 2, 1)).contains(LocalDate.of(2021, 1, 10)))
.isTrue();
}
@Test
public void shouldEqualToSameRange() {
Range<LocalDate> range1 = Range.open(LocalDate.of(2021, 1, 1), LocalDate.of(2021, 2, 1));
Range<LocalDate> range2 = Range.open(LocalDate.of(2021, 1, 1), LocalDate.of(2021, 2, 1));
assertThat(range1).isEqualTo(range2);
}
@Test
public void shouldHaveClosedBoundaries() {
Range<Integer> range = Range.closed(1, 3);
assertThat(range.contains(1)).isTrue();
assertThat(range.contains(2)).isTrue();
assertThat(range.contains(3)).isTrue();
}
@Test
public void shouldHaveJustOneValue() {
Range<Integer> range = Range.just(2);
assertThat(range.contains(1)).isFalse();
assertThat(range.contains(2)).isTrue();
assertThat(range.contains(3)).isFalse();
}
@Test
public void shouldHaveLeftOpenBoundary() {
Range<Integer> range = Range.leftOpen(1, 3);
assertThat(range.contains(1)).isFalse();
assertThat(range.contains(2)).isTrue();
assertThat(range.contains(3)).isTrue();
}
@Test
public void shouldHaveLeftUnboundedAndRightExclusive() {
Range<Integer> range = Range.leftUnbounded(Range.Bound.exclusive(3));
assertThat(range.contains(0)).isTrue();
assertThat(range.contains(1)).isTrue();
assertThat(range.contains(2)).isTrue();
assertThat(range.contains(3)).isFalse();
}
@Test
public void shouldHaveLeftUnboundedAndRightInclusive() {
Range<Integer> range = Range.leftUnbounded(Range.Bound.inclusive(3));
assertThat(range.contains(0)).isTrue();
assertThat(range.contains(1)).isTrue();
assertThat(range.contains(2)).isTrue();
assertThat(range.contains(3)).isTrue();
}
@Test
public void shouldHaveOpenBoundaries() {
Range<Integer> range = Range.open(1, 3);
assertThat(range.contains(1)).isFalse();
assertThat(range.contains(2)).isTrue();
assertThat(range.contains(3)).isFalse();
}
@Test
public void shouldHaveRightOpenBoundary() {
Range<Integer> range = Range.rightOpen(1, 3);
assertThat(range.contains(1)).isTrue();
assertThat(range.contains(2)).isTrue();
assertThat(range.contains(3)).isFalse();
}
@Test
public void shouldHaveRightUnboundedAndLeftExclusive() {
Range<Integer> range = Range.rightUnbounded(Range.Bound.exclusive(1));
assertThat(range.contains(1)).isFalse();
assertThat(range.contains(2)).isTrue();
assertThat(range.contains(3)).isTrue();
assertThat(range.contains(4)).isTrue();
}
@Test
public void shouldHaveRightUnboundedAndLeftInclusive() {
Range<Integer> range = Range.rightUnbounded(Range.Bound.inclusive(1));
assertThat(range.contains(1)).isTrue();
assertThat(range.contains(2)).isTrue();
assertThat(range.contains(3)).isTrue();
assertThat(range.contains(4)).isTrue();
}
@Test
public void shouldThrowExceptionIfNotComparable() {
assertThatThrownBy(() -> Range.just(Collections.singletonList("test"))).isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining("value must implements Comparable!");
}
}