diff --git a/pom.xml b/pom.xml index 0e86eeac1..680fc0a98 100644 --- a/pom.xml +++ b/pom.xml @@ -21,15 +21,15 @@ 3.0.0-SNAPSHOT - 7.17.5 + 7.17.6 - 8.3.3 + 8.4.2 2.18.0 4.1.65.Final 1.0.6.RELEASE - 0.14.2 + 0.14.3 1.5.1 1.17.3 2.33.2 diff --git a/src/main/asciidoc/preface.adoc b/src/main/asciidoc/preface.adoc index 0ae5addd8..675c6f058 100644 --- a/src/main/asciidoc/preface.adoc +++ b/src/main/asciidoc/preface.adoc @@ -37,7 +37,7 @@ built and tested. [cols="^,^,^,^,^",options="header"] |=== | Spring Data Release Train | Spring Data Elasticsearch | Elasticsearch | Spring Framework | Spring Boot -| 2022.0 (Turing) | 5.0.x | 8.3.3 | 6.0.x | 3.0.x? +| 2022.0 (Turing) | 5.0.x | 8.4.2 | 6.0.x | 3.0.x? | 2021.2 (Raj) | 4.4.x | 7.17.3 | 5.3.x | 2.7.x | 2021.1 (Q) | 4.3.x | 7.15.2 | 5.3.x | 2.6.x | 2021.0 (Pascal) | 4.2.xfootnote:oom[Out of maintenance] | 7.12.0 | 5.3.x | 2.5.x diff --git a/src/main/asciidoc/reference/elasticsearch-migration-guide-4.4-5.0.adoc b/src/main/asciidoc/reference/elasticsearch-migration-guide-4.4-5.0.adoc index 9485ffbe9..322e9f636 100644 --- a/src/main/asciidoc/reference/elasticsearch-migration-guide-4.4-5.0.adoc +++ b/src/main/asciidoc/reference/elasticsearch-migration-guide-4.4-5.0.adoc @@ -57,18 +57,18 @@ The following classes have been converted to `Record`, you might need to adjust === New HttpHeaders class -Until version 4.4 the client configuration used the `HttpHeaders` class from the `org.springframework:spring-web` +Until version 4.4 the client configuration used the `HttpHeaders` class from the `org.springframework:spring-web` project. This introduces a dependency on that artifact. Users that do not use spring-web then face an error as this class cannot be found. In version 5.0 we introduce our own `HttpHeaders` to configure the clients. -So if you are using headers in the client configuration, you need to replace `org.springframework.http.HttpHeaders` -with `org.springframework.data.elasticsearch.support.HttpHeaders`. +So if you are using headers in the client configuration, you need to replace `org.springframework.http.HttpHeaders` +with `org.springframework.data.elasticsearch.support.HttpHeaders`. Hint: You can pass a `org.springframework.http -.HttpHeaders` to the `addAll()` method of `org.springframework.data.elasticsearch.support.HttpHeaders`. +.HttpHeaders` to the `addAll()` method of `org.springframework.data.elasticsearch.support.HttpHeaders`. [[elasticsearch-migration-guide-4.4-5.0.new-clients]] == New Elasticsearch client @@ -151,4 +151,4 @@ The old deprecated `RestHighLevelClient` can still be used, but you will need to ---- ==== -Make sure to specify the version 7.17.5 explicitly, otherwise maven will resolve to 8.3.3, and this does not exist. +Make sure to specify the version 7.17.6 explicitly, otherwise maven will resolve to 8.4.2, and this does not exist. diff --git a/src/main/java/org/springframework/data/elasticsearch/client/elc/ElasticsearchClients.java b/src/main/java/org/springframework/data/elasticsearch/client/elc/ElasticsearchClients.java index 24cc1da79..30da6a4a6 100644 --- a/src/main/java/org/springframework/data/elasticsearch/client/elc/ElasticsearchClients.java +++ b/src/main/java/org/springframework/data/elasticsearch/client/elc/ElasticsearchClients.java @@ -29,6 +29,7 @@ import java.net.InetSocketAddress; import java.time.Duration; import java.util.Arrays; import java.util.List; +import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Supplier; import java.util.stream.Collectors; @@ -250,23 +251,26 @@ public final class ElasticsearchClients { TransportOptions.Builder transportOptionsBuilder = transportOptions != null ? transportOptions.toBuilder() : new RestClientOptions(RequestOptions.DEFAULT).toBuilder(); - // need to add the compatibility header, this is only done automatically when not passing in custom options. - // code copied from RestClientTransport as it is not available outside the package - ContentType jsonContentType = null; - if (Version.VERSION == null) { - jsonContentType = ContentType.APPLICATION_JSON; - } else { - jsonContentType = ContentType.create("application/vnd.elasticsearch+json", - new BasicNameValuePair("compatible-with", String.valueOf(Version.VERSION.major()))); - } - transportOptionsBuilder.addHeader("Accept", jsonContentType.toString()); + ContentType jsonContentType = Version.VERSION == null ? ContentType.APPLICATION_JSON + : ContentType.create("application/vnd.elasticsearch+json", + new BasicNameValuePair("compatible-with", String.valueOf(Version.VERSION.major()))); + + Consumer setHeaderIfNotPresent = header -> { + if (transportOptionsBuilder.build().headers().stream() // + .noneMatch((h) -> h.getKey().equalsIgnoreCase(header))) { + // need to add the compatibility header, this is only done automatically when not passing in custom options. + // code copied from RestClientTransport as it is not available outside the package + transportOptionsBuilder.addHeader(header, jsonContentType.toString()); + } + }; + + setHeaderIfNotPresent.accept("Content-Type"); + setHeaderIfNotPresent.accept("Accept"); TransportOptions transportOptionsWithHeader = transportOptionsBuilder .addHeader(X_SPRING_DATA_ELASTICSEARCH_CLIENT, clientType).build(); - ElasticsearchTransport transport = new RestClientTransport(restClient, new JacksonJsonpMapper(), - transportOptionsWithHeader); - return transport; + return new RestClientTransport(restClient, new JacksonJsonpMapper(), transportOptionsWithHeader); } private static List formattedHosts(List hosts, boolean useSsl) { @@ -333,7 +337,7 @@ public final class ElasticsearchClients { + ((header.getName().equals("Authorization")) ? ": *****" : ": " + header.getValue())) .collect(Collectors.joining(", ", "[", "]")); - // no way of logging the body, in this callback, it is not read yset, later there is no callback possibility in + // 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); } diff --git a/src/main/java/org/springframework/data/elasticsearch/client/elc/RequestConverter.java b/src/main/java/org/springframework/data/elasticsearch/client/elc/RequestConverter.java index e8b674faa..82dc30400 100644 --- a/src/main/java/org/springframework/data/elasticsearch/client/elc/RequestConverter.java +++ b/src/main/java/org/springframework/data/elasticsearch/client/elc/RequestConverter.java @@ -808,7 +808,7 @@ class RequestConverter { .maxDocs(reindexRequest.getMaxDocs()).waitForCompletion(waitForCompletion) // .refresh(reindexRequest.getRefresh()) // .requireAlias(reindexRequest.getRequireAlias()) // - .requestsPerSecond(reindexRequest.getRequestsPerSecond()) // + .requestsPerSecond(toFloat(reindexRequest.getRequestsPerSecond())) // .slices(slices(reindexRequest.getSlices())); return builder.build(); @@ -948,8 +948,7 @@ class RequestConverter { .script(getScript(updateQuery.getScriptData())) // .maxDocs(updateQuery.getMaxDocs() != null ? Long.valueOf(updateQuery.getMaxDocs()) : null) // .pipeline(updateQuery.getPipeline()) // - .requestsPerSecond( - updateQuery.getRequestsPerSecond() != null ? updateQuery.getRequestsPerSecond().longValue() : null) // + .requestsPerSecond(updateQuery.getRequestsPerSecond()) // .slices(slices(updateQuery.getSlices() != null ? Long.valueOf(updateQuery.getSlices()) : null)); if (updateQuery.getAbortOnVersionConflict() != null) { @@ -1107,7 +1106,7 @@ class RequestConverter { query.getRescorerQueries().forEach(rescorerQuery -> bb.rescore(getRescore(rescorerQuery))); if (!query.getRuntimeFields().isEmpty()) { - Map> runtimeMappings = new HashMap<>(); + Map runtimeMappings = new HashMap<>(); query.getRuntimeFields().forEach(runtimeField -> { RuntimeField esRuntimeField = RuntimeField.of(rt -> { RuntimeField.Builder builder = rt @@ -1119,7 +1118,7 @@ class RequestConverter { } return builder; }); - runtimeMappings.put(runtimeField.getName(), Collections.singletonList(esRuntimeField)); + runtimeMappings.put(runtimeField.getName(), esRuntimeField); }); bb.runtimeMappings(runtimeMappings); } @@ -1251,12 +1250,11 @@ class RequestConverter { if (!query.getRuntimeFields().isEmpty()) { - Map> runtimeMappings = new HashMap<>(); + Map runtimeMappings = new HashMap<>(); query.getRuntimeFields() - .forEach(runtimeField -> runtimeMappings.put(runtimeField.getName(), - Collections.singletonList(RuntimeField.of(rt -> rt // - .type(RuntimeFieldType._DESERIALIZER.parse(runtimeField.getType())) // - .script(s -> s.inline(is -> is.source(runtimeField.getScript()))))))); + .forEach(runtimeField -> runtimeMappings.put(runtimeField.getName(), RuntimeField.of(rt -> rt // + .type(RuntimeFieldType._DESERIALIZER.parse(runtimeField.getType())) // + .script(s -> s.inline(is -> is.source(runtimeField.getScript())))))); builder.runtimeMappings(runtimeMappings); } diff --git a/src/main/java/org/springframework/data/elasticsearch/client/elc/ResponseConverter.java b/src/main/java/org/springframework/data/elasticsearch/client/elc/ResponseConverter.java index 67341b449..5cfbb080b 100644 --- a/src/main/java/org/springframework/data/elasticsearch/client/elc/ResponseConverter.java +++ b/src/main/java/org/springframework/data/elasticsearch/client/elc/ResponseConverter.java @@ -90,7 +90,7 @@ class ResponseConverter { .withNumberOfPendingTasks(healthResponse.numberOfPendingTasks()) // .withRelocatingShards(healthResponse.relocatingShards()) // .withStatus(healthResponse.status().toString()) // - .withTaskMaxWaitingTimeMillis(healthResponse.taskMaxWaitingInQueueMillis().toEpochMilli()) // + .withTaskMaxWaitingTimeMillis(healthResponse.taskMaxWaitingInQueueMillis()) // .withTimedOut(healthResponse.timedOut()) // .withUnassignedShards(healthResponse.unassignedShards()) // .build(); // @@ -266,7 +266,7 @@ class ResponseConverter { // noinspection ConstantConditions return ReindexResponse.builder() // - .withTook(timeToLong(reindexResponse.took())) // + .withTook(reindexResponse.took()) // .withTimedOut(reindexResponse.timedOut()) // .withTotal(reindexResponse.total()) // .withCreated(reindexResponse.created()) // @@ -277,9 +277,10 @@ class ResponseConverter { .withNoops(reindexResponse.noops()) // .withBulkRetries(reindexResponse.retries().bulk()) // .withSearchRetries(reindexResponse.retries().search()) // - .withThrottledMillis(reindexResponse.throttledMillis().toEpochMilli()) // + .withThrottledMillis(reindexResponse.throttledMillis()) // .withRequestsPerSecond(reindexResponse.requestsPerSecond()) // - .withThrottledUntilMillis(reindexResponse.throttledUntilMillis().toEpochMilli()).withFailures(failures) // + .withThrottledUntilMillis(reindexResponse.throttledUntilMillis()) // + .withFailures(failures) // .build(); } diff --git a/src/main/java/org/springframework/data/elasticsearch/client/elc/TypeUtils.java b/src/main/java/org/springframework/data/elasticsearch/client/elc/TypeUtils.java index ebf4870fb..f4d2c7741 100644 --- a/src/main/java/org/springframework/data/elasticsearch/client/elc/TypeUtils.java +++ b/src/main/java/org/springframework/data/elasticsearch/client/elc/TypeUtils.java @@ -319,4 +319,15 @@ final class TypeUtils { } } + /** + * Converts a Long to a Float, returning null if the input is null. + * + * @param value the long value + * @return a FLoat with the given value + * @since 5.0 + */ + @Nullable + static Float toFloat(@Nullable Long value) { + return value != null ? Float.valueOf(value) : null; + } } diff --git a/src/test/java/org/springframework/data/elasticsearch/client/elc/DevTests.java b/src/test/java/org/springframework/data/elasticsearch/client/elc/DevTests.java index 9ff84296a..864d03dd0 100644 --- a/src/test/java/org/springframework/data/elasticsearch/client/elc/DevTests.java +++ b/src/test/java/org/springframework/data/elasticsearch/client/elc/DevTests.java @@ -39,7 +39,6 @@ import reactor.core.publisher.Mono; import java.io.IOException; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; -import java.util.Collections; import java.util.Objects; import java.util.function.Function; @@ -108,7 +107,7 @@ public class DevTests { client.search(sr -> sr // .index(index) // - .runtimeMappings("priceWithTax", Collections.singletonList(runtimeField)), // + .runtimeMappings("priceWithTax", runtimeField), // Person.class); // } diff --git a/src/test/java/org/springframework/data/elasticsearch/repositories/cdi/ElasticsearchOperationsProducer.java b/src/test/java/org/springframework/data/elasticsearch/repositories/cdi/ElasticsearchOperationsProducer.java index e863246fa..fe47b51b0 100644 --- a/src/test/java/org/springframework/data/elasticsearch/repositories/cdi/ElasticsearchOperationsProducer.java +++ b/src/test/java/org/springframework/data/elasticsearch/repositories/cdi/ElasticsearchOperationsProducer.java @@ -68,6 +68,12 @@ class ElasticsearchOperationsProducer { configurationBuilder.withBasicAuth(user, password); } + String proxy = System.getenv("DATAES_ELASTICSEARCH_PROXY"); + + if (hasText(proxy)) { + configurationBuilder.withProxy(proxy); + } + ClientConfiguration clientConfiguration = configurationBuilder // .build(); diff --git a/src/test/java/org/springframework/data/elasticsearch/repository/query/keywords/QueryKeywordsIntegrationTests.java b/src/test/java/org/springframework/data/elasticsearch/repository/query/keywords/QueryKeywordsIntegrationTests.java index f10eed3f0..ecadcc9f4 100644 --- a/src/test/java/org/springframework/data/elasticsearch/repository/query/keywords/QueryKeywordsIntegrationTests.java +++ b/src/test/java/org/springframework/data/elasticsearch/repository/query/keywords/QueryKeywordsIntegrationTests.java @@ -23,6 +23,7 @@ import java.util.List; import java.util.stream.Collectors; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; @@ -265,6 +266,7 @@ abstract class QueryKeywordsIntegrationTests { assertThat(products).isEmpty(); } + @Disabled("issue #2300, Elasticsearch bug https://github.com/elastic/elasticsearch/issues/89760") @Test // #1909 @DisplayName("should find by property exists") void shouldFindByPropertyExists() { @@ -274,6 +276,7 @@ abstract class QueryKeywordsIntegrationTests { assertThat(searchHits.getTotalHits()).isEqualTo(6); } + @Disabled("issue #2300, Elasticsearch bug https://github.com/elastic/elasticsearch/issues/89760") @Test // #1909 @DisplayName("should find by property is not null") void shouldFindByPropertyIsNotNull() { diff --git a/src/test/resources/testcontainers-elasticsearch.properties b/src/test/resources/testcontainers-elasticsearch.properties index f20349d72..7206e596b 100644 --- a/src/test/resources/testcontainers-elasticsearch.properties +++ b/src/test/resources/testcontainers-elasticsearch.properties @@ -15,7 +15,7 @@ # # sde.testcontainers.image-name=docker.elastic.co/elasticsearch/elasticsearch -sde.testcontainers.image-version=8.3.3 +sde.testcontainers.image-version=8.4.2 # # # needed as we do a DELETE /* at the end of the tests, will be required from 8.0 on, produces a warning since 7.13