diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/elasticsearch/ElasticsearchDataAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/elasticsearch/ElasticsearchDataAutoConfiguration.java
index bea89b82fc6..8cf642bfdd8 100644
--- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/elasticsearch/ElasticsearchDataAutoConfiguration.java
+++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/elasticsearch/ElasticsearchDataAutoConfiguration.java
@@ -24,27 +24,30 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.repository.config.EnableElasticsearchRepositories;
+import org.springframework.data.elasticsearch.repository.config.EnableReactiveElasticsearchRepositories;
/**
* {@link EnableAutoConfiguration Auto-configuration} for Spring Data's Elasticsearch
* support.
*
- * Registers an {@link ElasticsearchTemplate} if no other bean of the same type is
- * configured.
+ * Registers an {@link ElasticsearchTemplate} if no other bean of the same type and the
+ * same name {@code "elasticsearchTemplate"} is configured.
*
* @author Brian Clozel
* @author Artur Konczak
* @author Mohsin Husen
* @see EnableElasticsearchRepositories
+ * @see EnableReactiveElasticsearchRepositories
* @since 1.1.0
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ ElasticsearchTemplate.class })
@AutoConfigureAfter({ ElasticsearchAutoConfiguration.class,
- RestClientAutoConfiguration.class })
+ RestClientAutoConfiguration.class, ReactiveRestClientAutoConfiguration.class })
@Import({ ElasticsearchDataConfiguration.BaseConfiguration.class,
ElasticsearchDataConfiguration.TransportClientConfiguration.class,
- ElasticsearchDataConfiguration.RestHighLevelClientConfiguration.class })
+ ElasticsearchDataConfiguration.RestClientConfiguration.class,
+ ElasticsearchDataConfiguration.ReactiveRestClientConfiguration.class })
public class ElasticsearchDataAutoConfiguration {
}
diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/elasticsearch/ElasticsearchDataConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/elasticsearch/ElasticsearchDataConfiguration.java
index e9dda9b14b9..4848eb74e1c 100644
--- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/elasticsearch/ElasticsearchDataConfiguration.java
+++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/elasticsearch/ElasticsearchDataConfiguration.java
@@ -16,6 +16,8 @@
package org.springframework.boot.autoconfigure.data.elasticsearch;
+import org.elasticsearch.action.support.IndicesOptions;
+import org.elasticsearch.action.support.WriteRequest;
import org.elasticsearch.client.Client;
import org.elasticsearch.client.RestHighLevelClient;
@@ -24,12 +26,20 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
+import org.springframework.data.elasticsearch.client.reactive.ReactiveElasticsearchClient;
+import org.springframework.data.elasticsearch.core.DefaultEntityMapper;
+import org.springframework.data.elasticsearch.core.DefaultResultMapper;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
+import org.springframework.data.elasticsearch.core.EntityMapper;
+import org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperations;
+import org.springframework.data.elasticsearch.core.ReactiveElasticsearchTemplate;
+import org.springframework.data.elasticsearch.core.ResultsMapper;
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
import org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter;
import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchMappingContext;
+import org.springframework.web.reactive.function.client.WebClient;
/**
* Configuration classes for Spring Data for Elasticsearch
@@ -57,19 +67,33 @@ abstract class ElasticsearchDataConfiguration {
return new SimpleElasticsearchMappingContext();
}
+ @Bean
+ public EntityMapper entityMapper(
+ SimpleElasticsearchMappingContext mappingContext) {
+ return new DefaultEntityMapper(mappingContext);
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ public ResultsMapper resultsMapper(
+ SimpleElasticsearchMappingContext mappingContext,
+ EntityMapper entityMapper) {
+ return new DefaultResultMapper(mappingContext, entityMapper);
+ }
+
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(RestHighLevelClient.class)
- static class RestHighLevelClientConfiguration {
+ static class RestClientConfiguration {
@Bean
@ConditionalOnMissingBean(value = ElasticsearchOperations.class,
name = "elasticsearchTemplate")
@ConditionalOnBean(RestHighLevelClient.class)
public ElasticsearchRestTemplate elasticsearchTemplate(RestHighLevelClient client,
- ElasticsearchConverter converter) {
- return new ElasticsearchRestTemplate(client, converter);
+ ElasticsearchConverter converter, ResultsMapper resultsMapper) {
+ return new ElasticsearchRestTemplate(client, converter, resultsMapper);
}
}
@@ -83,9 +107,9 @@ abstract class ElasticsearchDataConfiguration {
name = "elasticsearchTemplate")
@ConditionalOnBean(Client.class)
public ElasticsearchTemplate elasticsearchTemplate(Client client,
- ElasticsearchConverter converter) {
+ ElasticsearchConverter converter, ResultsMapper resultsMapper) {
try {
- return new ElasticsearchTemplate(client, converter);
+ return new ElasticsearchTemplate(client, converter, resultsMapper);
}
catch (Exception ex) {
throw new IllegalStateException(ex);
@@ -94,4 +118,24 @@ abstract class ElasticsearchDataConfiguration {
}
+ @Configuration(proxyBeanMethods = false)
+ @ConditionalOnClass({ WebClient.class, ReactiveElasticsearchOperations.class })
+ static class ReactiveRestClientConfiguration {
+
+ @Bean
+ @ConditionalOnMissingBean(value = ReactiveElasticsearchOperations.class,
+ name = "reactiveElasticsearchTemplate")
+ @ConditionalOnBean(ReactiveElasticsearchClient.class)
+ public ReactiveElasticsearchTemplate reactiveElasticsearchTemplate(
+ ReactiveElasticsearchClient client, ElasticsearchConverter converter,
+ ResultsMapper resultsMapper) {
+ ReactiveElasticsearchTemplate template = new ReactiveElasticsearchTemplate(
+ client, converter, resultsMapper);
+ template.setIndicesOptions(IndicesOptions.strictExpandOpenAndForbidClosed());
+ template.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
+ return template;
+ }
+
+ }
+
}
diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/elasticsearch/ReactiveElasticsearchRepositoriesAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/elasticsearch/ReactiveElasticsearchRepositoriesAutoConfiguration.java
new file mode 100644
index 00000000000..811fc463f63
--- /dev/null
+++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/elasticsearch/ReactiveElasticsearchRepositoriesAutoConfiguration.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2012-2019 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.data.elasticsearch;
+
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Import;
+import org.springframework.data.elasticsearch.client.reactive.ReactiveElasticsearchClient;
+import org.springframework.data.elasticsearch.repository.ReactiveElasticsearchRepository;
+import org.springframework.data.elasticsearch.repository.config.EnableReactiveElasticsearchRepositories;
+import org.springframework.data.elasticsearch.repository.support.ReactiveElasticsearchRepositoryFactoryBean;
+
+/**
+ * {@link EnableAutoConfiguration Auto-configuration} for Spring Data's Elasticsearch
+ * Reactive Repositories.
+ *
+ * @author Brian Clozel
+ * @see EnableReactiveElasticsearchRepositories
+ * @since 2.2.0
+ */
+@Configuration(proxyBeanMethods = false)
+@ConditionalOnClass({ ReactiveElasticsearchClient.class,
+ ReactiveElasticsearchRepository.class })
+@ConditionalOnProperty(prefix = "spring.data.elasticsearch.repositories",
+ name = "enabled", havingValue = "true", matchIfMissing = true)
+@ConditionalOnMissingBean(ReactiveElasticsearchRepositoryFactoryBean.class)
+@Import(ReactiveElasticsearchRepositoriesRegistrar.class)
+public class ReactiveElasticsearchRepositoriesAutoConfiguration {
+
+}
diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/elasticsearch/ReactiveElasticsearchRepositoriesRegistrar.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/elasticsearch/ReactiveElasticsearchRepositoriesRegistrar.java
new file mode 100644
index 00000000000..c7bcfa8b416
--- /dev/null
+++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/elasticsearch/ReactiveElasticsearchRepositoriesRegistrar.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2012-2019 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.data.elasticsearch;
+
+import java.lang.annotation.Annotation;
+
+import org.springframework.boot.autoconfigure.data.AbstractRepositoryConfigurationSourceSupport;
+import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
+import org.springframework.data.elasticsearch.repository.config.EnableReactiveElasticsearchRepositories;
+import org.springframework.data.elasticsearch.repository.config.ReactiveElasticsearchRepositoryConfigurationExtension;
+import org.springframework.data.repository.config.RepositoryConfigurationExtension;
+
+/**
+ * {@link ImportBeanDefinitionRegistrar} used to auto-configure Spring Data Elasticsearch
+ * Reactive Repositories.
+ *
+ * @author Brian Clozel
+ * @since 2.2.0
+ */
+class ReactiveElasticsearchRepositoriesRegistrar
+ extends AbstractRepositoryConfigurationSourceSupport {
+
+ @Override
+ protected Class extends Annotation> getAnnotation() {
+ return EnableReactiveElasticsearchRepositories.class;
+ }
+
+ @Override
+ protected Class> getConfiguration() {
+ return EnableElasticsearchRepositoriesConfiguration.class;
+ }
+
+ @Override
+ protected RepositoryConfigurationExtension getRepositoryConfigurationExtension() {
+ return new ReactiveElasticsearchRepositoryConfigurationExtension();
+ }
+
+ @EnableReactiveElasticsearchRepositories
+ private static class EnableElasticsearchRepositoriesConfiguration {
+
+ }
+
+}
diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/elasticsearch/ReactiveRestClientAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/elasticsearch/ReactiveRestClientAutoConfiguration.java
new file mode 100644
index 00000000000..26a95f17ee8
--- /dev/null
+++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/elasticsearch/ReactiveRestClientAutoConfiguration.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2012-2019 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.data.elasticsearch;
+
+import reactor.netty.http.client.HttpClient;
+
+import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
+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.Configuration;
+import org.springframework.data.elasticsearch.client.ClientConfiguration;
+import org.springframework.data.elasticsearch.client.reactive.ReactiveElasticsearchClient;
+import org.springframework.data.elasticsearch.client.reactive.ReactiveRestClients;
+import org.springframework.http.HttpHeaders;
+import org.springframework.web.reactive.function.client.WebClient;
+
+/**
+ * {@link EnableAutoConfiguration Auto-configuration} for Elasticsearch Reactive REST
+ * clients.
+ *
+ * @author Brian Clozel
+ * @since 2.2.0
+ */
+@Configuration(proxyBeanMethods = false)
+@ConditionalOnClass({ ReactiveRestClients.class, WebClient.class, HttpClient.class })
+@EnableConfigurationProperties(ReactiveRestClientProperties.class)
+public class ReactiveRestClientAutoConfiguration {
+
+ @Bean
+ @ConditionalOnMissingBean
+ public ClientConfiguration clientConfiguration(
+ ReactiveRestClientProperties properties) {
+ ClientConfiguration.MaybeSecureClientConfigurationBuilder builder = ClientConfiguration
+ .builder().connectedTo(properties.getEndpoints().toArray(new String[0]));
+ if (properties.isUseSsl()) {
+ builder.usingSsl();
+ }
+ configureTimeouts(builder, properties);
+ return builder.build();
+ }
+
+ private void configureTimeouts(
+ ClientConfiguration.TerminalClientConfigurationBuilder builder,
+ ReactiveRestClientProperties properties) {
+ PropertyMapper map = PropertyMapper.get();
+ map.from(properties.getConnectionTimeout()).whenNonNull()
+ .to(builder::withConnectTimeout);
+ map.from(properties.getSocketTimeout()).whenNonNull()
+ .to(builder::withSocketTimeout);
+ map.from(properties.getUsername()).whenHasText().to((username) -> {
+ HttpHeaders headers = new HttpHeaders();
+ headers.setBasicAuth(username, properties.getPassword());
+ builder.withDefaultHeaders(headers);
+ });
+ }
+
+ @Bean
+ @ConditionalOnMissingBean
+ public ReactiveElasticsearchClient reactiveElasticsearchClient(
+ ClientConfiguration clientConfiguration) {
+ return ReactiveRestClients.create(clientConfiguration);
+ }
+
+}
diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/elasticsearch/ReactiveRestClientProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/elasticsearch/ReactiveRestClientProperties.java
new file mode 100644
index 00000000000..e322db33565
--- /dev/null
+++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/elasticsearch/ReactiveRestClientProperties.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2012-2019 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.data.elasticsearch;
+
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+/**
+ * Configuration properties for Elasticsearch Reactive REST clients.
+ *
+ * @author Brian Clozel
+ * @since 2.2.0
+ */
+@ConfigurationProperties(prefix = "spring.data.elasticsearch.client.reactive")
+public class ReactiveRestClientProperties {
+
+ /**
+ * Comma-separated list of the Elasticsearch endpoints to connect to.
+ */
+ private List endpoints = new ArrayList<>(
+ Collections.singletonList("localhost:9200"));
+
+ /**
+ * Whether the client should use SSL to connect to the endpoints.
+ */
+ private boolean useSsl = false;
+
+ /**
+ * Credentials username.
+ */
+ private String username;
+
+ /**
+ * Credentials password.
+ */
+ private String password;
+
+ /**
+ * Connection timeout.
+ */
+ private Duration connectionTimeout;
+
+ /**
+ * Read and Write Socket timeout.
+ */
+ private Duration socketTimeout;
+
+ public List getEndpoints() {
+ return this.endpoints;
+ }
+
+ public void setEndpoints(List endpoints) {
+ this.endpoints = endpoints;
+ }
+
+ public boolean isUseSsl() {
+ return this.useSsl;
+ }
+
+ public void setUseSsl(boolean useSsl) {
+ this.useSsl = useSsl;
+ }
+
+ public String getUsername() {
+ return this.username;
+ }
+
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ public String getPassword() {
+ return this.password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ public Duration getConnectionTimeout() {
+ return this.connectionTimeout;
+ }
+
+ public void setConnectionTimeout(Duration connectionTimeout) {
+ this.connectionTimeout = connectionTimeout;
+ }
+
+ public Duration getSocketTimeout() {
+ return this.socketTimeout;
+ }
+
+ public void setSocketTimeout(Duration socketTimeout) {
+ this.socketTimeout = socketTimeout;
+ }
+
+}
diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/elasticsearch/package-info.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/elasticsearch/package-info.java
index c27a1ccdb46..0796afa2183 100644
--- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/elasticsearch/package-info.java
+++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/elasticsearch/package-info.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2012-2017 the original author or authors.
+ * Copyright 2012-2019 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.
diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories
index 55165252981..91f0a509656 100644
--- a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories
+++ b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories
@@ -42,6 +42,8 @@ org.springframework.boot.autoconfigure.data.couchbase.CouchbaseRepositoriesAutoC
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfiguration,\
+org.springframework.boot.autoconfigure.data.elasticsearch.ReactiveElasticsearchRepositoriesAutoConfiguration,\
+org.springframework.boot.autoconfigure.data.elasticsearch.ReactiveRestClientAutoConfiguration,\
org.springframework.boot.autoconfigure.data.jdbc.JdbcRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.ldap.LdapRepositoriesAutoConfiguration,\
diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/alt/elasticsearch/CityReactiveElasticsearchDbRepository.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/alt/elasticsearch/CityReactiveElasticsearchDbRepository.java
new file mode 100644
index 00000000000..a216b15e851
--- /dev/null
+++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/alt/elasticsearch/CityReactiveElasticsearchDbRepository.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2012-2019 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.data.alt.elasticsearch;
+
+import org.springframework.boot.autoconfigure.data.elasticsearch.city.City;
+import org.springframework.data.elasticsearch.repository.ReactiveElasticsearchRepository;
+
+public interface CityReactiveElasticsearchDbRepository
+ extends ReactiveElasticsearchRepository {
+
+}
diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/elasticsearch/ElasticsearchAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/elasticsearch/ElasticsearchAutoConfigurationTests.java
index ac8f9f0ece1..9e61ac08b9d 100644
--- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/elasticsearch/ElasticsearchAutoConfigurationTests.java
+++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/elasticsearch/ElasticsearchAutoConfigurationTests.java
@@ -41,7 +41,6 @@ import static org.mockito.Mockito.mock;
* @author Phillip Webb
* @author Andy Wilkinson
*/
-@Deprecated
@Testcontainers
public class ElasticsearchAutoConfigurationTests {
diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/elasticsearch/ElasticsearchDataAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/elasticsearch/ElasticsearchDataAutoConfigurationTests.java
index 520c1b943a9..0c2ead20e8f 100644
--- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/elasticsearch/ElasticsearchDataAutoConfigurationTests.java
+++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/elasticsearch/ElasticsearchDataAutoConfigurationTests.java
@@ -28,6 +28,8 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
+import org.springframework.data.elasticsearch.core.EntityMapper;
+import org.springframework.data.elasticsearch.core.ReactiveElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchMappingContext;
@@ -50,6 +52,7 @@ public class ElasticsearchDataAutoConfigurationTests {
private ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(ElasticsearchAutoConfiguration.class,
RestClientAutoConfiguration.class,
+ ReactiveRestClientAutoConfiguration.class,
ElasticsearchDataAutoConfiguration.class));
@Test
@@ -75,6 +78,10 @@ public class ElasticsearchDataAutoConfigurationTests {
public void defaultRestBeansRegistered() {
this.contextRunner.run((context) -> assertThat(context)
.hasSingleBean(ElasticsearchRestTemplate.class)
+ .hasSingleBean(ReactiveElasticsearchTemplate.class)
+ .hasSingleBean(ElasticsearchConverter.class)
+ .hasSingleBean(SimpleElasticsearchMappingContext.class)
+ .hasSingleBean(EntityMapper.class)
.hasSingleBean(ElasticsearchConverter.class));
}
@@ -94,6 +101,14 @@ public class ElasticsearchDataAutoConfigurationTests {
.contains("elasticsearchTemplate"));
}
+ @Test
+ public void customReactiveRestTemplateShouldBeUsed() {
+ this.contextRunner.withUserConfiguration(CustomReactiveRestTemplate.class)
+ .run((context) -> assertThat(context)
+ .getBeanNames(ReactiveElasticsearchTemplate.class).hasSize(1)
+ .contains("reactiveElasticsearchTemplate"));
+ }
+
@Configuration
static class CustomTransportTemplate {
@@ -114,4 +129,14 @@ public class ElasticsearchDataAutoConfigurationTests {
}
+ @Configuration
+ static class CustomReactiveRestTemplate {
+
+ @Bean
+ ReactiveElasticsearchTemplate reactiveElasticsearchTemplate() {
+ return mock(ReactiveElasticsearchTemplate.class);
+ }
+
+ }
+
}
diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/elasticsearch/ReactiveElasticsearchRepositoriesAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/elasticsearch/ReactiveElasticsearchRepositoriesAutoConfigurationTests.java
new file mode 100644
index 00000000000..b2183d75110
--- /dev/null
+++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/elasticsearch/ReactiveElasticsearchRepositoriesAutoConfigurationTests.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2012-2019 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.data.elasticsearch;
+
+import org.junit.jupiter.api.Test;
+import org.testcontainers.junit.jupiter.Container;
+import org.testcontainers.junit.jupiter.Testcontainers;
+
+import org.springframework.boot.autoconfigure.AutoConfigurations;
+import org.springframework.boot.autoconfigure.TestAutoConfigurationPackage;
+import org.springframework.boot.autoconfigure.data.alt.elasticsearch.CityReactiveElasticsearchDbRepository;
+import org.springframework.boot.autoconfigure.data.elasticsearch.city.City;
+import org.springframework.boot.autoconfigure.data.elasticsearch.city.ReactiveCityRepository;
+import org.springframework.boot.autoconfigure.data.empty.EmptyDataPackage;
+import org.springframework.boot.test.context.runner.ApplicationContextRunner;
+import org.springframework.boot.testsupport.testcontainers.ElasticsearchContainer;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.elasticsearch.core.ReactiveElasticsearchTemplate;
+import org.springframework.data.elasticsearch.repository.config.EnableReactiveElasticsearchRepositories;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Tests for {@link ReactiveElasticsearchRepositoriesAutoConfiguration}.
+ *
+ * @author Phillip Webb
+ * @author Andy Wilkinson
+ * @author Brian Clozel
+ */
+@Testcontainers
+public class ReactiveElasticsearchRepositoriesAutoConfigurationTests {
+
+ @Container
+ public static ElasticsearchContainer elasticsearch = new ElasticsearchContainer();
+
+ private ApplicationContextRunner contextRunner = new ApplicationContextRunner()
+ .withConfiguration(
+ AutoConfigurations.of(ReactiveRestClientAutoConfiguration.class,
+ ReactiveElasticsearchRepositoriesAutoConfiguration.class,
+ ElasticsearchDataAutoConfiguration.class))
+ .withPropertyValues(
+ "spring.data.elasticsearch.client.reactive.endpoints=localhost:"
+ + elasticsearch.getMappedHttpPort());
+
+ @Test
+ public void testDefaultRepositoryConfiguration() {
+ this.contextRunner.withUserConfiguration(TestConfiguration.class)
+ .run((context) -> assertThat(context)
+ .hasSingleBean(ReactiveCityRepository.class)
+ .hasSingleBean(ReactiveElasticsearchTemplate.class));
+ }
+
+ @Test
+ public void testNoRepositoryConfiguration() {
+ this.contextRunner.withUserConfiguration(EmptyConfiguration.class)
+ .run((context) -> assertThat(context)
+ .hasSingleBean(ReactiveElasticsearchTemplate.class));
+ }
+
+ @Test
+ public void doesNotTriggerDefaultRepositoryDetectionIfCustomized() {
+ this.contextRunner.withUserConfiguration(CustomizedConfiguration.class)
+ .run((context) -> assertThat(context)
+ .hasSingleBean(CityReactiveElasticsearchDbRepository.class));
+ }
+
+ @Configuration(proxyBeanMethods = false)
+ @TestAutoConfigurationPackage(City.class)
+ static class TestConfiguration {
+
+ }
+
+ @Configuration(proxyBeanMethods = false)
+ @TestAutoConfigurationPackage(EmptyDataPackage.class)
+ static class EmptyConfiguration {
+
+ }
+
+ @Configuration(proxyBeanMethods = false)
+ @TestAutoConfigurationPackage(ReactiveElasticsearchRepositoriesAutoConfigurationTests.class)
+ @EnableReactiveElasticsearchRepositories(
+ basePackageClasses = CityReactiveElasticsearchDbRepository.class)
+ static class CustomizedConfiguration {
+
+ }
+
+}
diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/elasticsearch/ReactiveRestClientAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/elasticsearch/ReactiveRestClientAutoConfigurationTests.java
new file mode 100644
index 00000000000..b11e5343a1e
--- /dev/null
+++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/elasticsearch/ReactiveRestClientAutoConfigurationTests.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2012-2019 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.data.elasticsearch;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.elasticsearch.action.get.GetRequest;
+import org.elasticsearch.action.index.IndexRequest;
+import org.elasticsearch.index.get.GetResult;
+import org.junit.jupiter.api.Test;
+import org.testcontainers.junit.jupiter.Container;
+import org.testcontainers.junit.jupiter.Testcontainers;
+
+import org.springframework.boot.autoconfigure.AutoConfigurations;
+import org.springframework.boot.test.context.runner.ApplicationContextRunner;
+import org.springframework.boot.testsupport.testcontainers.ElasticsearchContainer;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.elasticsearch.client.ClientConfiguration;
+import org.springframework.data.elasticsearch.client.reactive.ReactiveElasticsearchClient;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+
+/**
+ * Tests for {@link ReactiveRestClientAutoConfiguration}
+ *
+ * @author Brian Clozel
+ */
+@Testcontainers
+public class ReactiveRestClientAutoConfigurationTests {
+
+ @Container
+ public static ElasticsearchContainer elasticsearch = new ElasticsearchContainer();
+
+ private ApplicationContextRunner contextRunner = new ApplicationContextRunner()
+ .withConfiguration(
+ AutoConfigurations.of(ReactiveRestClientAutoConfiguration.class));
+
+ @Test
+ public void configureShouldCreateDefaultBeans() {
+ this.contextRunner.run(
+ (context) -> assertThat(context).hasSingleBean(ClientConfiguration.class)
+ .hasSingleBean(ReactiveElasticsearchClient.class));
+ }
+
+ @Test
+ public void configureWhenCustomClientShouldBackOff() {
+ this.contextRunner.withUserConfiguration(CustomClientConfiguration.class)
+ .run((context) -> assertThat(context)
+ .hasSingleBean(ReactiveElasticsearchClient.class)
+ .hasBean("customClient"));
+ }
+
+ @Test
+ public void configureWhenCustomClientConfig() {
+ this.contextRunner.withUserConfiguration(CustomClientConfigConfiguration.class)
+ .run((context) -> assertThat(context)
+ .hasSingleBean(ReactiveElasticsearchClient.class)
+ .hasSingleBean(ClientConfiguration.class)
+ .hasBean("customClientConfiguration"));
+ }
+
+ @Test
+ public void restClientCanQueryElasticsearchNode() {
+ this.contextRunner.withPropertyValues(
+ "spring.data.elasticsearch.client.reactive.endpoints=localhost:"
+ + elasticsearch.getMappedPort())
+ .run((context) -> {
+ ReactiveElasticsearchClient client = context
+ .getBean(ReactiveElasticsearchClient.class);
+ Map source = new HashMap<>();
+ source.put("a", "alpha");
+ source.put("b", "bravo");
+ IndexRequest index = new IndexRequest("foo", "bar", "1")
+ .source(source);
+ GetRequest getRequest = new GetRequest("foo", "bar", "1");
+ GetResult getResult = client.index(index).then(client.get(getRequest))
+ .block();
+ assertThat(getResult.isExists()).isTrue();
+ });
+ }
+
+ @Configuration(proxyBeanMethods = false)
+ static class CustomClientConfiguration {
+
+ @Bean
+ public ReactiveElasticsearchClient customClient() {
+ return mock(ReactiveElasticsearchClient.class);
+ }
+
+ }
+
+ @Configuration(proxyBeanMethods = false)
+ static class CustomClientConfigConfiguration {
+
+ @Bean
+ public ClientConfiguration customClientConfiguration() {
+ return ClientConfiguration.localhost();
+ }
+
+ }
+
+}
diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/elasticsearch/city/ReactiveCityRepository.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/elasticsearch/city/ReactiveCityRepository.java
new file mode 100644
index 00000000000..444e0502c81
--- /dev/null
+++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/elasticsearch/city/ReactiveCityRepository.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2012-2019 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.data.elasticsearch.city;
+
+import org.springframework.data.repository.reactive.ReactiveCrudRepository;
+
+/**
+ * @author Brian Clozel
+ */
+public interface ReactiveCityRepository extends ReactiveCrudRepository {
+
+}
diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/attributes.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/attributes.adoc
index e06bb64e3ce..6d58eb62e09 100644
--- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/attributes.adoc
+++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/attributes.adoc
@@ -52,6 +52,8 @@
:spring-session: https://projects.spring.io/spring-session/
:spring-framework: https://projects.spring.io/spring-framework/
:spring-security: https://projects.spring.io/spring-security/
+:spring-data-elasticsearch: https://spring.io/projects/spring-data-elasticsearch
+:spring-data-elasticsearch-reference: https://docs.spring.io/spring-data/elasticsearch/docs/current/reference/html/
:spring-data-jpa: https://projects.spring.io/spring-data-jpa/
:spring-security-reference: https://docs.spring.io/spring-security/site/docs/{spring-security-docs-version}/reference/htmlsingle
:spring-security-oauth2-reference: https://projects.spring.io/spring-security-oauth/docs/oauth2.html
diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc
index dba67be2588..47e890ab26f 100644
--- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc
+++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc
@@ -4865,12 +4865,15 @@ auto-configuration for Elasticsearch.
Spring Boot supports several clients:
* The official Java "Low Level" and "High Level" REST clients
-* https://github.com/searchbox-io/Jest[Jest]
+* The `ReactiveElasticsearchClient` provided by Spring Data Elasticsearch
The transport client is still available but its support has been deprecated in
https://github.com/spring-projects/spring-data-elasticsearch[Spring Data Elasticsearch]
-and will be removed in a future release. Spring Boot provides a dedicated "`Starter`",
-`spring-boot-starter-data-elasticsearch`.
+and Elasticsearch itself. It will be removed in a future release.
+Spring Boot provides a dedicated "`Starter`", `spring-boot-starter-data-elasticsearch`.
+
+The https://github.com/searchbox-io/Jest[Jest] client has been deprecated as well, since
+both Elasticsearch and Spring Data Elasticsearch provide official support for REST clients.
[[boot-features-connecting-to-elasticsearch-rest]]
==== Connecting to Elasticsearch using REST clients
@@ -4899,6 +4902,28 @@ If you have the `org.elasticsearch.client:elasticsearch-rest-high-level-client`
on the classpath, Spring Boot will auto-configure a `RestHighLevelClient`, which wraps
any existing `RestClient` bean, reusing its HTTP configuration.
+[[boot-features-connecting-to-elasticsearch-reactive-rest]]
+==== Connecting to Elasticsearch using Reactive REST clients
+{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.
+
+By default, Spring Boot will auto-configure and register a `ReactiveElasticsearchClient`
+bean that targets `http://localhost:9200`.
+You can further tune how it is configured, as shown in the following example:
+
+[source,properties,indent=0]
+----
+ spring.elasticsearch.reactive.endpoints=search.example.com:9200
+ spring.elasticsearch.reactive.use-ssl=true
+ spring.elasticsearch.reactive.socket-timeout=10s
+ spring.elasticsearch.reactive.username=user
+ spring.elasticsearch.reactive.password=secret
+----
+
+If the configuration properties are not enough and you'd like to fully control the client
+configuration, you can register a custom `ClientConfiguration` bean.
[[boot-features-connecting-to-elasticsearch-jest]]
==== Connecting to Elasticsearch using Jest
@@ -4933,17 +4958,12 @@ To take full control over the registration, define a `JestClient` bean.
[[boot-features-connecting-to-elasticsearch-spring-data]]
==== Connecting to Elasticsearch by Using Spring Data
-To connect to Elasticsearch, you must provide the address of one or more Elasticsearch
-instances. The address can be specified by setting the `spring.elasticsearch.rest.uris`
-property to a comma-separated `host:port` list. With this configuration in place, an
-`ElasticsearchRestTemplate` or `RestHighLevelClient` can be injected like any other Spring bean,
+To connect to Elasticsearch, a `RestHighLevelClient` bean must be defined,
+auto-configured by Spring Boot or manually provided by the application (see previous sections).
+With this configuration in place, an
+`ElasticsearchRestTemplate` can be injected like any other Spring bean,
as shown in the following example:
-[source,properties,indent=0]
-----
- spring.elasticsearch.rest.uris=localhost:9200
-----
-
[source,java,indent=0]
----
@Component
@@ -4960,9 +4980,12 @@ as shown in the following example:
}
----
-If you add your own `ElasticsearchRestTemplate` or `ElasticsearchOperations` `@Bean`,
-it replaces the default given it is named `"elasticsearchTemplate""`.
-
+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
+<>
+and a `ReactiveElasticsearchTemplate` as beans. They are the reactive equivalent of the
+other REST clients.
[[boot-features-spring-data-elasticsearch-repositories]]
@@ -4977,8 +5000,24 @@ now an Elasticsearch `@Document` class rather than a JPA `@Entity`, it works in
way.
TIP: For complete details of Spring Data Elasticsearch, refer to the
-https://docs.spring.io/spring-data/elasticsearch/docs/[reference documentation].
+{spring-data-elasticsearch-reference}[reference documentation].
+Spring Boot supports both classic and reactive Elasticsearch repositories, using the
+`ElasticsearchRestTemplate` or `ReactiveElasticsearchTemplate` beans. Most likely those
+beans are auto-configured by Spring Boot given the required dependencies are present.
+
+If you wish to use your own template for backing the Elasticsearch repositories, you can
+add your own `ElasticsearchRestTemplate` or `ElasticsearchOperations` `@Bean`,
+as long as it is named `"elasticsearchTemplate"`. Same applies to
+`ReactiveElasticsearchTemplate` and `ReactiveElasticsearchOperations`, with the bean
+name `"reactiveElasticsearchTemplate"`.
+
+You can choose to disable the repositories support with the following property:
+
+[source,properties,indent=0]
+----
+ spring.data.elasticsearch.repositories.enabled=false
+----
[[boot-features-cassandra]]