Auto-configure the new Elasticsearch clients
This commit introduces auto-configuration for the new Elasticsearch clients that are based upon their new Java client. The new Java client builds on top of their existing low-level REST client, replacing the high-level REST client which has been deprecated. As part of introducing support for the new Elasticsearch client, the auto-configuration for the templates (both imperative and reactive) provided by Spring Data has also been updated to use the new templates that build upon the new Java client. As part of these changes, support for the high-level REST client and the old Spring Data Elasticsearch templates has been removed. One significant change is that the new reactive template is no longer based on WebClient. As a result, the WebClient-specific configuration property has been removed. Closes gh-30647 Closes gh-28597 Closes gh-31755
This commit is contained in:
parent
f9ccfc1e12
commit
5c057a2730
|
@ -103,7 +103,6 @@ dependencies {
|
||||||
optional("org.eclipse.jetty:jetty-server") {
|
optional("org.eclipse.jetty:jetty-server") {
|
||||||
exclude group: "org.eclipse.jetty.toolchain", module: "jetty-jakarta-servlet-api"
|
exclude group: "org.eclipse.jetty.toolchain", module: "jetty-jakarta-servlet-api"
|
||||||
}
|
}
|
||||||
optional("org.elasticsearch:elasticsearch")
|
|
||||||
optional("org.elasticsearch.client:elasticsearch-rest-client") {
|
optional("org.elasticsearch.client:elasticsearch-rest-client") {
|
||||||
exclude group: "commons-logging", module: "commons-logging"
|
exclude group: "commons-logging", module: "commons-logging"
|
||||||
}
|
}
|
||||||
|
@ -168,9 +167,6 @@ dependencies {
|
||||||
testImplementation("org.eclipse.jetty:jetty-webapp") {
|
testImplementation("org.eclipse.jetty:jetty-webapp") {
|
||||||
exclude group: "org.eclipse.jetty.toolchain", module: "jetty-jakarta-servlet-api"
|
exclude group: "org.eclipse.jetty.toolchain", module: "jetty-jakarta-servlet-api"
|
||||||
}
|
}
|
||||||
testImplementation("org.elasticsearch.client:elasticsearch-rest-high-level-client") {
|
|
||||||
exclude(group: "commons-logging", module: "commons-logging")
|
|
||||||
}
|
|
||||||
testImplementation("org.hamcrest:hamcrest")
|
testImplementation("org.hamcrest:hamcrest")
|
||||||
testImplementation("org.hsqldb:hsqldb")
|
testImplementation("org.hsqldb:hsqldb")
|
||||||
testImplementation("org.junit.jupiter:junit-jupiter")
|
testImplementation("org.junit.jupiter:junit-jupiter")
|
||||||
|
|
|
@ -31,7 +31,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
import org.springframework.boot.autoconfigure.elasticsearch.ReactiveElasticsearchClientAutoConfiguration;
|
import org.springframework.boot.autoconfigure.elasticsearch.ReactiveElasticsearchClientAutoConfiguration;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.data.elasticsearch.client.erhlc.ReactiveElasticsearchClient;
|
import org.springframework.data.elasticsearch.client.elc.ReactiveElasticsearchClient;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link EnableAutoConfiguration Auto-configuration} for
|
* {@link EnableAutoConfiguration Auto-configuration} for
|
||||||
|
@ -45,7 +45,7 @@ import org.springframework.data.elasticsearch.client.erhlc.ReactiveElasticsearch
|
||||||
@ConditionalOnClass({ ReactiveElasticsearchClient.class, Flux.class })
|
@ConditionalOnClass({ ReactiveElasticsearchClient.class, Flux.class })
|
||||||
@ConditionalOnBean(ReactiveElasticsearchClient.class)
|
@ConditionalOnBean(ReactiveElasticsearchClient.class)
|
||||||
@ConditionalOnEnabledHealthIndicator("elasticsearch")
|
@ConditionalOnEnabledHealthIndicator("elasticsearch")
|
||||||
public class ElasticSearchReactiveHealthContributorAutoConfiguration extends
|
public class ElasticsearchReactiveHealthContributorAutoConfiguration extends
|
||||||
CompositeReactiveHealthContributorConfiguration<ElasticsearchReactiveHealthIndicator, ReactiveElasticsearchClient> {
|
CompositeReactiveHealthContributorConfiguration<ElasticsearchReactiveHealthIndicator, ReactiveElasticsearchClient> {
|
||||||
|
|
||||||
@Bean
|
@Bean
|
|
@ -43,7 +43,7 @@ import org.springframework.context.annotation.Bean;
|
||||||
@ConditionalOnClass(RestClient.class)
|
@ConditionalOnClass(RestClient.class)
|
||||||
@ConditionalOnBean(RestClient.class)
|
@ConditionalOnBean(RestClient.class)
|
||||||
@ConditionalOnEnabledHealthIndicator("elasticsearch")
|
@ConditionalOnEnabledHealthIndicator("elasticsearch")
|
||||||
public class ElasticSearchRestHealthContributorAutoConfiguration
|
public class ElasticsearchRestHealthContributorAutoConfiguration
|
||||||
extends CompositeHealthContributorConfiguration<ElasticsearchRestClientHealthIndicator, RestClient> {
|
extends CompositeHealthContributorConfiguration<ElasticsearchRestClientHealthIndicator, RestClient> {
|
||||||
|
|
||||||
@Bean
|
@Bean
|
|
@ -14,8 +14,8 @@ org.springframework.boot.actuate.autoconfigure.context.properties.ConfigurationP
|
||||||
org.springframework.boot.actuate.autoconfigure.context.ShutdownEndpointAutoConfiguration
|
org.springframework.boot.actuate.autoconfigure.context.ShutdownEndpointAutoConfiguration
|
||||||
org.springframework.boot.actuate.autoconfigure.couchbase.CouchbaseHealthContributorAutoConfiguration
|
org.springframework.boot.actuate.autoconfigure.couchbase.CouchbaseHealthContributorAutoConfiguration
|
||||||
org.springframework.boot.actuate.autoconfigure.couchbase.CouchbaseReactiveHealthContributorAutoConfiguration
|
org.springframework.boot.actuate.autoconfigure.couchbase.CouchbaseReactiveHealthContributorAutoConfiguration
|
||||||
org.springframework.boot.actuate.autoconfigure.elasticsearch.ElasticSearchReactiveHealthContributorAutoConfiguration
|
org.springframework.boot.actuate.autoconfigure.elasticsearch.ElasticsearchReactiveHealthContributorAutoConfiguration
|
||||||
org.springframework.boot.actuate.autoconfigure.elasticsearch.ElasticSearchRestHealthContributorAutoConfiguration
|
org.springframework.boot.actuate.autoconfigure.elasticsearch.ElasticsearchRestHealthContributorAutoConfiguration
|
||||||
org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration
|
org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration
|
||||||
org.springframework.boot.actuate.autoconfigure.endpoint.jmx.JmxEndpointAutoConfiguration
|
org.springframework.boot.actuate.autoconfigure.endpoint.jmx.JmxEndpointAutoConfiguration
|
||||||
org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration
|
org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration
|
||||||
|
|
|
@ -30,7 +30,7 @@ import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for {@link ElasticSearchReactiveHealthContributorAutoConfiguration}.
|
* Tests for {@link ElasticsearchReactiveHealthContributorAutoConfiguration}.
|
||||||
*
|
*
|
||||||
* @author Aleksander Lech
|
* @author Aleksander Lech
|
||||||
*/
|
*/
|
||||||
|
@ -39,7 +39,7 @@ class ElasticsearchReactiveHealthContributorAutoConfigurationTests {
|
||||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||||
.withConfiguration(AutoConfigurations.of(ElasticsearchDataAutoConfiguration.class,
|
.withConfiguration(AutoConfigurations.of(ElasticsearchDataAutoConfiguration.class,
|
||||||
ReactiveElasticsearchClientAutoConfiguration.class, ElasticsearchRestClientAutoConfiguration.class,
|
ReactiveElasticsearchClientAutoConfiguration.class, ElasticsearchRestClientAutoConfiguration.class,
|
||||||
ElasticSearchReactiveHealthContributorAutoConfiguration.class,
|
ElasticsearchReactiveHealthContributorAutoConfiguration.class,
|
||||||
HealthContributorAutoConfiguration.class));
|
HealthContributorAutoConfiguration.class));
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -51,7 +51,7 @@ class ElasticsearchReactiveHealthContributorAutoConfigurationTests {
|
||||||
@Test
|
@Test
|
||||||
void runWithRegularIndicatorShouldOnlyCreateReactiveIndicator() {
|
void runWithRegularIndicatorShouldOnlyCreateReactiveIndicator() {
|
||||||
this.contextRunner
|
this.contextRunner
|
||||||
.withConfiguration(AutoConfigurations.of(ElasticSearchRestHealthContributorAutoConfiguration.class))
|
.withConfiguration(AutoConfigurations.of(ElasticsearchRestHealthContributorAutoConfiguration.class))
|
||||||
.run((context) -> assertThat(context).hasSingleBean(ElasticsearchReactiveHealthIndicator.class)
|
.run((context) -> assertThat(context).hasSingleBean(ElasticsearchReactiveHealthIndicator.class)
|
||||||
.hasBean("elasticsearchHealthContributor")
|
.hasBean("elasticsearchHealthContributor")
|
||||||
.doesNotHaveBean(ElasticsearchRestClientHealthIndicator.class));
|
.doesNotHaveBean(ElasticsearchRestClientHealthIndicator.class));
|
||||||
|
|
|
@ -32,16 +32,16 @@ import org.springframework.context.annotation.Configuration;
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for {@link ElasticSearchRestHealthContributorAutoConfiguration}.
|
* Tests for {@link ElasticsearchRestHealthContributorAutoConfiguration}.
|
||||||
*
|
*
|
||||||
* @author Filip Hrisafov
|
* @author Filip Hrisafov
|
||||||
* @author Andy Wilkinson
|
* @author Andy Wilkinson
|
||||||
*/
|
*/
|
||||||
class ElasticSearchRestHealthContributorAutoConfigurationTests {
|
class ElasticsearchRestHealthContributorAutoConfigurationTests {
|
||||||
|
|
||||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||||
.withConfiguration(AutoConfigurations.of(ElasticsearchRestClientAutoConfiguration.class,
|
.withConfiguration(AutoConfigurations.of(ElasticsearchRestClientAutoConfiguration.class,
|
||||||
ElasticSearchRestHealthContributorAutoConfiguration.class,
|
ElasticsearchRestHealthContributorAutoConfiguration.class,
|
||||||
HealthContributorAutoConfiguration.class));
|
HealthContributorAutoConfiguration.class));
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -51,29 +51,19 @@ class ElasticSearchRestHealthContributorAutoConfigurationTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@SuppressWarnings("deprecation")
|
void runWithoutRestClientShouldNotCreateIndicator() {
|
||||||
void runWithoutRestHighLevelClientAndWithoutRestClientShouldNotCreateIndicator() {
|
this.contextRunner.withClassLoader(new FilteredClassLoader(RestClient.class))
|
||||||
this.contextRunner
|
|
||||||
.withClassLoader(
|
|
||||||
new FilteredClassLoader(org.elasticsearch.client.RestHighLevelClient.class, RestClient.class))
|
|
||||||
.run((context) -> assertThat(context).doesNotHaveBean(ElasticsearchRestClientHealthIndicator.class)
|
.run((context) -> assertThat(context).doesNotHaveBean(ElasticsearchRestClientHealthIndicator.class)
|
||||||
.doesNotHaveBean("elasticsearchHealthContributor"));
|
.doesNotHaveBean("elasticsearchHealthContributor"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void runWithoutRestHighLevelClientAndWithRestClientShouldCreateIndicator() {
|
void runWithRestClientShouldCreateIndicator() {
|
||||||
this.contextRunner.withUserConfiguration(CustomRestClientConfiguration.class)
|
this.contextRunner.withUserConfiguration(CustomRestClientConfiguration.class)
|
||||||
.run((context) -> assertThat(context).hasSingleBean(ElasticsearchRestClientHealthIndicator.class)
|
.run((context) -> assertThat(context).hasSingleBean(ElasticsearchRestClientHealthIndicator.class)
|
||||||
.hasBean("elasticsearchHealthContributor"));
|
.hasBean("elasticsearchHealthContributor"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
void runWithRestHighLevelClientAndWithRestClientShouldCreateIndicator() {
|
|
||||||
this.contextRunner.withUserConfiguration(CustomRestHighClientConfiguration.class)
|
|
||||||
.run((context) -> assertThat(context).hasSingleBean(ElasticsearchRestClientHealthIndicator.class)
|
|
||||||
.hasBean("elasticsearchHealthContributor"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void runWhenDisabledShouldNotCreateIndicator() {
|
void runWhenDisabledShouldNotCreateIndicator() {
|
||||||
this.contextRunner.withPropertyValues("management.health.elasticsearch.enabled:false")
|
this.contextRunner.withPropertyValues("management.health.elasticsearch.enabled:false")
|
||||||
|
@ -91,20 +81,4 @@ class ElasticSearchRestHealthContributorAutoConfigurationTests {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Configuration(proxyBeanMethods = false)
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
static class CustomRestHighClientConfiguration {
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
org.elasticsearch.client.RestHighLevelClient customRestHighClient(RestClientBuilder builder) {
|
|
||||||
return new org.elasticsearch.client.RestHighLevelClient(builder);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
RestClient customClient(org.elasticsearch.client.RestHighLevelClient restHighLevelClient) {
|
|
||||||
return restHighLevelClient.getLowLevelClient();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -43,13 +43,9 @@ dependencies {
|
||||||
optional("org.eclipse.jetty:jetty-server") {
|
optional("org.eclipse.jetty:jetty-server") {
|
||||||
exclude(group: "org.eclipse.jetty.toolchain", module: "jetty-jakarta-servlet-api")
|
exclude(group: "org.eclipse.jetty.toolchain", module: "jetty-jakarta-servlet-api")
|
||||||
}
|
}
|
||||||
optional("org.elasticsearch:elasticsearch")
|
|
||||||
optional("org.elasticsearch.client:elasticsearch-rest-client") {
|
optional("org.elasticsearch.client:elasticsearch-rest-client") {
|
||||||
exclude(group: "commons-logging", module: "commons-logging")
|
exclude(group: "commons-logging", module: "commons-logging")
|
||||||
}
|
}
|
||||||
optional("org.elasticsearch.client:elasticsearch-rest-high-level-client") {
|
|
||||||
exclude(group: "commons-logging", module: "commons-logging")
|
|
||||||
}
|
|
||||||
optional("org.flywaydb:flyway-core")
|
optional("org.flywaydb:flyway-core")
|
||||||
optional("org.hibernate.validator:hibernate-validator")
|
optional("org.hibernate.validator:hibernate-validator")
|
||||||
optional("org.influxdb:influxdb-java")
|
optional("org.influxdb:influxdb-java")
|
||||||
|
|
|
@ -16,20 +16,15 @@
|
||||||
|
|
||||||
package org.springframework.boot.actuate.elasticsearch;
|
package org.springframework.boot.actuate.elasticsearch;
|
||||||
|
|
||||||
import java.util.Map;
|
import co.elastic.clients.elasticsearch._types.HealthStatus;
|
||||||
|
import co.elastic.clients.elasticsearch.cluster.HealthResponse;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
import org.springframework.boot.actuate.health.AbstractReactiveHealthIndicator;
|
import org.springframework.boot.actuate.health.AbstractReactiveHealthIndicator;
|
||||||
import org.springframework.boot.actuate.health.Health;
|
import org.springframework.boot.actuate.health.Health;
|
||||||
import org.springframework.boot.actuate.health.HealthIndicator;
|
import org.springframework.boot.actuate.health.HealthIndicator;
|
||||||
import org.springframework.boot.actuate.health.Status;
|
import org.springframework.boot.actuate.health.Status;
|
||||||
import org.springframework.core.ParameterizedTypeReference;
|
import org.springframework.data.elasticsearch.client.elc.ReactiveElasticsearchClient;
|
||||||
import org.springframework.data.elasticsearch.client.erhlc.ReactiveElasticsearchClient;
|
|
||||||
import org.springframework.http.HttpStatus;
|
|
||||||
import org.springframework.http.HttpStatusCode;
|
|
||||||
import org.springframework.web.reactive.function.client.ClientResponse;
|
|
||||||
import org.springframework.web.reactive.function.client.WebClient;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link HealthIndicator} for an Elasticsearch cluster using a
|
* {@link HealthIndicator} for an Elasticsearch cluster using a
|
||||||
|
@ -42,11 +37,6 @@ import org.springframework.web.reactive.function.client.WebClient;
|
||||||
*/
|
*/
|
||||||
public class ElasticsearchReactiveHealthIndicator extends AbstractReactiveHealthIndicator {
|
public class ElasticsearchReactiveHealthIndicator extends AbstractReactiveHealthIndicator {
|
||||||
|
|
||||||
private static final ParameterizedTypeReference<Map<String, Object>> STRING_OBJECT_MAP = new ParameterizedTypeReference<>() {
|
|
||||||
};
|
|
||||||
|
|
||||||
private static final String RED_STATUS = "red";
|
|
||||||
|
|
||||||
private final ReactiveElasticsearchClient client;
|
private final ReactiveElasticsearchClient client;
|
||||||
|
|
||||||
public ElasticsearchReactiveHealthIndicator(ReactiveElasticsearchClient client) {
|
public ElasticsearchReactiveHealthIndicator(ReactiveElasticsearchClient client) {
|
||||||
|
@ -56,32 +46,33 @@ public class ElasticsearchReactiveHealthIndicator extends AbstractReactiveHealth
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Mono<Health> doHealthCheck(Health.Builder builder) {
|
protected Mono<Health> doHealthCheck(Health.Builder builder) {
|
||||||
return this.client.execute((webClient) -> getHealth(builder, webClient));
|
return this.client.cluster().health((b) -> b).map((response) -> processResponse(builder, response));
|
||||||
}
|
}
|
||||||
|
|
||||||
private Mono<Health> getHealth(Health.Builder builder, WebClient webClient) {
|
private Health processResponse(Health.Builder builder, HealthResponse response) {
|
||||||
return webClient.get().uri("/_cluster/health/").exchangeToMono((response) -> doHealthCheck(builder, response));
|
if (!response.timedOut()) {
|
||||||
}
|
HealthStatus status = response.status();
|
||||||
|
builder.status((HealthStatus.Red == status) ? Status.OUT_OF_SERVICE : Status.UP);
|
||||||
private Mono<Health> doHealthCheck(Health.Builder builder, ClientResponse response) {
|
builder.withDetail("cluster_name", response.clusterName());
|
||||||
HttpStatusCode httpStatusCode = response.statusCode();
|
builder.withDetail("status", response.status().jsonValue());
|
||||||
HttpStatus httpStatus = HttpStatus.resolve(httpStatusCode.value());
|
builder.withDetail("timed_out", response.timedOut());
|
||||||
if (httpStatusCode.is2xxSuccessful()) {
|
builder.withDetail("number_of_nodes", response.numberOfNodes());
|
||||||
return response.bodyToMono(STRING_OBJECT_MAP).map((body) -> getHealth(builder, body));
|
builder.withDetail("number_of_data_nodes", response.numberOfDataNodes());
|
||||||
}
|
builder.withDetail("active_primary_shards", response.activePrimaryShards());
|
||||||
builder.down();
|
builder.withDetail("active_shards", response.activeShards());
|
||||||
builder.withDetail("statusCode", httpStatusCode.value());
|
builder.withDetail("relocating_shards", response.relocatingShards());
|
||||||
if (httpStatus != null) {
|
builder.withDetail("initializing_shards", response.initializingShards());
|
||||||
builder.withDetail("reasonPhrase", httpStatus.getReasonPhrase());
|
builder.withDetail("unassigned_shards", response.unassignedShards());
|
||||||
}
|
builder.withDetail("delayed_unassigned_shards", response.delayedUnassignedShards());
|
||||||
return response.releaseBody().thenReturn(builder.build());
|
builder.withDetail("number_of_pending_tasks", response.numberOfPendingTasks());
|
||||||
}
|
builder.withDetail("number_of_in_flight_fetch", response.numberOfInFlightFetch());
|
||||||
|
builder.withDetail("task_max_waiting_in_queue_millis",
|
||||||
private Health getHealth(Health.Builder builder, Map<String, Object> body) {
|
response.taskMaxWaitingInQueueMillis().toEpochMilli());
|
||||||
String status = (String) body.get("status");
|
builder.withDetail("active_shards_percent_as_number",
|
||||||
builder.status(RED_STATUS.equals(status) ? Status.OUT_OF_SERVICE : Status.UP);
|
Double.parseDouble(response.activeShardsPercentAsNumber()));
|
||||||
builder.withDetails(body);
|
|
||||||
return builder.build();
|
return builder.build();
|
||||||
}
|
}
|
||||||
|
return builder.down().build();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,16 +19,20 @@ package org.springframework.boot.actuate.elasticsearch;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import co.elastic.clients.json.jackson.JacksonJsonpMapper;
|
||||||
|
import co.elastic.clients.transport.rest_client.RestClientTransport;
|
||||||
import okhttp3.mockwebserver.MockResponse;
|
import okhttp3.mockwebserver.MockResponse;
|
||||||
import okhttp3.mockwebserver.MockWebServer;
|
import okhttp3.mockwebserver.MockWebServer;
|
||||||
|
import org.apache.http.HttpHost;
|
||||||
|
import org.elasticsearch.client.ResponseException;
|
||||||
|
import org.elasticsearch.client.RestClient;
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import org.springframework.boot.actuate.health.Health;
|
import org.springframework.boot.actuate.health.Health;
|
||||||
import org.springframework.boot.actuate.health.Status;
|
import org.springframework.boot.actuate.health.Status;
|
||||||
import org.springframework.data.elasticsearch.client.ClientConfiguration;
|
import org.springframework.data.elasticsearch.client.elc.ReactiveElasticsearchClient;
|
||||||
import org.springframework.data.elasticsearch.client.erhlc.ReactiveElasticsearchClient;
|
|
||||||
import org.springframework.http.HttpHeaders;
|
import org.springframework.http.HttpHeaders;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
|
@ -50,13 +54,13 @@ class ElasticsearchReactiveHealthIndicatorTests {
|
||||||
|
|
||||||
private ElasticsearchReactiveHealthIndicator healthIndicator;
|
private ElasticsearchReactiveHealthIndicator healthIndicator;
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
void setup() throws Exception {
|
void setup() throws Exception {
|
||||||
this.server = new MockWebServer();
|
this.server = new MockWebServer();
|
||||||
this.server.start();
|
this.server.start();
|
||||||
ReactiveElasticsearchClient client = org.springframework.data.elasticsearch.client.erhlc.DefaultReactiveElasticsearchClient
|
ReactiveElasticsearchClient client = new ReactiveElasticsearchClient(new RestClientTransport(
|
||||||
.create(ClientConfiguration.create(this.server.getHostName() + ":" + this.server.getPort()));
|
RestClient.builder(HttpHost.create(this.server.getHostName() + ":" + this.server.getPort())).build(),
|
||||||
|
new JacksonJsonpMapper()));
|
||||||
this.healthIndicator = new ElasticsearchReactiveHealthIndicator(client);
|
this.healthIndicator = new ElasticsearchReactiveHealthIndicator(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,20 +90,15 @@ class ElasticsearchReactiveHealthIndicatorTests {
|
||||||
this.server.shutdown();
|
this.server.shutdown();
|
||||||
Health health = this.healthIndicator.health().block(TIMEOUT);
|
Health health = this.healthIndicator.health().block(TIMEOUT);
|
||||||
assertThat(health.getStatus()).isEqualTo(Status.DOWN);
|
assertThat(health.getStatus()).isEqualTo(Status.DOWN);
|
||||||
assertThat(health.getDetails().get("error")).asString()
|
assertThat(health.getDetails().get("error")).asString().contains("Connection refused");
|
||||||
.contains("org.springframework.data.elasticsearch.client.NoReachableHostException");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void elasticsearchIsDownByResponseCode() {
|
void elasticsearchIsDownByResponseCode() {
|
||||||
// first enqueue an OK response since the HostChecker first sends a HEAD request
|
|
||||||
// to "/"
|
|
||||||
this.server.enqueue(new MockResponse().setResponseCode(HttpStatus.OK.value()));
|
|
||||||
this.server.enqueue(new MockResponse().setResponseCode(HttpStatus.INTERNAL_SERVER_ERROR.value()));
|
this.server.enqueue(new MockResponse().setResponseCode(HttpStatus.INTERNAL_SERVER_ERROR.value()));
|
||||||
Health health = this.healthIndicator.health().block(TIMEOUT);
|
Health health = this.healthIndicator.health().block(TIMEOUT);
|
||||||
assertThat(health.getStatus()).isEqualTo(Status.DOWN);
|
assertThat(health.getStatus()).isEqualTo(Status.DOWN);
|
||||||
assertThat(health.getDetails().get("statusCode")).asString().isEqualTo("500");
|
assertThat(health.getDetails().get("error")).asString().startsWith(ResponseException.class.getName());
|
||||||
assertThat(health.getDetails().get("reasonPhrase")).asString().isEqualTo("Internal Server Error");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -116,24 +115,19 @@ class ElasticsearchReactiveHealthIndicatorTests {
|
||||||
entry("active_primary_shards", 0), entry("active_shards", 0), entry("relocating_shards", 0),
|
entry("active_primary_shards", 0), entry("active_shards", 0), entry("relocating_shards", 0),
|
||||||
entry("initializing_shards", 0), entry("unassigned_shards", 0), entry("delayed_unassigned_shards", 0),
|
entry("initializing_shards", 0), entry("unassigned_shards", 0), entry("delayed_unassigned_shards", 0),
|
||||||
entry("number_of_pending_tasks", 0), entry("number_of_in_flight_fetch", 0),
|
entry("number_of_pending_tasks", 0), entry("number_of_in_flight_fetch", 0),
|
||||||
entry("task_max_waiting_in_queue_millis", 0), entry("active_shards_percent_as_number", 100.0));
|
entry("task_max_waiting_in_queue_millis", 0L), entry("active_shards_percent_as_number", 100.0));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupMockResponse(int responseCode, String status) {
|
private void setupMockResponse(int responseCode, String status) {
|
||||||
// first enqueue an OK response since the HostChecker first sends a HEAD request
|
MockResponse mockResponse = new MockResponse().setBody(createJsonResult(status))
|
||||||
// to "/"
|
.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
|
||||||
this.server.enqueue(new MockResponse());
|
.setHeader("X-Elastic-Product", "Elasticsearch");
|
||||||
MockResponse mockResponse = new MockResponse().setResponseCode(HttpStatus.valueOf(responseCode).value())
|
|
||||||
.setBody(createJsonResult(responseCode, status))
|
|
||||||
.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
|
|
||||||
this.server.enqueue(mockResponse);
|
this.server.enqueue(mockResponse);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String createJsonResult(int responseCode, String status) {
|
private String createJsonResult(String status) {
|
||||||
if (responseCode == 200) {
|
|
||||||
return String.format(
|
return String.format(
|
||||||
"{\"cluster_name\":\"elasticsearch\","
|
"{\"cluster_name\":\"elasticsearch\"," + "\"status\":\"%s\",\"timed_out\":false,\"number_of_nodes\":1,"
|
||||||
+ "\"status\":\"%s\",\"timed_out\":false,\"number_of_nodes\":1,"
|
|
||||||
+ "\"number_of_data_nodes\":1,\"active_primary_shards\":0,"
|
+ "\"number_of_data_nodes\":1,\"active_primary_shards\":0,"
|
||||||
+ "\"active_shards\":0,\"relocating_shards\":0,\"initializing_shards\":0,"
|
+ "\"active_shards\":0,\"relocating_shards\":0,\"initializing_shards\":0,"
|
||||||
+ "\"unassigned_shards\":0,\"delayed_unassigned_shards\":0,"
|
+ "\"unassigned_shards\":0,\"delayed_unassigned_shards\":0,"
|
||||||
|
@ -141,7 +135,5 @@ class ElasticsearchReactiveHealthIndicatorTests {
|
||||||
+ "\"task_max_waiting_in_queue_millis\":0,\"active_shards_percent_as_number\":100.0}",
|
+ "\"task_max_waiting_in_queue_millis\":0,\"active_shards_percent_as_number\":100.0}",
|
||||||
status);
|
status);
|
||||||
}
|
}
|
||||||
return "{\n \"error\": \"Server Error\",\n \"status\": " + responseCode + "\n}";
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,9 @@ description = "Spring Boot AutoConfigure"
|
||||||
dependencies {
|
dependencies {
|
||||||
api(project(":spring-boot-project:spring-boot"))
|
api(project(":spring-boot-project:spring-boot"))
|
||||||
|
|
||||||
|
optional("co.elastic.clients:elasticsearch-java") {
|
||||||
|
exclude group: "commons-logging", module: "commons-logging"
|
||||||
|
}
|
||||||
optional("com.fasterxml.jackson.core:jackson-databind")
|
optional("com.fasterxml.jackson.core:jackson-databind")
|
||||||
optional("com.fasterxml.jackson.dataformat:jackson-dataformat-cbor")
|
optional("com.fasterxml.jackson.dataformat:jackson-dataformat-cbor")
|
||||||
optional("com.fasterxml.jackson.dataformat:jackson-dataformat-xml")
|
optional("com.fasterxml.jackson.dataformat:jackson-dataformat-xml")
|
||||||
|
@ -99,9 +102,6 @@ dependencies {
|
||||||
optional("org.elasticsearch.client:elasticsearch-rest-client-sniffer") {
|
optional("org.elasticsearch.client:elasticsearch-rest-client-sniffer") {
|
||||||
exclude group: "commons-logging", module: "commons-logging"
|
exclude group: "commons-logging", module: "commons-logging"
|
||||||
}
|
}
|
||||||
optional("org.elasticsearch.client:elasticsearch-rest-high-level-client") {
|
|
||||||
exclude group: "commons-logging", module: "commons-logging"
|
|
||||||
}
|
|
||||||
optional("org.flywaydb:flyway-core")
|
optional("org.flywaydb:flyway-core")
|
||||||
optional("org.flywaydb:flyway-sqlserver")
|
optional("org.flywaydb:flyway-sqlserver")
|
||||||
optional("org.freemarker:freemarker")
|
optional("org.freemarker:freemarker")
|
||||||
|
|
|
@ -19,10 +19,10 @@ package org.springframework.boot.autoconfigure.data.elasticsearch;
|
||||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||||
import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchRestClientAutoConfiguration;
|
import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchClientAutoConfiguration;
|
||||||
import org.springframework.boot.autoconfigure.elasticsearch.ReactiveElasticsearchClientAutoConfiguration;
|
import org.springframework.boot.autoconfigure.elasticsearch.ReactiveElasticsearchClientAutoConfiguration;
|
||||||
import org.springframework.context.annotation.Import;
|
import org.springframework.context.annotation.Import;
|
||||||
import org.springframework.data.elasticsearch.client.erhlc.ElasticsearchRestTemplate;
|
import org.springframework.data.elasticsearch.client.elc.ElasticsearchTemplate;
|
||||||
import org.springframework.data.elasticsearch.repository.config.EnableElasticsearchRepositories;
|
import org.springframework.data.elasticsearch.repository.config.EnableElasticsearchRepositories;
|
||||||
import org.springframework.data.elasticsearch.repository.config.EnableReactiveElasticsearchRepositories;
|
import org.springframework.data.elasticsearch.repository.config.EnableReactiveElasticsearchRepositories;
|
||||||
|
|
||||||
|
@ -38,12 +38,11 @@ import org.springframework.data.elasticsearch.repository.config.EnableReactiveEl
|
||||||
* @see EnableReactiveElasticsearchRepositories
|
* @see EnableReactiveElasticsearchRepositories
|
||||||
*/
|
*/
|
||||||
@AutoConfiguration(
|
@AutoConfiguration(
|
||||||
after = { ElasticsearchRestClientAutoConfiguration.class, ReactiveElasticsearchClientAutoConfiguration.class })
|
after = { ElasticsearchClientAutoConfiguration.class, ReactiveElasticsearchClientAutoConfiguration.class })
|
||||||
@ConditionalOnClass({ ElasticsearchRestTemplate.class })
|
@ConditionalOnClass({ ElasticsearchTemplate.class })
|
||||||
@Import({ ElasticsearchDataConfiguration.BaseConfiguration.class,
|
@Import({ ElasticsearchDataConfiguration.BaseConfiguration.class,
|
||||||
ElasticsearchDataConfiguration.RestClientConfiguration.class,
|
ElasticsearchDataConfiguration.JavaClientConfiguration.class,
|
||||||
ElasticsearchDataConfiguration.ReactiveRestClientConfiguration.class })
|
ElasticsearchDataConfiguration.ReactiveRestClientConfiguration.class })
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
public class ElasticsearchDataAutoConfiguration {
|
public class ElasticsearchDataAutoConfiguration {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,8 @@ package org.springframework.boot.autoconfigure.data.elasticsearch;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
|
||||||
|
import co.elastic.clients.elasticsearch.ElasticsearchClient;
|
||||||
|
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
|
@ -26,14 +28,15 @@ import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.data.elasticsearch.annotations.Document;
|
import org.springframework.data.elasticsearch.annotations.Document;
|
||||||
import org.springframework.data.elasticsearch.client.erhlc.ReactiveElasticsearchClient;
|
import org.springframework.data.elasticsearch.client.elc.ElasticsearchTemplate;
|
||||||
|
import org.springframework.data.elasticsearch.client.elc.ReactiveElasticsearchClient;
|
||||||
|
import org.springframework.data.elasticsearch.client.elc.ReactiveElasticsearchTemplate;
|
||||||
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
|
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
|
||||||
import org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperations;
|
import org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperations;
|
||||||
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
|
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
|
||||||
import org.springframework.data.elasticsearch.core.convert.ElasticsearchCustomConversions;
|
import org.springframework.data.elasticsearch.core.convert.ElasticsearchCustomConversions;
|
||||||
import org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter;
|
import org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter;
|
||||||
import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchMappingContext;
|
import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchMappingContext;
|
||||||
import org.springframework.web.reactive.function.client.WebClient;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configuration classes for Spring Data for Elasticsearch
|
* Configuration classes for Spring Data for Elasticsearch
|
||||||
|
@ -77,33 +80,28 @@ abstract class ElasticsearchDataConfiguration {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
@Configuration(proxyBeanMethods = false)
|
@Configuration(proxyBeanMethods = false)
|
||||||
@ConditionalOnClass(org.elasticsearch.client.RestHighLevelClient.class)
|
@ConditionalOnClass(ElasticsearchClient.class)
|
||||||
static class RestClientConfiguration {
|
static class JavaClientConfiguration {
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@ConditionalOnMissingBean(value = ElasticsearchOperations.class, name = "elasticsearchTemplate")
|
@ConditionalOnMissingBean(value = ElasticsearchOperations.class, name = "elasticsearchTemplate")
|
||||||
@ConditionalOnBean(org.elasticsearch.client.RestHighLevelClient.class)
|
@ConditionalOnBean(ElasticsearchClient.class)
|
||||||
org.springframework.data.elasticsearch.client.erhlc.ElasticsearchRestTemplate elasticsearchTemplate(
|
ElasticsearchTemplate elasticsearchTemplate(ElasticsearchClient client, ElasticsearchConverter converter) {
|
||||||
org.elasticsearch.client.RestHighLevelClient client, ElasticsearchConverter converter) {
|
return new ElasticsearchTemplate(client, converter);
|
||||||
return new org.springframework.data.elasticsearch.client.erhlc.ElasticsearchRestTemplate(client, converter);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Configuration(proxyBeanMethods = false)
|
@Configuration(proxyBeanMethods = false)
|
||||||
@ConditionalOnClass({ WebClient.class, ReactiveElasticsearchOperations.class })
|
|
||||||
static class ReactiveRestClientConfiguration {
|
static class ReactiveRestClientConfiguration {
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@ConditionalOnMissingBean(value = ReactiveElasticsearchOperations.class, name = "reactiveElasticsearchTemplate")
|
@ConditionalOnMissingBean(value = ReactiveElasticsearchOperations.class, name = "reactiveElasticsearchTemplate")
|
||||||
@ConditionalOnBean(ReactiveElasticsearchClient.class)
|
@ConditionalOnBean(ReactiveElasticsearchClient.class)
|
||||||
@SuppressWarnings("deprecation")
|
ReactiveElasticsearchTemplate reactiveElasticsearchTemplate(ReactiveElasticsearchClient client,
|
||||||
org.springframework.data.elasticsearch.client.erhlc.ReactiveElasticsearchTemplate reactiveElasticsearchTemplate(
|
ElasticsearchConverter converter) {
|
||||||
ReactiveElasticsearchClient client, ElasticsearchConverter converter) {
|
return new ReactiveElasticsearchTemplate(client, converter);
|
||||||
return new org.springframework.data.elasticsearch.client.erhlc.ReactiveElasticsearchTemplate(client,
|
|
||||||
converter);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,8 +16,6 @@
|
||||||
|
|
||||||
package org.springframework.boot.autoconfigure.data.elasticsearch;
|
package org.springframework.boot.autoconfigure.data.elasticsearch;
|
||||||
|
|
||||||
import org.elasticsearch.client.Client;
|
|
||||||
|
|
||||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||||
|
@ -38,7 +36,7 @@ import org.springframework.data.elasticsearch.repository.support.ElasticsearchRe
|
||||||
* @see EnableElasticsearchRepositories
|
* @see EnableElasticsearchRepositories
|
||||||
*/
|
*/
|
||||||
@AutoConfiguration
|
@AutoConfiguration
|
||||||
@ConditionalOnClass({ Client.class, ElasticsearchRepository.class })
|
@ConditionalOnClass(ElasticsearchRepository.class)
|
||||||
@ConditionalOnProperty(prefix = "spring.data.elasticsearch.repositories", name = "enabled", havingValue = "true",
|
@ConditionalOnProperty(prefix = "spring.data.elasticsearch.repositories", name = "enabled", havingValue = "true",
|
||||||
matchIfMissing = true)
|
matchIfMissing = true)
|
||||||
@ConditionalOnMissingBean(ElasticsearchRepositoryFactoryBean.class)
|
@ConditionalOnMissingBean(ElasticsearchRepositoryFactoryBean.class)
|
||||||
|
|
|
@ -22,7 +22,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
import org.springframework.context.annotation.Import;
|
import org.springframework.context.annotation.Import;
|
||||||
import org.springframework.data.elasticsearch.client.erhlc.ReactiveElasticsearchClient;
|
import org.springframework.data.elasticsearch.client.elc.ReactiveElasticsearchClient;
|
||||||
import org.springframework.data.elasticsearch.repository.ReactiveElasticsearchRepository;
|
import org.springframework.data.elasticsearch.repository.ReactiveElasticsearchRepository;
|
||||||
import org.springframework.data.elasticsearch.repository.config.EnableReactiveElasticsearchRepositories;
|
import org.springframework.data.elasticsearch.repository.config.EnableReactiveElasticsearchRepositories;
|
||||||
import org.springframework.data.elasticsearch.repository.support.ReactiveElasticsearchRepositoryFactoryBean;
|
import org.springframework.data.elasticsearch.repository.support.ReactiveElasticsearchRepositoryFactoryBean;
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2022 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.boot.autoconfigure.elasticsearch;
|
||||||
|
|
||||||
|
import co.elastic.clients.elasticsearch.ElasticsearchClient;
|
||||||
|
|
||||||
|
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||||
|
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||||
|
import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchClientConfigurations.ElasticsearchClientConfiguration;
|
||||||
|
import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchClientConfigurations.ElasticsearchTransportConfiguration;
|
||||||
|
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
|
||||||
|
import org.springframework.boot.autoconfigure.jsonb.JsonbAutoConfiguration;
|
||||||
|
import org.springframework.context.annotation.Import;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@link EnableAutoConfiguration Auto-configuration} for Elasticsearch's Java client.
|
||||||
|
*
|
||||||
|
* @author Andy Wilkinson
|
||||||
|
* @since 3.0.0
|
||||||
|
*/
|
||||||
|
@AutoConfiguration(after = { JacksonAutoConfiguration.class, JsonbAutoConfiguration.class,
|
||||||
|
ElasticsearchRestClientAutoConfiguration.class })
|
||||||
|
@ConditionalOnClass(ElasticsearchClient.class)
|
||||||
|
@Import({ ElasticsearchTransportConfiguration.class, ElasticsearchClientConfiguration.class })
|
||||||
|
public class ElasticsearchClientAutoConfiguration {
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,107 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2022 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.boot.autoconfigure.elasticsearch;
|
||||||
|
|
||||||
|
import co.elastic.clients.elasticsearch.ElasticsearchClient;
|
||||||
|
import co.elastic.clients.json.JsonpMapper;
|
||||||
|
import co.elastic.clients.json.SimpleJsonpMapper;
|
||||||
|
import co.elastic.clients.json.jackson.JacksonJsonpMapper;
|
||||||
|
import co.elastic.clients.json.jsonb.JsonbJsonpMapper;
|
||||||
|
import co.elastic.clients.transport.ElasticsearchTransport;
|
||||||
|
import co.elastic.clients.transport.TransportOptions;
|
||||||
|
import co.elastic.clients.transport.rest_client.RestClientTransport;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import jakarta.json.bind.Jsonb;
|
||||||
|
import jakarta.json.spi.JsonProvider;
|
||||||
|
import org.elasticsearch.client.RestClient;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.ObjectProvider;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.Import;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configurations for import into {@link ElasticsearchClientAutoConfiguration}.
|
||||||
|
*
|
||||||
|
* @author Andy Wilkinson
|
||||||
|
*/
|
||||||
|
class ElasticsearchClientConfigurations {
|
||||||
|
|
||||||
|
@ConditionalOnMissingBean(JsonpMapper.class)
|
||||||
|
@ConditionalOnBean(ObjectMapper.class)
|
||||||
|
@Configuration(proxyBeanMethods = false)
|
||||||
|
static class JacksonJsonpMapperConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
JacksonJsonpMapper jacksonJsonpMapper(ObjectMapper objectMapper) {
|
||||||
|
return new JacksonJsonpMapper(objectMapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@ConditionalOnMissingBean(JsonpMapper.class)
|
||||||
|
@ConditionalOnBean(Jsonb.class)
|
||||||
|
@Configuration(proxyBeanMethods = false)
|
||||||
|
static class JsonbJsonpMapperConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
JsonbJsonpMapper jsonbJsonpMapper(Jsonb jsonb) {
|
||||||
|
return new JsonbJsonpMapper(JsonProvider.provider(), jsonb);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@ConditionalOnMissingBean(JsonpMapper.class)
|
||||||
|
@Configuration(proxyBeanMethods = false)
|
||||||
|
static class SimpleJsonpMapperConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
SimpleJsonpMapper simpleJsonpMapper() {
|
||||||
|
return new SimpleJsonpMapper();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Import({ JacksonJsonpMapperConfiguration.class, JsonbJsonpMapperConfiguration.class,
|
||||||
|
SimpleJsonpMapperConfiguration.class })
|
||||||
|
@ConditionalOnBean(RestClient.class)
|
||||||
|
@ConditionalOnMissingBean(ElasticsearchTransport.class)
|
||||||
|
static class ElasticsearchTransportConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
RestClientTransport restClientTransport(RestClient restClient, JsonpMapper jsonMapper,
|
||||||
|
ObjectProvider<TransportOptions> transportOptions) {
|
||||||
|
return new RestClientTransport(restClient, jsonMapper, transportOptions.getIfAvailable());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration(proxyBeanMethods = false)
|
||||||
|
@ConditionalOnBean(ElasticsearchTransport.class)
|
||||||
|
static class ElasticsearchClientConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnMissingBean
|
||||||
|
ElasticsearchClient elasticsearchClient(ElasticsearchTransport transport) {
|
||||||
|
return new ElasticsearchClient(transport);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -22,7 +22,6 @@ import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
import org.springframework.util.unit.DataSize;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configuration properties for Elasticsearch.
|
* Configuration properties for Elasticsearch.
|
||||||
|
@ -65,8 +64,6 @@ public class ElasticsearchProperties {
|
||||||
|
|
||||||
private final Restclient restclient = new Restclient();
|
private final Restclient restclient = new Restclient();
|
||||||
|
|
||||||
private final Webclient webclient = new Webclient();
|
|
||||||
|
|
||||||
public List<String> getUris() {
|
public List<String> getUris() {
|
||||||
return this.uris;
|
return this.uris;
|
||||||
}
|
}
|
||||||
|
@ -119,10 +116,6 @@ public class ElasticsearchProperties {
|
||||||
return this.restclient;
|
return this.restclient;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Webclient getWebclient() {
|
|
||||||
return this.webclient;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class Restclient {
|
public static class Restclient {
|
||||||
|
|
||||||
private final Sniffer sniffer = new Sniffer();
|
private final Sniffer sniffer = new Sniffer();
|
||||||
|
@ -163,22 +156,4 @@ public class ElasticsearchProperties {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Webclient {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Limit on the number of bytes that can be buffered whenever the input stream
|
|
||||||
* needs to be aggregated.
|
|
||||||
*/
|
|
||||||
private DataSize maxInMemorySize;
|
|
||||||
|
|
||||||
public DataSize getMaxInMemorySize() {
|
|
||||||
return this.maxInMemorySize;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMaxInMemorySize(DataSize maxInMemorySize) {
|
|
||||||
this.maxInMemorySize = maxInMemorySize;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,9 +23,7 @@ import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||||
import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchRestClientConfigurations.RestClientBuilderConfiguration;
|
import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchRestClientConfigurations.RestClientBuilderConfiguration;
|
||||||
import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchRestClientConfigurations.RestClientConfiguration;
|
import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchRestClientConfigurations.RestClientConfiguration;
|
||||||
import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchRestClientConfigurations.RestClientFromRestHighLevelClientConfiguration;
|
|
||||||
import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchRestClientConfigurations.RestClientSnifferConfiguration;
|
import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchRestClientConfigurations.RestClientSnifferConfiguration;
|
||||||
import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchRestClientConfigurations.RestHighLevelClientConfiguration;
|
|
||||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
import org.springframework.context.annotation.Import;
|
import org.springframework.context.annotation.Import;
|
||||||
|
|
||||||
|
@ -39,9 +37,7 @@ import org.springframework.context.annotation.Import;
|
||||||
@AutoConfiguration
|
@AutoConfiguration
|
||||||
@ConditionalOnClass(RestClientBuilder.class)
|
@ConditionalOnClass(RestClientBuilder.class)
|
||||||
@EnableConfigurationProperties(ElasticsearchProperties.class)
|
@EnableConfigurationProperties(ElasticsearchProperties.class)
|
||||||
@Import({ RestClientBuilderConfiguration.class, RestHighLevelClientConfiguration.class,
|
@Import({ RestClientBuilderConfiguration.class, RestClientConfiguration.class, RestClientSnifferConfiguration.class })
|
||||||
RestClientFromRestHighLevelClientConfiguration.class, RestClientConfiguration.class,
|
|
||||||
RestClientSnifferConfiguration.class })
|
|
||||||
public class ElasticsearchRestClientAutoConfiguration {
|
public class ElasticsearchRestClientAutoConfiguration {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,6 @@ import org.elasticsearch.client.sniff.SnifferBuilder;
|
||||||
import org.springframework.beans.factory.ObjectProvider;
|
import org.springframework.beans.factory.ObjectProvider;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
|
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
|
||||||
import org.springframework.boot.context.properties.PropertyMapper;
|
import org.springframework.boot.context.properties.PropertyMapper;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
|
@ -109,36 +108,7 @@ class ElasticsearchRestClientConfigurations {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
@Configuration(proxyBeanMethods = false)
|
@Configuration(proxyBeanMethods = false)
|
||||||
@ConditionalOnClass(org.elasticsearch.client.RestHighLevelClient.class)
|
|
||||||
@ConditionalOnMissingBean({ org.elasticsearch.client.RestHighLevelClient.class, RestClient.class })
|
|
||||||
static class RestHighLevelClientConfiguration {
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
org.elasticsearch.client.RestHighLevelClient elasticsearchRestHighLevelClient(
|
|
||||||
RestClientBuilder restClientBuilder) {
|
|
||||||
return new org.elasticsearch.client.RestHighLevelClient(restClientBuilder);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
@Configuration(proxyBeanMethods = false)
|
|
||||||
@ConditionalOnClass(org.elasticsearch.client.RestHighLevelClient.class)
|
|
||||||
@ConditionalOnSingleCandidate(org.elasticsearch.client.RestHighLevelClient.class)
|
|
||||||
@ConditionalOnMissingBean(RestClient.class)
|
|
||||||
static class RestClientFromRestHighLevelClientConfiguration {
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
RestClient elasticsearchRestClient(org.elasticsearch.client.RestHighLevelClient restHighLevelClient) {
|
|
||||||
return restHighLevelClient.getLowLevelClient();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Configuration(proxyBeanMethods = false)
|
|
||||||
@ConditionalOnMissingClass("org.elasticsearch.client.RestHighLevelClient")
|
|
||||||
@ConditionalOnMissingBean(RestClient.class)
|
@ConditionalOnMissingBean(RestClient.class)
|
||||||
static class RestClientConfiguration {
|
static class RestClientConfiguration {
|
||||||
|
|
||||||
|
|
|
@ -16,207 +16,37 @@
|
||||||
|
|
||||||
package org.springframework.boot.autoconfigure.elasticsearch;
|
package org.springframework.boot.autoconfigure.elasticsearch;
|
||||||
|
|
||||||
import java.net.URI;
|
import co.elastic.clients.transport.ElasticsearchTransport;
|
||||||
import java.time.Duration;
|
import reactor.core.publisher.Mono;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import org.elasticsearch.ElasticsearchException;
|
|
||||||
import org.elasticsearch.client.indices.GetIndexRequest;
|
|
||||||
import reactor.netty.http.client.HttpClient;
|
|
||||||
|
|
||||||
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||||
import org.springframework.boot.context.properties.PropertyMapper;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.data.elasticsearch.client.ClientConfiguration;
|
import org.springframework.context.annotation.Import;
|
||||||
import org.springframework.data.elasticsearch.client.elc.ElasticsearchClients;
|
import org.springframework.data.elasticsearch.client.elc.ReactiveElasticsearchClient;
|
||||||
import org.springframework.data.elasticsearch.client.erhlc.ReactiveElasticsearchClient;
|
|
||||||
import org.springframework.data.elasticsearch.client.erhlc.ReactiveRestClients;
|
|
||||||
import org.springframework.util.Assert;
|
|
||||||
import org.springframework.util.ObjectUtils;
|
|
||||||
import org.springframework.util.unit.DataSize;
|
|
||||||
import org.springframework.web.reactive.function.client.ExchangeStrategies;
|
|
||||||
import org.springframework.web.reactive.function.client.WebClient;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link EnableAutoConfiguration Auto-configuration} for Elasticsearch Reactive REST
|
* {@link EnableAutoConfiguration Auto-configuration} for Spring Data Elasticsearch's
|
||||||
* clients.
|
* reactive client.
|
||||||
*
|
*
|
||||||
* @author Brian Clozel
|
* @author Brian Clozel
|
||||||
* @since 3.0.0
|
* @since 3.0.0
|
||||||
*/
|
*/
|
||||||
@AutoConfiguration
|
@AutoConfiguration(after = ElasticsearchClientAutoConfiguration.class)
|
||||||
@ConditionalOnClass({ ReactiveRestClients.class, ElasticsearchException.class, GetIndexRequest.class, WebClient.class,
|
@ConditionalOnClass({ ReactiveElasticsearchClient.class, ElasticsearchTransport.class, Mono.class })
|
||||||
HttpClient.class })
|
|
||||||
@EnableConfigurationProperties(ElasticsearchProperties.class)
|
@EnableConfigurationProperties(ElasticsearchProperties.class)
|
||||||
@SuppressWarnings("deprecation")
|
@Import(ElasticsearchClientConfigurations.ElasticsearchTransportConfiguration.class)
|
||||||
public class ReactiveElasticsearchClientAutoConfiguration {
|
public class ReactiveElasticsearchClientAutoConfiguration {
|
||||||
|
|
||||||
private final ConsolidatedProperties properties;
|
|
||||||
|
|
||||||
ReactiveElasticsearchClientAutoConfiguration(ElasticsearchProperties properties) {
|
|
||||||
this.properties = new ConsolidatedProperties(properties);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@ConditionalOnMissingBean
|
@ConditionalOnMissingBean
|
||||||
public ClientConfiguration clientConfiguration() {
|
@ConditionalOnBean(ElasticsearchTransport.class)
|
||||||
ClientConfiguration.MaybeSecureClientConfigurationBuilder builder = ClientConfiguration.builder()
|
ReactiveElasticsearchClient reactiveElasticsearchClient(ElasticsearchTransport transport) {
|
||||||
.connectedTo(this.properties.getEndpoints().toArray(new String[0]));
|
return new ReactiveElasticsearchClient(transport);
|
||||||
PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull();
|
|
||||||
map.from(this.properties.isUseSsl()).whenTrue().toCall(builder::usingSsl);
|
|
||||||
map.from(this.properties.getCredentials())
|
|
||||||
.to((credentials) -> builder.withBasicAuth(credentials.getUsername(), credentials.getPassword()));
|
|
||||||
map.from(this.properties.getConnectionTimeout()).to(builder::withConnectTimeout);
|
|
||||||
map.from(this.properties.getSocketTimeout()).to(builder::withSocketTimeout);
|
|
||||||
map.from(this.properties.getPathPrefix()).to(builder::withPathPrefix);
|
|
||||||
configureExchangeStrategies(map, builder);
|
|
||||||
return builder.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void configureExchangeStrategies(PropertyMapper map,
|
|
||||||
ClientConfiguration.TerminalClientConfigurationBuilder builder) {
|
|
||||||
map.from(this.properties.getMaxInMemorySize()).asInt(DataSize::toBytes).to((maxInMemorySize) -> {
|
|
||||||
builder.withClientConfigurer(ElasticsearchClients.WebClientConfigurationCallback.from((webClient) -> {
|
|
||||||
ExchangeStrategies exchangeStrategies = ExchangeStrategies.builder()
|
|
||||||
.codecs((configurer) -> configurer.defaultCodecs().maxInMemorySize(maxInMemorySize)).build();
|
|
||||||
return webClient.mutate().exchangeStrategies(exchangeStrategies).build();
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
@ConditionalOnMissingBean
|
|
||||||
public ReactiveElasticsearchClient reactiveElasticsearchClient(ClientConfiguration clientConfiguration) {
|
|
||||||
return ReactiveRestClients.create(clientConfiguration);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final class ConsolidatedProperties {
|
|
||||||
|
|
||||||
private final ElasticsearchProperties properties;
|
|
||||||
|
|
||||||
private final List<URI> uris;
|
|
||||||
|
|
||||||
private ConsolidatedProperties(ElasticsearchProperties properties) {
|
|
||||||
this.properties = properties;
|
|
||||||
this.uris = properties.getUris().stream().map((s) -> s.startsWith("http") ? s : "http://" + s)
|
|
||||||
.map(URI::create).collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<String> getEndpoints() {
|
|
||||||
return this.uris.stream().map(this::getEndpoint).collect(Collectors.toList());
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getEndpoint(URI uri) {
|
|
||||||
return uri.getHost() + ":" + uri.getPort();
|
|
||||||
}
|
|
||||||
|
|
||||||
private Credentials getCredentials() {
|
|
||||||
Credentials propertyCredentials = Credentials.from(this.properties);
|
|
||||||
Credentials uriCredentials = Credentials.from(this.uris);
|
|
||||||
if (uriCredentials == null) {
|
|
||||||
return propertyCredentials;
|
|
||||||
}
|
|
||||||
Assert.isTrue(propertyCredentials == null || uriCredentials.equals(propertyCredentials),
|
|
||||||
"Credentials from URI user info do not match those from spring.elasticsearch.username and "
|
|
||||||
+ "spring.elasticsearch.password");
|
|
||||||
return uriCredentials;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Duration getConnectionTimeout() {
|
|
||||||
return this.properties.getConnectionTimeout();
|
|
||||||
}
|
|
||||||
|
|
||||||
private Duration getSocketTimeout() {
|
|
||||||
return this.properties.getSocketTimeout();
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isUseSsl() {
|
|
||||||
Set<String> schemes = this.uris.stream().map(URI::getScheme).collect(Collectors.toSet());
|
|
||||||
Assert.isTrue(schemes.size() == 1, "Configured Elasticsearch URIs have varying schemes");
|
|
||||||
return schemes.iterator().next().equals("https");
|
|
||||||
}
|
|
||||||
|
|
||||||
private DataSize getMaxInMemorySize() {
|
|
||||||
return this.properties.getWebclient().getMaxInMemorySize();
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getPathPrefix() {
|
|
||||||
return this.properties.getPathPrefix();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final class Credentials {
|
|
||||||
|
|
||||||
private final String username;
|
|
||||||
|
|
||||||
private final String password;
|
|
||||||
|
|
||||||
private Credentials(String username, String password) {
|
|
||||||
this.username = username;
|
|
||||||
this.password = password;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getUsername() {
|
|
||||||
return this.username;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getPassword() {
|
|
||||||
return this.password;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Credentials from(List<URI> uris) {
|
|
||||||
Set<String> userInfos = uris.stream().map(URI::getUserInfo).collect(Collectors.toSet());
|
|
||||||
Assert.isTrue(userInfos.size() == 1, "Configured Elasticsearch URIs have varying user infos");
|
|
||||||
String userInfo = userInfos.iterator().next();
|
|
||||||
if (userInfo == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
String[] parts = userInfo.split(":");
|
|
||||||
String username = parts[0];
|
|
||||||
String password = (parts.length != 2) ? "" : parts[1];
|
|
||||||
return new Credentials(username, password);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Credentials from(ElasticsearchProperties properties) {
|
|
||||||
return getCredentials(properties.getUsername(), properties.getPassword());
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Credentials getCredentials(String username, String password) {
|
|
||||||
if (username == null && password == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return new Credentials(username, password);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object obj) {
|
|
||||||
if (this == obj) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (obj == null || getClass() != obj.getClass()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
Credentials other = (Credentials) obj;
|
|
||||||
return ObjectUtils.nullSafeEquals(this.username, other.username)
|
|
||||||
&& ObjectUtils.nullSafeEquals(this.password, other.password);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
final int prime = 31;
|
|
||||||
int result = 1;
|
|
||||||
result = prime * result + ObjectUtils.nullSafeHashCode(this.username);
|
|
||||||
result = prime * result + ObjectUtils.nullSafeHashCode(this.password);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -981,6 +981,15 @@
|
||||||
"http://localhost:9200"
|
"http://localhost:9200"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "spring.elasticsearch.webclient.max-in-memory-size",
|
||||||
|
"type": "org.springframework.util.unit.DataSize",
|
||||||
|
"description": "Limit on the number of bytes that can be buffered whenever the input stream needs to be aggregated.",
|
||||||
|
"deprecation": {
|
||||||
|
"level": "error",
|
||||||
|
"reason": "Reactive Elasticsearch client no longer uses WebClient."
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "spring.flyway.baseline-migration-prefix",
|
"name": "spring.flyway.baseline-migration-prefix",
|
||||||
"defaultValue": "B"
|
"defaultValue": "B"
|
||||||
|
|
|
@ -39,6 +39,7 @@ org.springframework.boot.autoconfigure.data.redis.RedisReactiveAutoConfiguration
|
||||||
org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration
|
org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration
|
||||||
org.springframework.boot.autoconfigure.data.rest.RepositoryRestMvcAutoConfiguration
|
org.springframework.boot.autoconfigure.data.rest.RepositoryRestMvcAutoConfiguration
|
||||||
org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration
|
org.springframework.boot.autoconfigure.data.web.SpringDataWebAutoConfiguration
|
||||||
|
org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchClientAutoConfiguration
|
||||||
org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchRestClientAutoConfiguration
|
org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchRestClientAutoConfiguration
|
||||||
org.springframework.boot.autoconfigure.elasticsearch.ReactiveElasticsearchClientAutoConfiguration
|
org.springframework.boot.autoconfigure.elasticsearch.ReactiveElasticsearchClientAutoConfiguration
|
||||||
org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration
|
org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration
|
||||||
|
|
|
@ -20,21 +20,20 @@ import java.math.BigDecimal;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
|
||||||
import org.assertj.core.api.InstanceOfAssertFactories;
|
import org.assertj.core.api.InstanceOfAssertFactories;
|
||||||
import org.junit.jupiter.api.AfterEach;
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||||
import org.springframework.boot.autoconfigure.TestAutoConfigurationPackage;
|
import org.springframework.boot.autoconfigure.TestAutoConfigurationPackage;
|
||||||
import org.springframework.boot.autoconfigure.data.elasticsearch.city.City;
|
import org.springframework.boot.autoconfigure.data.elasticsearch.city.City;
|
||||||
|
import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchClientAutoConfiguration;
|
||||||
import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchRestClientAutoConfiguration;
|
import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchRestClientAutoConfiguration;
|
||||||
import org.springframework.boot.autoconfigure.elasticsearch.ReactiveElasticsearchClientAutoConfiguration;
|
import org.springframework.boot.autoconfigure.elasticsearch.ReactiveElasticsearchClientAutoConfiguration;
|
||||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.core.convert.converter.Converter;
|
import org.springframework.core.convert.converter.Converter;
|
||||||
import org.springframework.data.elasticsearch.client.erhlc.ElasticsearchRestTemplate;
|
import org.springframework.data.elasticsearch.client.elc.ElasticsearchTemplate;
|
||||||
import org.springframework.data.elasticsearch.client.erhlc.ReactiveElasticsearchTemplate;
|
import org.springframework.data.elasticsearch.client.elc.ReactiveElasticsearchTemplate;
|
||||||
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
|
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
|
||||||
import org.springframework.data.elasticsearch.core.convert.ElasticsearchCustomConversions;
|
import org.springframework.data.elasticsearch.core.convert.ElasticsearchCustomConversions;
|
||||||
import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchMappingContext;
|
import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchMappingContext;
|
||||||
|
@ -53,26 +52,16 @@ import static org.mockito.Mockito.mock;
|
||||||
* @author Scott Frederick
|
* @author Scott Frederick
|
||||||
* @author Stephane Nicoll
|
* @author Stephane Nicoll
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
class ElasticsearchDataAutoConfigurationTests {
|
class ElasticsearchDataAutoConfigurationTests {
|
||||||
|
|
||||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||||
.withConfiguration(AutoConfigurations.of(ElasticsearchRestClientAutoConfiguration.class,
|
.withConfiguration(AutoConfigurations.of(ElasticsearchRestClientAutoConfiguration.class,
|
||||||
ReactiveElasticsearchClientAutoConfiguration.class, ElasticsearchDataAutoConfiguration.class));
|
ElasticsearchClientAutoConfiguration.class, ElasticsearchDataAutoConfiguration.class,
|
||||||
|
ReactiveElasticsearchClientAutoConfiguration.class));
|
||||||
@BeforeEach
|
|
||||||
void setUp() {
|
|
||||||
System.setProperty("es.set.netty.runtime.available.processors", "false");
|
|
||||||
}
|
|
||||||
|
|
||||||
@AfterEach
|
|
||||||
void tearDown() {
|
|
||||||
System.clearProperty("es.set.netty.runtime.available.processors");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void defaultRestBeansRegistered() {
|
void defaultRestBeansRegistered() {
|
||||||
this.contextRunner.run((context) -> assertThat(context).hasSingleBean(ElasticsearchRestTemplate.class)
|
this.contextRunner.run((context) -> assertThat(context).hasSingleBean(ElasticsearchTemplate.class)
|
||||||
.hasSingleBean(ReactiveElasticsearchTemplate.class).hasSingleBean(ElasticsearchConverter.class)
|
.hasSingleBean(ReactiveElasticsearchTemplate.class).hasSingleBean(ElasticsearchConverter.class)
|
||||||
.hasSingleBean(ElasticsearchConverter.class).hasSingleBean(ElasticsearchCustomConversions.class));
|
.hasSingleBean(ElasticsearchConverter.class).hasSingleBean(ElasticsearchCustomConversions.class));
|
||||||
}
|
}
|
||||||
|
@ -92,19 +81,19 @@ class ElasticsearchDataAutoConfigurationTests {
|
||||||
this.contextRunner.withUserConfiguration(CustomElasticsearchCustomConversions.class).run((context) -> {
|
this.contextRunner.withUserConfiguration(CustomElasticsearchCustomConversions.class).run((context) -> {
|
||||||
assertThat(context).hasSingleBean(ElasticsearchCustomConversions.class).hasBean("testCustomConversions");
|
assertThat(context).hasSingleBean(ElasticsearchCustomConversions.class).hasBean("testCustomConversions");
|
||||||
assertThat(context.getBean(ElasticsearchConverter.class).getConversionService()
|
assertThat(context.getBean(ElasticsearchConverter.class).getConversionService()
|
||||||
.canConvert(ElasticsearchRestTemplate.class, Boolean.class)).isTrue();
|
.canConvert(ElasticsearchTemplate.class, Boolean.class)).isTrue();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void customRestTemplateShouldBeUsed() {
|
void customRestTemplateShouldBeUsed() {
|
||||||
this.contextRunner.withUserConfiguration(CustomRestTemplate.class).run((context) -> assertThat(context)
|
this.contextRunner.withUserConfiguration(CustomRestTemplate.class).run((context) -> assertThat(context)
|
||||||
.getBeanNames(ElasticsearchRestTemplate.class).hasSize(1).contains("elasticsearchTemplate"));
|
.getBeanNames(ElasticsearchTemplate.class).hasSize(1).contains("elasticsearchTemplate"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void customReactiveRestTemplateShouldBeUsed() {
|
void customReactiveRestTemplateShouldBeUsed() {
|
||||||
this.contextRunner.withUserConfiguration(CustomReactiveRestTemplate.class)
|
this.contextRunner.withUserConfiguration(CustomReactiveElasticsearchTemplate.class)
|
||||||
.run((context) -> assertThat(context).getBeanNames(ReactiveElasticsearchTemplate.class).hasSize(1)
|
.run((context) -> assertThat(context).getBeanNames(ReactiveElasticsearchTemplate.class).hasSize(1)
|
||||||
.contains("reactiveElasticsearchTemplate"));
|
.contains("reactiveElasticsearchTemplate"));
|
||||||
}
|
}
|
||||||
|
@ -131,14 +120,14 @@ class ElasticsearchDataAutoConfigurationTests {
|
||||||
static class CustomRestTemplate {
|
static class CustomRestTemplate {
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
ElasticsearchRestTemplate elasticsearchTemplate() {
|
ElasticsearchTemplate elasticsearchTemplate() {
|
||||||
return mock(ElasticsearchRestTemplate.class);
|
return mock(ElasticsearchTemplate.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Configuration(proxyBeanMethods = false)
|
@Configuration(proxyBeanMethods = false)
|
||||||
static class CustomReactiveRestTemplate {
|
static class CustomReactiveElasticsearchTemplate {
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
ReactiveElasticsearchTemplate reactiveElasticsearchTemplate() {
|
ReactiveElasticsearchTemplate reactiveElasticsearchTemplate() {
|
||||||
|
@ -153,10 +142,10 @@ class ElasticsearchDataAutoConfigurationTests {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static class MyConverter implements Converter<ElasticsearchRestTemplate, Boolean> {
|
static class MyConverter implements Converter<ElasticsearchTemplate, Boolean> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Boolean convert(ElasticsearchRestTemplate source) {
|
public Boolean convert(ElasticsearchTemplate source) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,11 +29,12 @@ import org.springframework.boot.autoconfigure.data.alt.elasticsearch.CityElastic
|
||||||
import org.springframework.boot.autoconfigure.data.elasticsearch.city.City;
|
import org.springframework.boot.autoconfigure.data.elasticsearch.city.City;
|
||||||
import org.springframework.boot.autoconfigure.data.elasticsearch.city.CityRepository;
|
import org.springframework.boot.autoconfigure.data.elasticsearch.city.CityRepository;
|
||||||
import org.springframework.boot.autoconfigure.data.empty.EmptyDataPackage;
|
import org.springframework.boot.autoconfigure.data.empty.EmptyDataPackage;
|
||||||
|
import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchClientAutoConfiguration;
|
||||||
import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchRestClientAutoConfiguration;
|
import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchRestClientAutoConfiguration;
|
||||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||||
import org.springframework.boot.testsupport.testcontainers.DockerImageNames;
|
import org.springframework.boot.testsupport.testcontainers.DockerImageNames;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.data.elasticsearch.client.erhlc.ElasticsearchRestTemplate;
|
import org.springframework.data.elasticsearch.client.elc.ElasticsearchTemplate;
|
||||||
import org.springframework.data.elasticsearch.repository.config.EnableElasticsearchRepositories;
|
import org.springframework.data.elasticsearch.repository.config.EnableElasticsearchRepositories;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
@ -46,7 +47,6 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||||
* @author Brian Clozel
|
* @author Brian Clozel
|
||||||
*/
|
*/
|
||||||
@Testcontainers(disabledWithoutDocker = true)
|
@Testcontainers(disabledWithoutDocker = true)
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
class ElasticsearchRepositoriesAutoConfigurationTests {
|
class ElasticsearchRepositoriesAutoConfigurationTests {
|
||||||
|
|
||||||
@Container
|
@Container
|
||||||
|
@ -55,19 +55,20 @@ class ElasticsearchRepositoriesAutoConfigurationTests {
|
||||||
|
|
||||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||||
.withConfiguration(AutoConfigurations.of(ElasticsearchRestClientAutoConfiguration.class,
|
.withConfiguration(AutoConfigurations.of(ElasticsearchRestClientAutoConfiguration.class,
|
||||||
ElasticsearchRepositoriesAutoConfiguration.class, ElasticsearchDataAutoConfiguration.class))
|
ElasticsearchClientAutoConfiguration.class, ElasticsearchRepositoriesAutoConfiguration.class,
|
||||||
|
ElasticsearchDataAutoConfiguration.class))
|
||||||
.withPropertyValues("spring.elasticsearch.uris=" + elasticsearch.getHttpHostAddress());
|
.withPropertyValues("spring.elasticsearch.uris=" + elasticsearch.getHttpHostAddress());
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testDefaultRepositoryConfiguration() {
|
void testDefaultRepositoryConfiguration() {
|
||||||
this.contextRunner.withUserConfiguration(TestConfiguration.class).run((context) -> assertThat(context)
|
this.contextRunner.withUserConfiguration(TestConfiguration.class).run((context) -> assertThat(context)
|
||||||
.hasSingleBean(CityRepository.class).hasSingleBean(ElasticsearchRestTemplate.class));
|
.hasSingleBean(CityRepository.class).hasSingleBean(ElasticsearchTemplate.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testNoRepositoryConfiguration() {
|
void testNoRepositoryConfiguration() {
|
||||||
this.contextRunner.withUserConfiguration(EmptyConfiguration.class)
|
this.contextRunner.withUserConfiguration(EmptyConfiguration.class)
|
||||||
.run((context) -> assertThat(context).hasSingleBean(ElasticsearchRestTemplate.class));
|
.run((context) -> assertThat(context).hasSingleBean(ElasticsearchTemplate.class));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -29,11 +29,12 @@ import org.springframework.boot.autoconfigure.data.alt.elasticsearch.CityReactiv
|
||||||
import org.springframework.boot.autoconfigure.data.elasticsearch.city.City;
|
import org.springframework.boot.autoconfigure.data.elasticsearch.city.City;
|
||||||
import org.springframework.boot.autoconfigure.data.elasticsearch.city.ReactiveCityRepository;
|
import org.springframework.boot.autoconfigure.data.elasticsearch.city.ReactiveCityRepository;
|
||||||
import org.springframework.boot.autoconfigure.data.empty.EmptyDataPackage;
|
import org.springframework.boot.autoconfigure.data.empty.EmptyDataPackage;
|
||||||
import org.springframework.boot.autoconfigure.elasticsearch.ReactiveElasticsearchClientAutoConfiguration;
|
import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchClientAutoConfiguration;
|
||||||
|
import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchRestClientAutoConfiguration;
|
||||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||||
import org.springframework.boot.testsupport.testcontainers.DockerImageNames;
|
import org.springframework.boot.testsupport.testcontainers.DockerImageNames;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.data.elasticsearch.client.erhlc.ReactiveElasticsearchTemplate;
|
import org.springframework.data.elasticsearch.client.elc.ReactiveElasticsearchTemplate;
|
||||||
import org.springframework.data.elasticsearch.repository.config.EnableReactiveElasticsearchRepositories;
|
import org.springframework.data.elasticsearch.repository.config.EnableReactiveElasticsearchRepositories;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
@ -46,7 +47,6 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||||
* @author Brian Clozel
|
* @author Brian Clozel
|
||||||
*/
|
*/
|
||||||
@Testcontainers(disabledWithoutDocker = true)
|
@Testcontainers(disabledWithoutDocker = true)
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
class ReactiveElasticsearchRepositoriesAutoConfigurationTests {
|
class ReactiveElasticsearchRepositoriesAutoConfigurationTests {
|
||||||
|
|
||||||
@Container
|
@Container
|
||||||
|
@ -54,7 +54,8 @@ class ReactiveElasticsearchRepositoriesAutoConfigurationTests {
|
||||||
.withStartupAttempts(5).withStartupTimeout(Duration.ofMinutes(10));
|
.withStartupAttempts(5).withStartupTimeout(Duration.ofMinutes(10));
|
||||||
|
|
||||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||||
.withConfiguration(AutoConfigurations.of(ReactiveElasticsearchClientAutoConfiguration.class,
|
.withConfiguration(AutoConfigurations.of(ElasticsearchClientAutoConfiguration.class,
|
||||||
|
ElasticsearchRestClientAutoConfiguration.class,
|
||||||
ReactiveElasticsearchRepositoriesAutoConfiguration.class, ElasticsearchDataAutoConfiguration.class))
|
ReactiveElasticsearchRepositoriesAutoConfiguration.class, ElasticsearchDataAutoConfiguration.class))
|
||||||
.withPropertyValues(
|
.withPropertyValues(
|
||||||
"spring.elasticsearch.uris=" + elasticsearch.getHost() + ":" + elasticsearch.getFirstMappedPort(),
|
"spring.elasticsearch.uris=" + elasticsearch.getHost() + ":" + elasticsearch.getFirstMappedPort(),
|
||||||
|
|
|
@ -0,0 +1,66 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2022 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.boot.autoconfigure.elasticsearch;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import co.elastic.clients.elasticsearch.ElasticsearchClient;
|
||||||
|
import co.elastic.clients.elasticsearch.core.GetResponse;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.testcontainers.elasticsearch.ElasticsearchContainer;
|
||||||
|
import org.testcontainers.junit.jupiter.Container;
|
||||||
|
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||||
|
|
||||||
|
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||||
|
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
|
||||||
|
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||||
|
import org.springframework.boot.testsupport.testcontainers.DockerImageNames;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Integration tests for {@link ElasticsearchClientAutoConfiguration}.
|
||||||
|
*
|
||||||
|
* @author Andy Wilkinson
|
||||||
|
*/
|
||||||
|
@Testcontainers(disabledWithoutDocker = true)
|
||||||
|
class ElasticsearchClientAutoConfigurationIntegrationTests {
|
||||||
|
|
||||||
|
@Container
|
||||||
|
static ElasticsearchContainer elasticsearch = new ElasticsearchContainer(DockerImageNames.elasticsearch())
|
||||||
|
.withStartupAttempts(5).withStartupTimeout(Duration.ofMinutes(10));
|
||||||
|
|
||||||
|
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||||
|
.withConfiguration(AutoConfigurations.of(JacksonAutoConfiguration.class,
|
||||||
|
ElasticsearchRestClientAutoConfiguration.class, ElasticsearchClientAutoConfiguration.class));
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void reactiveClientCanQueryElasticsearchNode() {
|
||||||
|
this.contextRunner
|
||||||
|
.withPropertyValues("spring.elasticsearch.uris=" + elasticsearch.getHttpHostAddress(),
|
||||||
|
"spring.elasticsearch.connection-timeout=120s", "spring.elasticsearch.socket-timeout=120s")
|
||||||
|
.run((context) -> {
|
||||||
|
ElasticsearchClient client = context.getBean(ElasticsearchClient.class);
|
||||||
|
client.index((b) -> b.index("foo").id("1").document(Map.of("a", "alpha", "b", "bravo")));
|
||||||
|
GetResponse<Object> response = client.get((b) -> b.index("foo").id("1"), Object.class);
|
||||||
|
assertThat(response).isNotNull();
|
||||||
|
assertThat(response.found()).isTrue();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,141 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2012-2022 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.boot.autoconfigure.elasticsearch;
|
||||||
|
|
||||||
|
import co.elastic.clients.elasticsearch.ElasticsearchClient;
|
||||||
|
import co.elastic.clients.json.JsonpMapper;
|
||||||
|
import co.elastic.clients.json.SimpleJsonpMapper;
|
||||||
|
import co.elastic.clients.json.jackson.JacksonJsonpMapper;
|
||||||
|
import co.elastic.clients.json.jsonb.JsonbJsonpMapper;
|
||||||
|
import co.elastic.clients.transport.ElasticsearchTransport;
|
||||||
|
import co.elastic.clients.transport.rest_client.RestClientTransport;
|
||||||
|
import org.elasticsearch.client.RestClient;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||||
|
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
|
||||||
|
import org.springframework.boot.autoconfigure.jsonb.JsonbAutoConfiguration;
|
||||||
|
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for {@link ElasticsearchClientAutoConfiguration}.
|
||||||
|
*
|
||||||
|
* @author Andy Wilkinson
|
||||||
|
*/
|
||||||
|
public class ElasticsearchClientAutoConfigurationTests {
|
||||||
|
|
||||||
|
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||||
|
.withConfiguration(AutoConfigurations.of(ElasticsearchClientAutoConfiguration.class));
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void withoutRestClientThenAutoConfigurationShouldBackOff() {
|
||||||
|
this.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(ElasticsearchTransport.class)
|
||||||
|
.doesNotHaveBean(JsonpMapper.class).doesNotHaveBean(ElasticsearchClient.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void withRestClientAutoConfigurationShouldDefineClientAndSupportingBeans() {
|
||||||
|
this.contextRunner.withUserConfiguration(RestClientConfiguration.class)
|
||||||
|
.run((context) -> assertThat(context).hasSingleBean(JsonpMapper.class)
|
||||||
|
.hasSingleBean(RestClientTransport.class).hasSingleBean(ElasticsearchClient.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void withoutJsonbOrJacksonShouldDefineSimpleMapper() {
|
||||||
|
this.contextRunner.withUserConfiguration(RestClientConfiguration.class).run((context) -> assertThat(context)
|
||||||
|
.hasSingleBean(JsonpMapper.class).hasSingleBean(SimpleJsonpMapper.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void withJsonbShouldDefineJsonbMapper() {
|
||||||
|
this.contextRunner.withConfiguration(AutoConfigurations.of(JsonbAutoConfiguration.class))
|
||||||
|
.withUserConfiguration(RestClientConfiguration.class).run((context) -> assertThat(context)
|
||||||
|
.hasSingleBean(JsonpMapper.class).hasSingleBean(JsonbJsonpMapper.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void withJacksonShouldDefineJacksonMapper() {
|
||||||
|
this.contextRunner.withConfiguration(AutoConfigurations.of(JacksonAutoConfiguration.class))
|
||||||
|
.withUserConfiguration(RestClientConfiguration.class).run((context) -> assertThat(context)
|
||||||
|
.hasSingleBean(JsonpMapper.class).hasSingleBean(JacksonJsonpMapper.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void withJacksonAndJsonbShouldDefineJacksonMapper() {
|
||||||
|
this.contextRunner
|
||||||
|
.withConfiguration(AutoConfigurations.of(JsonbAutoConfiguration.class, JacksonAutoConfiguration.class))
|
||||||
|
.withUserConfiguration(RestClientConfiguration.class).run((context) -> assertThat(context)
|
||||||
|
.hasSingleBean(JsonpMapper.class).hasSingleBean(JacksonJsonpMapper.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void withCustomMapperTransportShouldUseIt() {
|
||||||
|
this.contextRunner.withUserConfiguration(JsonpMapperConfiguration.class)
|
||||||
|
.withUserConfiguration(RestClientConfiguration.class).run((context) -> {
|
||||||
|
assertThat(context).hasSingleBean(JsonpMapper.class).hasBean("customJsonpMapper");
|
||||||
|
JsonpMapper mapper = context.getBean(JsonpMapper.class);
|
||||||
|
assertThat(context.getBean(ElasticsearchTransport.class).jsonpMapper()).isSameAs(mapper);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void withCustomTransportClientShouldUseIt() {
|
||||||
|
this.contextRunner.withUserConfiguration(TransportConfiguration.class)
|
||||||
|
.withUserConfiguration(RestClientConfiguration.class).run((context) -> {
|
||||||
|
assertThat(context).hasSingleBean(ElasticsearchTransport.class)
|
||||||
|
.hasBean("customElasticsearchTransport");
|
||||||
|
ElasticsearchTransport transport = context.getBean(ElasticsearchTransport.class);
|
||||||
|
assertThat(context.getBean(ElasticsearchClient.class)._transport()).isSameAs(transport);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration(proxyBeanMethods = false)
|
||||||
|
static class RestClientConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
RestClient restClient() {
|
||||||
|
return mock(RestClient.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration(proxyBeanMethods = false)
|
||||||
|
static class JsonpMapperConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
JsonpMapper customJsonpMapper() {
|
||||||
|
return mock(JsonpMapper.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Configuration(proxyBeanMethods = false)
|
||||||
|
static class TransportConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
ElasticsearchTransport customElasticsearchTransport() {
|
||||||
|
return mock(ElasticsearchTransport.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -18,15 +18,10 @@ package org.springframework.boot.autoconfigure.elasticsearch;
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import org.elasticsearch.action.get.GetRequest;
|
|
||||||
import org.elasticsearch.action.index.IndexRequest;
|
|
||||||
import org.elasticsearch.client.Request;
|
import org.elasticsearch.client.Request;
|
||||||
import org.elasticsearch.client.RequestOptions;
|
|
||||||
import org.elasticsearch.client.Response;
|
import org.elasticsearch.client.Response;
|
||||||
import org.elasticsearch.client.RestClient;
|
import org.elasticsearch.client.RestClient;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
@ -58,25 +53,6 @@ class ElasticsearchRestClientAutoConfigurationIntegrationTests {
|
||||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||||
.withConfiguration(AutoConfigurations.of(ElasticsearchRestClientAutoConfiguration.class));
|
.withConfiguration(AutoConfigurations.of(ElasticsearchRestClientAutoConfiguration.class));
|
||||||
|
|
||||||
@Test
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
void restHighLevelClientCanQueryElasticsearchNode() {
|
|
||||||
this.contextRunner
|
|
||||||
.withPropertyValues("spring.elasticsearch.uris=" + elasticsearch.getHttpHostAddress(),
|
|
||||||
"spring.elasticsearch.connection-timeout=120s", "spring.elasticsearch.socket-timeout=120s")
|
|
||||||
.run((context) -> {
|
|
||||||
org.elasticsearch.client.RestHighLevelClient client = context
|
|
||||||
.getBean(org.elasticsearch.client.RestHighLevelClient.class);
|
|
||||||
Map<String, String> source = new HashMap<>();
|
|
||||||
source.put("a", "alpha");
|
|
||||||
source.put("b", "bravo");
|
|
||||||
IndexRequest index = new IndexRequest("test").id("1").source(source);
|
|
||||||
client.index(index, RequestOptions.DEFAULT);
|
|
||||||
GetRequest getRequest = new GetRequest("test").id("1");
|
|
||||||
assertThat(client.get(getRequest, RequestOptions.DEFAULT).isExists()).isTrue();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void restClientCanQueryElasticsearchNode() {
|
void restClientCanQueryElasticsearchNode() {
|
||||||
this.contextRunner
|
this.contextRunner
|
||||||
|
|
|
@ -50,74 +50,32 @@ import static org.mockito.Mockito.mock;
|
||||||
* @author Filip Hrisafov
|
* @author Filip Hrisafov
|
||||||
* @author Andy Wilkinson
|
* @author Andy Wilkinson
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
class ElasticsearchRestClientAutoConfigurationTests {
|
class ElasticsearchRestClientAutoConfigurationTests {
|
||||||
|
|
||||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||||
.withConfiguration(AutoConfigurations.of(ElasticsearchRestClientAutoConfiguration.class));
|
.withConfiguration(AutoConfigurations.of(ElasticsearchRestClientAutoConfiguration.class));
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void configureShouldCreateHighLevelAndLowLevelRestClients() {
|
void configureShouldCreateRestClientBuilderAndRestClient() {
|
||||||
this.contextRunner.run((context) -> {
|
this.contextRunner.run((context) -> assertThat(context).hasSingleBean(RestClient.class)
|
||||||
assertThat(context).hasSingleBean(RestClient.class)
|
.hasSingleBean(RestClientBuilder.class));
|
||||||
.hasSingleBean(org.elasticsearch.client.RestHighLevelClient.class)
|
|
||||||
.hasSingleBean(RestClientBuilder.class);
|
|
||||||
assertThat(context.getBean(RestClient.class))
|
|
||||||
.isEqualTo(context.getBean(org.elasticsearch.client.RestHighLevelClient.class).getLowLevelClient());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void configureWithoutRestHighLevelClientShouldOnlyCreateRestClientBuilderAndRestClient() {
|
|
||||||
this.contextRunner.withClassLoader(new FilteredClassLoader(org.elasticsearch.client.RestHighLevelClient.class))
|
|
||||||
.run((context) -> assertThat(context).hasSingleBean(RestClient.class)
|
|
||||||
.hasSingleBean(RestClientBuilder.class)
|
|
||||||
.doesNotHaveBean(org.elasticsearch.client.RestHighLevelClient.class));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void configureWhenCustomRestClientShouldBackOff() {
|
void configureWhenCustomRestClientShouldBackOff() {
|
||||||
this.contextRunner.withUserConfiguration(CustomRestClientConfiguration.class)
|
this.contextRunner.withUserConfiguration(CustomRestClientConfiguration.class)
|
||||||
.run((context) -> assertThat(context)
|
.run((context) -> assertThat(context).hasSingleBean(RestClientBuilder.class)
|
||||||
.doesNotHaveBean(org.elasticsearch.client.RestHighLevelClient.class)
|
.hasSingleBean(RestClient.class).hasBean("customRestClient"));
|
||||||
.hasSingleBean(RestClientBuilder.class).hasSingleBean(RestClient.class)
|
|
||||||
.hasBean("customRestClient"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void configureWhenCustomRestHighLevelClientShouldDefineRestClientFromCustomHighLevelClient() {
|
|
||||||
this.contextRunner.withUserConfiguration(CustomRestHighLevelClientConfiguration.class)
|
|
||||||
.run((context) -> assertThat(context).hasSingleBean(org.elasticsearch.client.RestHighLevelClient.class)
|
|
||||||
.hasSingleBean(RestClient.class).hasBean("elasticsearchRestClient").getBean(RestClient.class)
|
|
||||||
.isEqualTo(context.getBean(org.elasticsearch.client.RestHighLevelClient.class)
|
|
||||||
.getLowLevelClient()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void configureWhenCustomRestHighLevelClientAndRestClientShouldBackOff() {
|
|
||||||
this.contextRunner.withUserConfiguration(CustomRestHighLevelClientWithRestClientConfiguration.class)
|
|
||||||
.run((context) -> assertThat(context).hasSingleBean(org.elasticsearch.client.RestHighLevelClient.class)
|
|
||||||
.hasBean("customRestHighLevelClient").hasSingleBean(RestClient.class)
|
|
||||||
.hasBean("customRestClient"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void configureWhenNoUniqueRestHighLevelClientShouldNotDefineRestClient() {
|
|
||||||
this.contextRunner.withUserConfiguration(TwoCustomRestHighLevelClientsConfiguration.class)
|
|
||||||
.run((context) -> assertThat(context).doesNotHaveBean(RestClient.class));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void configureWhenBuilderCustomizerShouldApply() {
|
void configureWhenBuilderCustomizerShouldApply() {
|
||||||
this.contextRunner.withUserConfiguration(BuilderCustomizerConfiguration.class).run((context) -> {
|
this.contextRunner.withUserConfiguration(BuilderCustomizerConfiguration.class).run((context) -> {
|
||||||
assertThat(context).hasSingleBean(org.elasticsearch.client.RestHighLevelClient.class)
|
assertThat(context).hasSingleBean(RestClient.class);
|
||||||
.hasSingleBean(RestClient.class);
|
RestClient restClient = context.getBean(RestClient.class);
|
||||||
org.elasticsearch.client.RestHighLevelClient restClient = context
|
assertThat(restClient).hasFieldOrPropertyWithValue("pathPrefix", "/test");
|
||||||
.getBean(org.elasticsearch.client.RestHighLevelClient.class);
|
assertThat(restClient).extracting("client.connmgr.pool.maxTotal").isEqualTo(100);
|
||||||
RestClient lowLevelClient = restClient.getLowLevelClient();
|
assertThat(restClient).extracting("client.defaultConfig.cookieSpec").isEqualTo("rfc6265-lax");
|
||||||
assertThat(lowLevelClient).hasFieldOrPropertyWithValue("pathPrefix", "/test");
|
|
||||||
assertThat(lowLevelClient).extracting("client.connmgr.pool.maxTotal").isEqualTo(100);
|
|
||||||
assertThat(lowLevelClient).extracting("client.defaultConfig.cookieSpec").isEqualTo("rfc6265-lax");
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -228,14 +186,12 @@ class ElasticsearchRestClientAutoConfigurationTests {
|
||||||
@Test
|
@Test
|
||||||
void configureWithoutSnifferLibraryShouldNotCreateSniffer() {
|
void configureWithoutSnifferLibraryShouldNotCreateSniffer() {
|
||||||
this.contextRunner.withClassLoader(new FilteredClassLoader("org.elasticsearch.client.sniff"))
|
this.contextRunner.withClassLoader(new FilteredClassLoader("org.elasticsearch.client.sniff"))
|
||||||
.run((context) -> assertThat(context).hasSingleBean(org.elasticsearch.client.RestHighLevelClient.class)
|
.run((context) -> assertThat(context).hasSingleBean(RestClient.class).doesNotHaveBean(Sniffer.class));
|
||||||
.hasSingleBean(RestClient.class).doesNotHaveBean(Sniffer.class));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void configureShouldCreateSnifferUsingRestClient() {
|
void configureShouldCreateSnifferUsingRestClient() {
|
||||||
this.contextRunner.withClassLoader(new FilteredClassLoader(org.elasticsearch.client.RestHighLevelClient.class))
|
this.contextRunner.run((context) -> {
|
||||||
.run((context) -> {
|
|
||||||
assertThat(context).hasSingleBean(Sniffer.class);
|
assertThat(context).hasSingleBean(Sniffer.class);
|
||||||
assertThat(context.getBean(Sniffer.class)).hasFieldOrPropertyWithValue("restClient",
|
assertThat(context.getBean(Sniffer.class)).hasFieldOrPropertyWithValue("restClient",
|
||||||
context.getBean(RestClient.class));
|
context.getBean(RestClient.class));
|
||||||
|
@ -297,46 +253,6 @@ class ElasticsearchRestClientAutoConfigurationTests {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Configuration(proxyBeanMethods = false)
|
|
||||||
static class CustomRestHighLevelClientConfiguration {
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
org.elasticsearch.client.RestHighLevelClient customRestHighLevelClient(RestClientBuilder builder) {
|
|
||||||
return new org.elasticsearch.client.RestHighLevelClient(builder);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Configuration(proxyBeanMethods = false)
|
|
||||||
static class CustomRestHighLevelClientWithRestClientConfiguration {
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
org.elasticsearch.client.RestHighLevelClient customRestHighLevelClient(RestClientBuilder builder) {
|
|
||||||
return new org.elasticsearch.client.RestHighLevelClient(builder);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
RestClient customRestClient(org.elasticsearch.client.RestHighLevelClient restHighLevelClient) {
|
|
||||||
return restHighLevelClient.getLowLevelClient();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Configuration(proxyBeanMethods = false)
|
|
||||||
static class TwoCustomRestHighLevelClientsConfiguration {
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
org.elasticsearch.client.RestHighLevelClient customRestHighLevelClient(RestClientBuilder builder) {
|
|
||||||
return new org.elasticsearch.client.RestHighLevelClient(builder);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
org.elasticsearch.client.RestHighLevelClient anotherCustomRestHighLevelClient(RestClientBuilder builder) {
|
|
||||||
return new org.elasticsearch.client.RestHighLevelClient(builder);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Configuration(proxyBeanMethods = false)
|
@Configuration(proxyBeanMethods = false)
|
||||||
static class CustomRestClientConfiguration {
|
static class CustomRestClientConfiguration {
|
||||||
|
|
||||||
|
|
|
@ -17,21 +17,21 @@
|
||||||
package org.springframework.boot.autoconfigure.elasticsearch;
|
package org.springframework.boot.autoconfigure.elasticsearch;
|
||||||
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.elasticsearch.action.get.GetRequest;
|
import co.elastic.clients.elasticsearch.core.GetResponse;
|
||||||
import org.elasticsearch.action.index.IndexRequest;
|
import co.elastic.clients.elasticsearch.core.IndexResponse;
|
||||||
import org.elasticsearch.index.get.GetResult;
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.testcontainers.elasticsearch.ElasticsearchContainer;
|
import org.testcontainers.elasticsearch.ElasticsearchContainer;
|
||||||
import org.testcontainers.junit.jupiter.Container;
|
import org.testcontainers.junit.jupiter.Container;
|
||||||
import org.testcontainers.junit.jupiter.Testcontainers;
|
import org.testcontainers.junit.jupiter.Testcontainers;
|
||||||
|
import reactor.core.publisher.Mono;
|
||||||
|
|
||||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||||
|
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
|
||||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||||
import org.springframework.boot.testsupport.testcontainers.DockerImageNames;
|
import org.springframework.boot.testsupport.testcontainers.DockerImageNames;
|
||||||
import org.springframework.data.elasticsearch.client.erhlc.ReactiveElasticsearchClient;
|
import org.springframework.data.elasticsearch.client.elc.ReactiveElasticsearchClient;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
@ -39,32 +39,33 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||||
* Integration tests for {@link ReactiveElasticsearchClientAutoConfiguration}.
|
* Integration tests for {@link ReactiveElasticsearchClientAutoConfiguration}.
|
||||||
*
|
*
|
||||||
* @author Brian Clozel
|
* @author Brian Clozel
|
||||||
|
* @author Andy Wilkinson
|
||||||
*/
|
*/
|
||||||
@Testcontainers(disabledWithoutDocker = true)
|
@Testcontainers(disabledWithoutDocker = true)
|
||||||
class ReactiveElasticsearchRestClientAutoConfigurationIntegrationTests {
|
class ReactiveElasticsearchClientAutoConfigurationIntegrationTests {
|
||||||
|
|
||||||
@Container
|
@Container
|
||||||
static ElasticsearchContainer elasticsearch = new ElasticsearchContainer(DockerImageNames.elasticsearch())
|
static ElasticsearchContainer elasticsearch = new ElasticsearchContainer(DockerImageNames.elasticsearch())
|
||||||
.withStartupAttempts(5).withStartupTimeout(Duration.ofMinutes(10));
|
.withStartupAttempts(5).withStartupTimeout(Duration.ofMinutes(10));
|
||||||
|
|
||||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner().withConfiguration(
|
||||||
.withConfiguration(AutoConfigurations.of(ReactiveElasticsearchClientAutoConfiguration.class));
|
AutoConfigurations.of(JacksonAutoConfiguration.class, ElasticsearchRestClientAutoConfiguration.class,
|
||||||
|
ReactiveElasticsearchClientAutoConfiguration.class));
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void restClientCanQueryElasticsearchNode() {
|
void reactiveClientCanQueryElasticsearchNode() {
|
||||||
this.contextRunner
|
this.contextRunner
|
||||||
.withPropertyValues("spring.elasticsearch.uris=" + elasticsearch.getHttpHostAddress(),
|
.withPropertyValues("spring.elasticsearch.uris=" + elasticsearch.getHttpHostAddress(),
|
||||||
"spring.elasticsearch.connection-timeout=120s", "spring.elasticsearch.socket-timeout=120s")
|
"spring.elasticsearch.connection-timeout=120s", "spring.elasticsearch.socket-timeout=120s")
|
||||||
.run((context) -> {
|
.run((context) -> {
|
||||||
ReactiveElasticsearchClient client = context.getBean(ReactiveElasticsearchClient.class);
|
ReactiveElasticsearchClient client = context.getBean(ReactiveElasticsearchClient.class);
|
||||||
Map<String, String> source = new HashMap<>();
|
Mono<IndexResponse> index = client
|
||||||
source.put("a", "alpha");
|
.index((b) -> b.index("foo").id("1").document(Map.of("a", "alpha", "b", "bravo")));
|
||||||
source.put("b", "bravo");
|
index.block();
|
||||||
IndexRequest indexRequest = new IndexRequest("foo").id("1").source(source);
|
Mono<GetResponse<Object>> get = client.get((b) -> b.index("foo").id("1"), Object.class);
|
||||||
GetRequest getRequest = new GetRequest("foo").id("1");
|
GetResponse<Object> response = get.block();
|
||||||
GetResult getResult = client.index(indexRequest).then(client.get(getRequest)).block();
|
assertThat(response).isNotNull();
|
||||||
assertThat(getResult).isNotNull();
|
assertThat(response.found()).isTrue();
|
||||||
assertThat(getResult.isExists()).isTrue();
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,25 +16,14 @@
|
||||||
|
|
||||||
package org.springframework.boot.autoconfigure.elasticsearch;
|
package org.springframework.boot.autoconfigure.elasticsearch;
|
||||||
|
|
||||||
import java.net.InetSocketAddress;
|
import org.elasticsearch.client.RestClient;
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.time.Duration;
|
|
||||||
import java.util.Base64;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.assertj.core.api.InstanceOfAssertFactories;
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.data.elasticsearch.client.ClientConfiguration;
|
import org.springframework.data.elasticsearch.client.elc.ReactiveElasticsearchClient;
|
||||||
import org.springframework.data.elasticsearch.client.ClientConfiguration.ClientConfigurationCallback;
|
|
||||||
import org.springframework.data.elasticsearch.client.erhlc.ReactiveElasticsearchClient;
|
|
||||||
import org.springframework.http.HttpHeaders;
|
|
||||||
import org.springframework.http.codec.CodecConfigurer.DefaultCodecConfig;
|
|
||||||
import org.springframework.web.reactive.function.client.WebClient;
|
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
|
@ -43,6 +32,7 @@ import static org.mockito.Mockito.mock;
|
||||||
* Tests for {@link ReactiveElasticsearchClientAutoConfiguration}.
|
* Tests for {@link ReactiveElasticsearchClientAutoConfiguration}.
|
||||||
*
|
*
|
||||||
* @author Brian Clozel
|
* @author Brian Clozel
|
||||||
|
* @author Andy Wilkinson
|
||||||
*/
|
*/
|
||||||
class ReactiveElasticsearchClientAutoConfigurationTests {
|
class ReactiveElasticsearchClientAutoConfigurationTests {
|
||||||
|
|
||||||
|
@ -50,206 +40,31 @@ class ReactiveElasticsearchClientAutoConfigurationTests {
|
||||||
.withConfiguration(AutoConfigurations.of(ReactiveElasticsearchClientAutoConfiguration.class));
|
.withConfiguration(AutoConfigurations.of(ReactiveElasticsearchClientAutoConfiguration.class));
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void configureShouldCreateDefaultBeans() {
|
void configureWithoutRestClientShouldBackOff() {
|
||||||
this.contextRunner.run((context) -> {
|
this.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(ReactiveElasticsearchClient.class));
|
||||||
assertThat(context).hasSingleBean(ClientConfiguration.class)
|
}
|
||||||
.hasSingleBean(ReactiveElasticsearchClient.class);
|
|
||||||
List<InetSocketAddress> endpoints = context.getBean(ClientConfiguration.class).getEndpoints();
|
@Test
|
||||||
assertThat(endpoints).hasSize(1);
|
void configureWithRestClientShouldCreateTransportAndClient() {
|
||||||
assertThat(endpoints.get(0).getHostString()).isEqualTo("localhost");
|
this.contextRunner.withUserConfiguration(RestClientConfiguration.class)
|
||||||
assertThat(endpoints.get(0).getPort()).isEqualTo(9200);
|
.run((context) -> assertThat(context).hasSingleBean(ReactiveElasticsearchClient.class));
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void configureWhenCustomClientShouldBackOff() {
|
void configureWhenCustomClientShouldBackOff() {
|
||||||
this.contextRunner.withUserConfiguration(CustomClientConfiguration.class).run((context) -> assertThat(context)
|
this.contextRunner.withUserConfiguration(RestClientConfiguration.class, CustomClientConfiguration.class)
|
||||||
.hasSingleBean(ReactiveElasticsearchClient.class).hasBean("customClient"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void configureWhenCustomClientConfig() {
|
|
||||||
this.contextRunner.withUserConfiguration(CustomClientConfigConfiguration.class)
|
|
||||||
.run((context) -> assertThat(context).hasSingleBean(ReactiveElasticsearchClient.class)
|
.run((context) -> assertThat(context).hasSingleBean(ReactiveElasticsearchClient.class)
|
||||||
.hasSingleBean(ClientConfiguration.class).hasBean("customClientConfiguration"));
|
.hasBean("customClient"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Configuration(proxyBeanMethods = false)
|
||||||
void whenUriIsCustomizedThenClientConfigurationHasCustomEndpoint() {
|
static class RestClientConfiguration {
|
||||||
this.contextRunner.withPropertyValues("spring.elasticsearch.uris=http://localhost:9876").run((context) -> {
|
|
||||||
List<InetSocketAddress> endpoints = context.getBean(ClientConfiguration.class).getEndpoints();
|
@Bean
|
||||||
assertThat(endpoints).hasSize(1);
|
RestClient restClient() {
|
||||||
assertThat(endpoints.get(0).getHostString()).isEqualTo("localhost");
|
return mock(RestClient.class);
|
||||||
assertThat(endpoints.get(0).getPort()).isEqualTo(9876);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
void whenUriHasHttpsSchemeThenClientConfigurationUsesSsl() {
|
|
||||||
this.contextRunner.withPropertyValues("spring.elasticsearch.uris=https://localhost:9876").run((context) -> {
|
|
||||||
ClientConfiguration clientConfiguration = context.getBean(ClientConfiguration.class);
|
|
||||||
List<InetSocketAddress> endpoints = clientConfiguration.getEndpoints();
|
|
||||||
assertThat(endpoints).hasSize(1);
|
|
||||||
assertThat(endpoints.get(0).getHostString()).isEqualTo("localhost");
|
|
||||||
assertThat(endpoints.get(0).getPort()).isEqualTo(9876);
|
|
||||||
assertThat(clientConfiguration.useSsl()).isTrue();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void whenMultipleUrisAreConfiguredThenClientConfigurationHasMultipleEndpoints() {
|
|
||||||
this.contextRunner.withPropertyValues("spring.elasticsearch.uris=http://localhost:9876,http://localhost:8765")
|
|
||||||
.run((context) -> {
|
|
||||||
List<InetSocketAddress> endpoints = context.getBean(ClientConfiguration.class).getEndpoints();
|
|
||||||
assertThat(endpoints).hasSize(2);
|
|
||||||
assertThat(endpoints.get(0).getHostString()).isEqualTo("localhost");
|
|
||||||
assertThat(endpoints.get(0).getPort()).isEqualTo(9876);
|
|
||||||
assertThat(endpoints.get(1).getHostString()).isEqualTo("localhost");
|
|
||||||
assertThat(endpoints.get(1).getPort()).isEqualTo(8765);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void whenMultipleUrisHaveHttpsSchemeThenClientConfigurationUsesSsl() {
|
|
||||||
this.contextRunner.withPropertyValues("spring.elasticsearch.uris=https://localhost:9876,https://localhost:8765")
|
|
||||||
.run((context) -> {
|
|
||||||
ClientConfiguration clientConfiguration = context.getBean(ClientConfiguration.class);
|
|
||||||
List<InetSocketAddress> endpoints = clientConfiguration.getEndpoints();
|
|
||||||
assertThat(endpoints).hasSize(2);
|
|
||||||
assertThat(endpoints.get(0).getHostString()).isEqualTo("localhost");
|
|
||||||
assertThat(endpoints.get(0).getPort()).isEqualTo(9876);
|
|
||||||
assertThat(endpoints.get(1).getHostString()).isEqualTo("localhost");
|
|
||||||
assertThat(endpoints.get(1).getPort()).isEqualTo(8765);
|
|
||||||
assertThat(clientConfiguration.useSsl()).isTrue();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void whenMultipleUrisHaveVaryingSchemesThenRunFails() {
|
|
||||||
this.contextRunner.withPropertyValues("spring.elasticsearch.uris=https://localhost:9876,http://localhost:8765")
|
|
||||||
.run((context) -> {
|
|
||||||
assertThat(context).hasFailed();
|
|
||||||
assertThat(context).getFailure().hasRootCauseInstanceOf(IllegalArgumentException.class)
|
|
||||||
.hasRootCauseMessage("Configured Elasticsearch URIs have varying schemes");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void whenUriHasUsernameOnlyThenDefaultAuthorizationHeaderHasUsernameAndEmptyPassword() {
|
|
||||||
this.contextRunner.withPropertyValues("spring.elasticsearch.uris=http://user@localhost:9200").run((context) -> {
|
|
||||||
ClientConfiguration clientConfiguration = context.getBean(ClientConfiguration.class);
|
|
||||||
assertThat(clientConfiguration.getDefaultHeaders().get(HttpHeaders.AUTHORIZATION)).containsExactly(
|
|
||||||
"Basic " + Base64.getEncoder().encodeToString("user:".getBytes(StandardCharsets.UTF_8)));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void whenUriHasUsernameAndPasswordThenDefaultAuthorizationHeaderHasUsernameAndPassword() {
|
|
||||||
this.contextRunner.withPropertyValues("spring.elasticsearch.uris=http://user:secret@localhost:9200")
|
|
||||||
.run((context) -> {
|
|
||||||
ClientConfiguration clientConfiguration = context.getBean(ClientConfiguration.class);
|
|
||||||
assertThat(clientConfiguration.getDefaultHeaders().get(HttpHeaders.AUTHORIZATION))
|
|
||||||
.containsExactly("Basic " + Base64.getEncoder()
|
|
||||||
.encodeToString("user:secret".getBytes(StandardCharsets.UTF_8)));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void whenMultipleUrisHaveVaryingUserInfosThenRunFails() {
|
|
||||||
this.contextRunner
|
|
||||||
.withPropertyValues("spring.elasticsearch.uris=http://user:secret@localhost:9876,http://localhost:8765")
|
|
||||||
.run((context) -> {
|
|
||||||
assertThat(context).hasFailed();
|
|
||||||
assertThat(context).getFailure().hasRootCauseInstanceOf(IllegalArgumentException.class)
|
|
||||||
.hasRootCauseMessage("Configured Elasticsearch URIs have varying user infos");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void whenUriUserInfoMatchesUsernameAndPasswordPropertiesThenDefaultAuthorizationHeaderIsConfigured() {
|
|
||||||
this.contextRunner.withPropertyValues("spring.elasticsearch.uris=http://user:secret@localhost:9876",
|
|
||||||
"spring.elasticsearch.username=user", "spring.elasticsearch.password=secret").run((context) -> {
|
|
||||||
ClientConfiguration clientConfiguration = context.getBean(ClientConfiguration.class);
|
|
||||||
assertThat(clientConfiguration.getDefaultHeaders().get(HttpHeaders.AUTHORIZATION))
|
|
||||||
.containsExactly("Basic " + Base64.getEncoder()
|
|
||||||
.encodeToString("user:secret".getBytes(StandardCharsets.UTF_8)));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void whenUriUserInfoAndUsernameAndPasswordPropertiesDoNotMatchThenRunFails() {
|
|
||||||
this.contextRunner
|
|
||||||
.withPropertyValues("spring.elasticsearch.uris=http://user:secret@localhost:9876",
|
|
||||||
"spring.elasticsearch.username=alice", "spring.elasticsearch.password=confidential")
|
|
||||||
.run((context) -> {
|
|
||||||
assertThat(context).hasFailed();
|
|
||||||
assertThat(context).getFailure().hasRootCauseInstanceOf(IllegalArgumentException.class)
|
|
||||||
.hasRootCauseMessage("Credentials from URI user info do not match those from "
|
|
||||||
+ "spring.elasticsearch.username and spring.elasticsearch.password");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void whenSocketTimeoutIsNotConfiguredThenClientConfigurationUsesDefault() {
|
|
||||||
this.contextRunner.run((context) -> assertThat(context.getBean(ClientConfiguration.class).getSocketTimeout())
|
|
||||||
.isEqualTo(Duration.ofSeconds(30)));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void whenConnectionTimeoutIsNotConfiguredThenClientConfigurationUsesDefault() {
|
|
||||||
this.contextRunner.run((context) -> assertThat(context.getBean(ClientConfiguration.class).getConnectTimeout())
|
|
||||||
.isEqualTo(Duration.ofSeconds(1)));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void whenSocketTimeoutIsConfiguredThenClientConfigurationHasCustomSocketTimeout() {
|
|
||||||
this.contextRunner.withPropertyValues("spring.elasticsearch.socket-timeout=2s")
|
|
||||||
.run((context) -> assertThat(context.getBean(ClientConfiguration.class).getSocketTimeout())
|
|
||||||
.isEqualTo(Duration.ofSeconds(2)));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void whenConnectionTimeoutIsConfiguredThenClientConfigurationHasCustomConnectTimeout() {
|
|
||||||
this.contextRunner.withPropertyValues("spring.elasticsearch.connection-timeout=2s")
|
|
||||||
.run((context) -> assertThat(context.getBean(ClientConfiguration.class).getConnectTimeout())
|
|
||||||
.isEqualTo(Duration.ofSeconds(2)));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void whenPathPrefixIsConfiguredThenClientConfigurationHasPathPrefix() {
|
|
||||||
this.contextRunner.withPropertyValues("spring.elasticsearch.path-prefix=/some/prefix")
|
|
||||||
.run((context) -> assertThat(context.getBean(ClientConfiguration.class).getPathPrefix())
|
|
||||||
.isEqualTo("/some/prefix"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void whenCredentialsAreConfiguredThenClientConfigurationHasDefaultAuthorizationHeader() {
|
|
||||||
this.contextRunner
|
|
||||||
.withPropertyValues("spring.elasticsearch.username=alice", "spring.elasticsearch.password=secret")
|
|
||||||
.run((context) -> assertThat(
|
|
||||||
context.getBean(ClientConfiguration.class).getDefaultHeaders().get(HttpHeaders.AUTHORIZATION))
|
|
||||||
.containsExactly("Basic YWxpY2U6c2VjcmV0"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void whenMaxInMemorySizeIsConfiguredThenUnderlyingWebClientHasCustomMaxInMemorySize() {
|
|
||||||
this.contextRunner.withPropertyValues("spring.elasticsearch.webclient.max-in-memory-size=1MB")
|
|
||||||
.run((context) -> {
|
|
||||||
WebClient client = configureWebClient(
|
|
||||||
context.getBean(ClientConfiguration.class).getClientConfigurers());
|
|
||||||
assertThat(client).extracting("exchangeFunction.strategies.codecConfigurer.defaultCodecs")
|
|
||||||
.asInstanceOf(InstanceOfAssertFactories.type(DefaultCodecConfig.class))
|
|
||||||
.extracting(DefaultCodecConfig::maxInMemorySize).isEqualTo(1024 * 1024);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
private WebClient configureWebClient(List<ClientConfigurationCallback<?>> callbacks) {
|
|
||||||
WebClient webClient = WebClient.create();
|
|
||||||
for (ClientConfigurationCallback<?> callback : callbacks) {
|
|
||||||
webClient = ((ClientConfiguration.ClientConfigurationCallback<WebClient>) callback).configure(webClient);
|
|
||||||
}
|
|
||||||
return webClient;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Configuration(proxyBeanMethods = false)
|
@Configuration(proxyBeanMethods = false)
|
||||||
|
@ -262,14 +77,4 @@ class ReactiveElasticsearchClientAutoConfigurationTests {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Configuration(proxyBeanMethods = false)
|
|
||||||
static class CustomClientConfigConfiguration {
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
ClientConfiguration customClientConfiguration() {
|
|
||||||
return ClientConfiguration.localhost();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,6 @@ import org.springframework.http.converter.StringHttpMessageConverter;
|
||||||
import org.springframework.http.converter.cbor.MappingJackson2CborHttpMessageConverter;
|
import org.springframework.http.converter.cbor.MappingJackson2CborHttpMessageConverter;
|
||||||
import org.springframework.http.converter.json.GsonHttpMessageConverter;
|
import org.springframework.http.converter.json.GsonHttpMessageConverter;
|
||||||
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
|
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
|
||||||
import org.springframework.http.converter.smile.MappingJackson2SmileHttpMessageConverter;
|
|
||||||
import org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter;
|
import org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter;
|
||||||
import org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter;
|
import org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter;
|
||||||
import org.springframework.http.converter.xml.SourceHttpMessageConverter;
|
import org.springframework.http.converter.xml.SourceHttpMessageConverter;
|
||||||
|
@ -58,8 +57,7 @@ class HttpMessageConvertersTests {
|
||||||
StringHttpMessageConverter.class, ResourceHttpMessageConverter.class,
|
StringHttpMessageConverter.class, ResourceHttpMessageConverter.class,
|
||||||
ResourceRegionHttpMessageConverter.class, SourceHttpMessageConverter.class,
|
ResourceRegionHttpMessageConverter.class, SourceHttpMessageConverter.class,
|
||||||
AllEncompassingFormHttpMessageConverter.class, MappingJackson2HttpMessageConverter.class,
|
AllEncompassingFormHttpMessageConverter.class, MappingJackson2HttpMessageConverter.class,
|
||||||
MappingJackson2SmileHttpMessageConverter.class, MappingJackson2CborHttpMessageConverter.class,
|
MappingJackson2CborHttpMessageConverter.class, MappingJackson2XmlHttpMessageConverter.class);
|
||||||
MappingJackson2XmlHttpMessageConverter.class);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -130,7 +128,7 @@ class HttpMessageConvertersTests {
|
||||||
StringHttpMessageConverter.class, ResourceHttpMessageConverter.class,
|
StringHttpMessageConverter.class, ResourceHttpMessageConverter.class,
|
||||||
ResourceRegionHttpMessageConverter.class, SourceHttpMessageConverter.class,
|
ResourceRegionHttpMessageConverter.class, SourceHttpMessageConverter.class,
|
||||||
AllEncompassingFormHttpMessageConverter.class, MappingJackson2HttpMessageConverter.class,
|
AllEncompassingFormHttpMessageConverter.class, MappingJackson2HttpMessageConverter.class,
|
||||||
MappingJackson2SmileHttpMessageConverter.class, MappingJackson2CborHttpMessageConverter.class);
|
MappingJackson2CborHttpMessageConverter.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -151,7 +149,7 @@ class HttpMessageConvertersTests {
|
||||||
}
|
}
|
||||||
assertThat(converterClasses).containsExactly(ByteArrayHttpMessageConverter.class,
|
assertThat(converterClasses).containsExactly(ByteArrayHttpMessageConverter.class,
|
||||||
StringHttpMessageConverter.class, ResourceHttpMessageConverter.class, SourceHttpMessageConverter.class,
|
StringHttpMessageConverter.class, ResourceHttpMessageConverter.class, SourceHttpMessageConverter.class,
|
||||||
MappingJackson2HttpMessageConverter.class, MappingJackson2SmileHttpMessageConverter.class);
|
MappingJackson2HttpMessageConverter.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<HttpMessageConverter<?>> extractFormPartConverters(List<HttpMessageConverter<?>> converters) {
|
private List<HttpMessageConverter<?>> extractFormPartConverters(List<HttpMessageConverter<?>> converters) {
|
||||||
|
|
|
@ -212,34 +212,20 @@ bom {
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
library("Elasticsearch", "7.17.5") {
|
library("Elasticsearch Client", "8.3.2") {
|
||||||
group("org.elasticsearch") {
|
|
||||||
modules = [
|
|
||||||
"elasticsearch"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
group("org.elasticsearch.client") {
|
group("org.elasticsearch.client") {
|
||||||
modules = [
|
modules = [
|
||||||
"transport",
|
|
||||||
"elasticsearch-rest-client" {
|
"elasticsearch-rest-client" {
|
||||||
exclude group: "commons-logging", module: "commons-logging"
|
exclude group: "commons-logging", module: "commons-logging"
|
||||||
},
|
},
|
||||||
"elasticsearch-rest-client-sniffer" {
|
"elasticsearch-rest-client-sniffer" {
|
||||||
exclude group: "commons-logging", module: "commons-logging"
|
exclude group: "commons-logging", module: "commons-logging"
|
||||||
},
|
},
|
||||||
"elasticsearch-rest-high-level-client"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
group("org.elasticsearch.distribution.integ-test-zip") {
|
group("co.elastic.clients") {
|
||||||
modules = [
|
modules = [
|
||||||
"elasticsearch" {
|
"elasticsearch-java"
|
||||||
type = 'zip'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
group("org.elasticsearch.plugin") {
|
|
||||||
modules = [
|
|
||||||
"transport-netty4-client"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -999,3 +999,6 @@ dependency-versions.properties=appendix.dependency-versions.properties
|
||||||
|
|
||||||
# gh-30405
|
# gh-30405
|
||||||
web.servlet.spring-mvc.json=features.json.jackson.custom-serializers-and-deserializers
|
web.servlet.spring-mvc.json=features.json.jackson.custom-serializers-and-deserializers
|
||||||
|
|
||||||
|
# gh-28597
|
||||||
|
data.nosql.elasticsearch.connecting-using-rest.webclient=data.nosql.elasticsearch.connecting-using-rest.reactiveclient
|
||||||
|
|
|
@ -203,7 +203,8 @@ Spring Boot offers basic auto-configuration for Elasticsearch clients.
|
||||||
|
|
||||||
Spring Boot supports several clients:
|
Spring Boot supports several clients:
|
||||||
|
|
||||||
* The official Java "Low Level" and "High Level" REST clients
|
* The official low-level REST client
|
||||||
|
* The official Java API client
|
||||||
* The `ReactiveElasticsearchClient` provided by Spring Data Elasticsearch
|
* The `ReactiveElasticsearchClient` provided by Spring Data Elasticsearch
|
||||||
|
|
||||||
Spring Boot provides a dedicated "`Starter`", `spring-boot-starter-data-elasticsearch`.
|
Spring Boot provides a dedicated "`Starter`", `spring-boot-starter-data-elasticsearch`.
|
||||||
|
@ -212,8 +213,8 @@ Spring Boot provides a dedicated "`Starter`", `spring-boot-starter-data-elastics
|
||||||
|
|
||||||
[[data.nosql.elasticsearch.connecting-using-rest]]
|
[[data.nosql.elasticsearch.connecting-using-rest]]
|
||||||
==== Connecting to Elasticsearch using REST clients
|
==== Connecting to Elasticsearch using REST clients
|
||||||
Elasticsearch ships https://www.elastic.co/guide/en/elasticsearch/client/java-rest/current/index.html[two different REST clients] that you can use to query a cluster: the low-level client from the `org.elasticsearch.client:elasticsearch-rest-client` module and the high-level client from the `org.elasticsearch.client:elasticsearch-high-level-client` module.
|
Elasticsearch ships two different REST clients] that you can use to query a cluster: the https://www.elastic.co/guide/en/elasticsearch/client/java-api-client/current/java-rest-low.html[low-level client] from the `org.elasticsearch.client:elasticsearch-rest-client` module and the https://www.elastic.co/guide/en/elasticsearch/client/java-api-client/current/index.html[Java API client] from the `co.elastic.clients:elasticsearch-java` module.
|
||||||
Additionally, Spring Boot provides support for a reactive client, based on Spring Framework's `WebClient`, from the `org.springframework.data:spring-data-elasticsearch` module.
|
Additionally, Spring Boot provides support for a reactive client from the `org.springframework.data:spring-data-elasticsearch` module.
|
||||||
By default, the clients will target `http://localhost:9200`.
|
By default, the clients will target `http://localhost:9200`.
|
||||||
You can use `spring.elasticsearch.*` properties to further tune how the clients are configured, as shown in the following example:
|
You can use `spring.elasticsearch.*` properties to further tune how the clients are configured, as shown in the following example:
|
||||||
|
|
||||||
|
@ -230,9 +231,7 @@ You can use `spring.elasticsearch.*` properties to further tune how the clients
|
||||||
[[data.nosql.elasticsearch.connecting-using-rest.restclient]]
|
[[data.nosql.elasticsearch.connecting-using-rest.restclient]]
|
||||||
===== Connecting to Elasticsearch using RestClient
|
===== Connecting to Elasticsearch using RestClient
|
||||||
If you have `elasticsearch-rest-client` on the classpath, Spring Boot will auto-configure and register a `RestClient` bean.
|
If you have `elasticsearch-rest-client` on the classpath, Spring Boot will auto-configure and register a `RestClient` bean.
|
||||||
If you have `elasticsearch-rest-high-level-client` on the classpath a `RestHighLevelClient` bean will be auto-configured as well.
|
In addition to the properties described previously, to fine-tune the `RestClient` you can register an arbitrary number of beans that implement `RestClientBuilderCustomizer` for more advanced customizations.
|
||||||
Following Elasticsearch's deprecation of `RestHighLevelClient`, its auto-configuration is deprecated and will be removed in a future release.
|
|
||||||
In addition to the properties described previously, to fine-tune the `RestClient` and `RestHighLevelClient`, you can register an arbitrary number of beans that implement `RestClientBuilderCustomizer` for more advanced customizations.
|
|
||||||
To take full control over the clients' configuration, define a `RestClientBuilder` bean.
|
To take full control over the clients' configuration, define a `RestClientBuilder` bean.
|
||||||
|
|
||||||
|
|
||||||
|
@ -251,38 +250,38 @@ You can further tune how `Sniffer` is configured, as shown in the following exam
|
||||||
----
|
----
|
||||||
|
|
||||||
|
|
||||||
|
[[data.nosql.elasticsearch.connecting-using-rest.javaapiclient]]
|
||||||
|
===== Connecting to Elastixsearch using ElasticsearchClient
|
||||||
|
If you have `co.elastic.clients:elasticsearch-java` on the classpath, Spring Boot will auto-configure and register an `ElasticsearchClient` bean.
|
||||||
|
|
||||||
[[data.nosql.elasticsearch.connecting-using-rest.webclient]]
|
The `ElasticsearchClient` uses a transport that depends upon the previously described `RestClient`.
|
||||||
|
Therefore, the properties described previously can be used to configure the `ElasticsearchClient`.
|
||||||
|
Furthermore, you can define a `TransportOptions` bean to take further control of the behavior of the transport.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[[data.nosql.elasticsearch.connecting-using-rest.reactiveclient]]
|
||||||
===== Connecting to Elasticsearch using ReactiveElasticsearchClient
|
===== Connecting to Elasticsearch using ReactiveElasticsearchClient
|
||||||
{spring-data-elasticsearch}[Spring Data Elasticsearch] ships `ReactiveElasticsearchClient` for querying Elasticsearch instances in a reactive fashion.
|
{spring-data-elasticsearch}[Spring Data Elasticsearch] ships `ReactiveElasticsearchClient` for querying Elasticsearch instances in a reactive fashion.
|
||||||
It is built on top of WebFlux's `WebClient`, so both `spring-boot-starter-elasticsearch` and `spring-boot-starter-webflux` dependencies are useful to enable this support.
|
If you have Spring Data Elasticsearch and Reactor on the classpath, Spring Boot will auto-configure and register a `ReactiveElasticsearchClient`.
|
||||||
|
|
||||||
By default, Spring Boot will auto-configure and register a `ReactiveElasticsearchClient`.
|
The `ReactiveElasticsearchclient` uses a transport that depends upon the previously described `RestClient`.
|
||||||
In addition to the properties described previously, the `spring.elasticsearch.webclient.*` properties can be used to configure reactive-specific settings, as shown in the following example:
|
Therefore, the properties described previously can be used to configure the `ReactiveElasticsearchClient`.
|
||||||
|
Furthermore, you can define a `TransportOptions` bean to take further control of the behavior of the transport.
|
||||||
[source,yaml,indent=0,subs="verbatim",configprops,configblocks]
|
|
||||||
----
|
|
||||||
spring:
|
|
||||||
elasticsearch:
|
|
||||||
webclient:
|
|
||||||
max-in-memory-size: "1MB"
|
|
||||||
----
|
|
||||||
|
|
||||||
If the `spring.elasticsearch.*` and `spring.elasticsearch.webclient.*` configuration properties are not enough and you'd like to fully control the client configuration, you can register a custom `ClientConfiguration` bean.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
[[data.nosql.elasticsearch.connecting-using-spring-data]]
|
[[data.nosql.elasticsearch.connecting-using-spring-data]]
|
||||||
==== Connecting to Elasticsearch by Using Spring Data
|
==== Connecting to Elasticsearch by Using Spring Data
|
||||||
To connect to Elasticsearch, a `RestHighLevelClient` bean must be defined,
|
To connect to Elasticsearch, an `ElasticsearchClient` bean must be defined,
|
||||||
auto-configured by Spring Boot or manually provided by the application (see previous sections).
|
auto-configured by Spring Boot or manually provided by the application (see previous sections).
|
||||||
With this configuration in place, an
|
With this configuration in place, an
|
||||||
`ElasticsearchRestTemplate` can be injected like any other Spring bean,
|
`ElasticsearchTemplate` can be injected like any other Spring bean,
|
||||||
as shown in the following example:
|
as shown in the following example:
|
||||||
|
|
||||||
include::code:MyBean[]
|
include::code:MyBean[]
|
||||||
|
|
||||||
In the presence of `spring-data-elasticsearch` and the required dependencies for using a `WebClient` (typically `spring-boot-starter-webflux`), Spring Boot can also auto-configure a <<features#data.nosql.elasticsearch.connecting-using-rest.webclient,ReactiveElasticsearchClient>> and a `ReactiveElasticsearchTemplate` as beans.
|
In the presence of `spring-data-elasticsearch` and Reactor, Spring Boot can also auto-configure a <<features#data.nosql.elasticsearch.connecting-using-rest.reactiveclient,ReactiveElasticsearchClient>> and a `ReactiveElasticsearchTemplate` as beans.
|
||||||
They are the reactive equivalent of the other REST clients.
|
They are the reactive equivalent of the other REST clients.
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -16,15 +16,15 @@
|
||||||
|
|
||||||
package org.springframework.boot.docs.data.nosql.elasticsearch.connectingusingspringdata;
|
package org.springframework.boot.docs.data.nosql.elasticsearch.connectingusingspringdata;
|
||||||
|
|
||||||
|
import org.springframework.data.elasticsearch.client.elc.ElasticsearchTemplate;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
public class MyBean {
|
public class MyBean {
|
||||||
|
|
||||||
private final org.springframework.data.elasticsearch.client.erhlc.ElasticsearchRestTemplate template;
|
private final ElasticsearchTemplate template;
|
||||||
|
|
||||||
public MyBean(org.springframework.data.elasticsearch.client.erhlc.ElasticsearchRestTemplate template) {
|
public MyBean(ElasticsearchTemplate template) {
|
||||||
this.template = template;
|
this.template = template;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -101,11 +101,6 @@ dependencies {
|
||||||
testImplementation("org.testcontainers:neo4j")
|
testImplementation("org.testcontainers:neo4j")
|
||||||
testImplementation("org.testcontainers:testcontainers")
|
testImplementation("org.testcontainers:testcontainers")
|
||||||
testImplementation("org.thymeleaf:thymeleaf")
|
testImplementation("org.thymeleaf:thymeleaf")
|
||||||
|
|
||||||
testRuntimeOnly("org.elasticsearch:elasticsearch")
|
|
||||||
testRuntimeOnly("org.elasticsearch.client:elasticsearch-rest-high-level-client") {
|
|
||||||
exclude group: "commons-logging", module: "commons-logging"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
configurations {
|
configurations {
|
||||||
|
|
|
@ -2,5 +2,8 @@
|
||||||
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfiguration
|
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfiguration
|
||||||
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration
|
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration
|
||||||
org.springframework.boot.autoconfigure.data.elasticsearch.ReactiveElasticsearchRepositoriesAutoConfiguration
|
org.springframework.boot.autoconfigure.data.elasticsearch.ReactiveElasticsearchRepositoriesAutoConfiguration
|
||||||
|
org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchClientAutoConfiguration
|
||||||
org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchRestClientAutoConfiguration
|
org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchRestClientAutoConfiguration
|
||||||
org.springframework.boot.autoconfigure.elasticsearch.ReactiveElasticsearchClientAutoConfiguration
|
org.springframework.boot.autoconfigure.elasticsearch.ReactiveElasticsearchClientAutoConfiguration
|
||||||
|
org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration
|
||||||
|
org.springframework.boot.autoconfigure.jsonb.JsonbAutoConfiguration
|
||||||
|
|
|
@ -28,6 +28,7 @@ import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.testsupport.testcontainers.DockerImageNames;
|
import org.springframework.boot.testsupport.testcontainers.DockerImageNames;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
|
import org.springframework.data.elasticsearch.client.elc.ElasticsearchTemplate;
|
||||||
import org.springframework.test.context.DynamicPropertyRegistry;
|
import org.springframework.test.context.DynamicPropertyRegistry;
|
||||||
import org.springframework.test.context.DynamicPropertySource;
|
import org.springframework.test.context.DynamicPropertySource;
|
||||||
|
|
||||||
|
@ -53,8 +54,7 @@ class DataElasticsearchTestIntegrationTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
@SuppressWarnings("deprecation")
|
private ElasticsearchTemplate elasticsearchTemplate;
|
||||||
private org.springframework.data.elasticsearch.client.erhlc.ElasticsearchRestTemplate elasticsearchRestTemplate;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private ExampleRepository exampleRepository;
|
private ExampleRepository exampleRepository;
|
||||||
|
@ -75,7 +75,7 @@ class DataElasticsearchTestIntegrationTests {
|
||||||
String id = UUID.randomUUID().toString();
|
String id = UUID.randomUUID().toString();
|
||||||
document.setId(id);
|
document.setId(id);
|
||||||
ExampleDocument savedDocument = this.exampleRepository.save(document);
|
ExampleDocument savedDocument = this.exampleRepository.save(document);
|
||||||
ExampleDocument getDocument = this.elasticsearchRestTemplate.get(id, ExampleDocument.class);
|
ExampleDocument getDocument = this.elasticsearchTemplate.get(id, ExampleDocument.class);
|
||||||
assertThat(getDocument).isNotNull();
|
assertThat(getDocument).isNotNull();
|
||||||
assertThat(getDocument.getId()).isNotNull();
|
assertThat(getDocument.getId()).isNotNull();
|
||||||
assertThat(getDocument.getId()).isEqualTo(savedDocument.getId());
|
assertThat(getDocument.getId()).isEqualTo(savedDocument.getId());
|
||||||
|
|
|
@ -25,6 +25,7 @@ import org.testcontainers.junit.jupiter.Testcontainers;
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.testsupport.testcontainers.DockerImageNames;
|
import org.springframework.boot.testsupport.testcontainers.DockerImageNames;
|
||||||
|
import org.springframework.data.elasticsearch.client.elc.ReactiveElasticsearchTemplate;
|
||||||
import org.springframework.test.context.DynamicPropertyRegistry;
|
import org.springframework.test.context.DynamicPropertyRegistry;
|
||||||
import org.springframework.test.context.DynamicPropertySource;
|
import org.springframework.test.context.DynamicPropertySource;
|
||||||
|
|
||||||
|
@ -50,8 +51,7 @@ class DataElasticsearchTestReactiveIntegrationTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
@SuppressWarnings("deprecation")
|
private ReactiveElasticsearchTemplate elasticsearchTemplate;
|
||||||
private org.springframework.data.elasticsearch.client.erhlc.ReactiveElasticsearchTemplate elasticsearchTemplate;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private ExampleReactiveRepository exampleReactiveRepository;
|
private ExampleReactiveRepository exampleReactiveRepository;
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
package org.springframework.boot.test.autoconfigure.data.elasticsearch;
|
package org.springframework.boot.test.autoconfigure.data.elasticsearch;
|
||||||
|
|
||||||
|
import org.springframework.data.elasticsearch.client.elc.ElasticsearchTemplate;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -24,18 +25,16 @@ import org.springframework.stereotype.Service;
|
||||||
* @author Eddú Meléndez
|
* @author Eddú Meléndez
|
||||||
*/
|
*/
|
||||||
@Service
|
@Service
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
public class ExampleService {
|
public class ExampleService {
|
||||||
|
|
||||||
private final org.springframework.data.elasticsearch.client.erhlc.ElasticsearchRestTemplate elasticsearchRestTemplate;
|
private final ElasticsearchTemplate elasticsearchTemplate;
|
||||||
|
|
||||||
public ExampleService(
|
public ExampleService(ElasticsearchTemplate elasticsearchRestTemplate) {
|
||||||
org.springframework.data.elasticsearch.client.erhlc.ElasticsearchRestTemplate elasticsearchRestTemplate) {
|
this.elasticsearchTemplate = elasticsearchRestTemplate;
|
||||||
this.elasticsearchRestTemplate = elasticsearchRestTemplate;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ExampleDocument findById(String id) {
|
public ExampleDocument findById(String id) {
|
||||||
return this.elasticsearchRestTemplate.get(id, ExampleDocument.class);
|
return this.elasticsearchTemplate.get(id, ExampleDocument.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,6 @@ dependencies {
|
||||||
}
|
}
|
||||||
compileOnly("jakarta.servlet:jakarta.servlet-api")
|
compileOnly("jakarta.servlet:jakarta.servlet-api")
|
||||||
compileOnly("junit:junit")
|
compileOnly("junit:junit")
|
||||||
compileOnly("org.elasticsearch:elasticsearch")
|
|
||||||
compileOnly("org.junit.jupiter:junit-jupiter")
|
compileOnly("org.junit.jupiter:junit-jupiter")
|
||||||
compileOnly("org.junit.platform:junit-platform-engine")
|
compileOnly("org.junit.platform:junit-platform-engine")
|
||||||
compileOnly("org.junit.platform:junit-platform-launcher")
|
compileOnly("org.junit.platform:junit-platform-launcher")
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2012-2021 the original author or authors.
|
* Copyright 2012-2022 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -30,6 +30,8 @@ public final class DockerImageNames {
|
||||||
|
|
||||||
private static final String COUCHBASE_VERSION = "6.5.1";
|
private static final String COUCHBASE_VERSION = "6.5.1";
|
||||||
|
|
||||||
|
private static final String ELASTICSEARCH_VERSION = "7.17.5";
|
||||||
|
|
||||||
private static final String MONGO_VERSION = "4.0.23";
|
private static final String MONGO_VERSION = "4.0.23";
|
||||||
|
|
||||||
private static final String NEO4J_VERSION = "4.0";
|
private static final String NEO4J_VERSION = "4.0";
|
||||||
|
@ -60,13 +62,11 @@ public final class DockerImageNames {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a {@link DockerImageName} suitable for running Elasticsearch according to
|
* Return a {@link DockerImageName} suitable for running Elasticsearch.
|
||||||
* the version available on the classpath.
|
|
||||||
* @return a docker image name for running elasticsearch
|
* @return a docker image name for running elasticsearch
|
||||||
*/
|
*/
|
||||||
public static DockerImageName elasticsearch() {
|
public static DockerImageName elasticsearch() {
|
||||||
String version = org.elasticsearch.Version.CURRENT.toString();
|
return DockerImageName.parse("docker.elastic.co/elasticsearch/elasticsearch").withTag(ELASTICSEARCH_VERSION);
|
||||||
return DockerImageName.parse("docker.elastic.co/elasticsearch/elasticsearch").withTag(version);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue