Create spring-boot-data-elasticsearch module

This commit is contained in:
Stéphane Nicoll
2025-03-28 09:29:10 +01:00
committed by Phillip Webb
parent f3dd5dae72
commit fd07ba3860
30 changed files with 131 additions and 128 deletions

View File

@@ -0,0 +1,32 @@
plugins {
id "java-library"
id "org.springframework.boot.auto-configuration"
id "org.springframework.boot.configuration-properties"
id "org.springframework.boot.deployed"
id "org.springframework.boot.docker-test"
id "org.springframework.boot.optional-dependencies"
}
description = "Spring Boot Data Elasticsearch"
dependencies {
api(project(":spring-boot-project:spring-boot-elasticsearch"))
api("org.springframework.data:spring-data-elasticsearch")
optional(project(":spring-boot-project:spring-boot-autoconfigure"))
optional("io.projectreactor:reactor-core")
dockerTestImplementation(project(":spring-boot-project:spring-boot-test"))
dockerTestImplementation(project(":spring-boot-project:spring-boot-tools:spring-boot-test-support-docker"))
dockerTestImplementation(testFixtures(project(":spring-boot-project:spring-boot-autoconfigure")))
dockerTestImplementation("ch.qos.logback:logback-classic")
dockerTestImplementation("org.junit.jupiter:junit-jupiter")
dockerTestImplementation("org.testcontainers:elasticsearch")
dockerTestImplementation("org.testcontainers:junit-jupiter")
testImplementation(project(":spring-boot-project:spring-boot-test"))
testImplementation(project(":spring-boot-project:spring-boot-tools:spring-boot-test-support"))
testImplementation(testFixtures(project(":spring-boot-project:spring-boot-autoconfigure")))
testRuntimeOnly("ch.qos.logback:logback-classic")
}

View File

@@ -0,0 +1,112 @@
/*
* Copyright 2012-2025 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.data.elasticsearch.autoconfigure;
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.TestAutoConfigurationPackage;
import org.springframework.boot.data.elasticsearch.domain.city.City;
import org.springframework.boot.data.elasticsearch.domain.city.CityRepository;
import org.springframework.boot.data.elasticsearch.domain.empty.EmptyDataPackage;
import org.springframework.boot.elasticsearch.autoconfigure.ElasticsearchClientAutoConfiguration;
import org.springframework.boot.elasticsearch.autoconfigure.ElasticsearchRestClientAutoConfiguration;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.boot.testsupport.container.TestImage;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.elasticsearch.client.elc.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.config.EnableElasticsearchAuditing;
import org.springframework.data.elasticsearch.repository.config.EnableElasticsearchRepositories;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link ElasticsearchRepositoriesAutoConfiguration}.
*
* @author Phillip Webb
* @author Andy Wilkinson
* @author Brian Clozel
* @author Scott Frederick
*/
@Testcontainers(disabledWithoutDocker = true)
class ElasticsearchRepositoriesAutoConfigurationTests {
@Container
static final ElasticsearchContainer elasticsearch = TestImage.container(ElasticsearchContainer.class);
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(ElasticsearchRestClientAutoConfiguration.class,
ElasticsearchClientAutoConfiguration.class, ElasticsearchRepositoriesAutoConfiguration.class,
ElasticsearchDataAutoConfiguration.class))
.withPropertyValues("spring.elasticsearch.uris=" + elasticsearch.getHttpHostAddress());
@Test
void testDefaultRepositoryConfiguration() {
this.contextRunner.withUserConfiguration(TestConfiguration.class)
.run((context) -> assertThat(context).hasSingleBean(CityRepository.class)
.hasSingleBean(ElasticsearchTemplate.class));
}
@Test
void testNoRepositoryConfiguration() {
this.contextRunner.withUserConfiguration(EmptyConfiguration.class)
.run((context) -> assertThat(context).hasSingleBean(ElasticsearchTemplate.class));
}
@Test
void doesNotTriggerDefaultRepositoryDetectionIfCustomized() {
this.contextRunner.withUserConfiguration(CustomizedConfiguration.class)
.run((context) -> assertThat(context).hasSingleBean(CityRepository.class));
}
@Test
void testAuditingConfiguration() {
this.contextRunner.withUserConfiguration(AuditingConfiguration.class)
.run((context) -> assertThat(context).hasSingleBean(ElasticsearchTemplate.class));
}
@Configuration(proxyBeanMethods = false)
@TestAutoConfigurationPackage(City.class)
static class TestConfiguration {
}
@Configuration(proxyBeanMethods = false)
@TestAutoConfigurationPackage(EmptyDataPackage.class)
static class EmptyConfiguration {
}
@Configuration(proxyBeanMethods = false)
@TestAutoConfigurationPackage(City.class)
@EnableElasticsearchRepositories(basePackageClasses = CityRepository.class)
static class CustomizedConfiguration {
}
@Configuration(proxyBeanMethods = false)
@TestAutoConfigurationPackage(City.class)
@EnableElasticsearchRepositories
@EnableElasticsearchAuditing
static class AuditingConfiguration {
}
}

View File

@@ -0,0 +1,126 @@
/*
* Copyright 2012-2025 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.data.elasticsearch.autoconfigure;
import org.junit.jupiter.api.Test;
import org.testcontainers.elasticsearch.ElasticsearchContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import reactor.core.publisher.Mono;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.TestAutoConfigurationPackage;
import org.springframework.boot.data.elasticsearch.domain.city.City;
import org.springframework.boot.data.elasticsearch.domain.city.ReactiveCityRepository;
import org.springframework.boot.data.elasticsearch.domain.empty.EmptyDataPackage;
import org.springframework.boot.elasticsearch.autoconfigure.ElasticsearchClientAutoConfiguration;
import org.springframework.boot.elasticsearch.autoconfigure.ElasticsearchRestClientAutoConfiguration;
import org.springframework.boot.elasticsearch.autoconfigure.ReactiveElasticsearchClientAutoConfiguration;
import org.springframework.boot.test.context.FilteredClassLoader;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.boot.testsupport.container.TestImage;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.elasticsearch.client.elc.ReactiveElasticsearchTemplate;
import org.springframework.data.elasticsearch.config.EnableElasticsearchAuditing;
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
* @author Scott Frederick
*/
@Testcontainers(disabledWithoutDocker = true)
class ReactiveElasticsearchRepositoriesAutoConfigurationTests {
@Container
static final ElasticsearchContainer elasticsearch = TestImage.container(ElasticsearchContainer.class);
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(ElasticsearchClientAutoConfiguration.class,
ElasticsearchRestClientAutoConfiguration.class,
ReactiveElasticsearchRepositoriesAutoConfiguration.class, ElasticsearchDataAutoConfiguration.class,
ReactiveElasticsearchClientAutoConfiguration.class))
.withPropertyValues(
"spring.elasticsearch.uris=" + elasticsearch.getHost() + ":" + elasticsearch.getFirstMappedPort(),
"spring.elasticsearch.socket-timeout=30s");
@Test
void backsOffWithoutReactor() {
this.contextRunner.withUserConfiguration(TestConfiguration.class)
.withClassLoader(new FilteredClassLoader(Mono.class))
.run((context) -> assertThat(context)
.doesNotHaveBean(ReactiveElasticsearchRepositoriesAutoConfiguration.class));
}
@Test
void testDefaultRepositoryConfiguration() {
this.contextRunner.withUserConfiguration(TestConfiguration.class)
.run((context) -> assertThat(context).hasSingleBean(ReactiveCityRepository.class)
.hasSingleBean(ReactiveElasticsearchTemplate.class));
}
@Test
void testNoRepositoryConfiguration() {
this.contextRunner.withUserConfiguration(EmptyConfiguration.class)
.run((context) -> assertThat(context).hasSingleBean(ReactiveElasticsearchTemplate.class));
}
@Test
void doesNotTriggerDefaultRepositoryDetectionIfCustomized() {
this.contextRunner.withUserConfiguration(CustomizedConfiguration.class)
.run((context) -> assertThat(context).hasSingleBean(ReactiveCityRepository.class));
}
@Test
void testAuditingConfiguration() {
this.contextRunner.withUserConfiguration(AuditingConfiguration.class)
.run((context) -> assertThat(context).hasSingleBean(ReactiveElasticsearchTemplate.class));
}
@Configuration(proxyBeanMethods = false)
@TestAutoConfigurationPackage(City.class)
static class TestConfiguration {
}
@Configuration(proxyBeanMethods = false)
@TestAutoConfigurationPackage(EmptyDataPackage.class)
static class EmptyConfiguration {
}
@Configuration(proxyBeanMethods = false)
@TestAutoConfigurationPackage(City.class)
@EnableReactiveElasticsearchRepositories(basePackageClasses = ReactiveCityRepository.class)
static class CustomizedConfiguration {
}
@Configuration(proxyBeanMethods = false)
@TestAutoConfigurationPackage(City.class)
@EnableReactiveElasticsearchRepositories
@EnableElasticsearchAuditing
static class AuditingConfiguration {
}
}

View File

@@ -0,0 +1,21 @@
/*
* Copyright 2012-2025 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.data.elasticsearch.domain.empty;
public class EmptyDataPackage {
}

View File

@@ -0,0 +1,48 @@
/*
* Copyright 2012-2025 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.data.elasticsearch.autoconfigure;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.elasticsearch.autoconfigure.ElasticsearchClientAutoConfiguration;
import org.springframework.boot.elasticsearch.autoconfigure.ReactiveElasticsearchClientAutoConfiguration;
import org.springframework.context.annotation.Import;
import org.springframework.data.elasticsearch.client.elc.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.
*
* @author Brian Clozel
* @author Artur Konczak
* @author Mohsin Husen
* @since 4.0.0
* @see EnableElasticsearchRepositories
* @see EnableReactiveElasticsearchRepositories
*/
@AutoConfiguration(
after = { ElasticsearchClientAutoConfiguration.class, ReactiveElasticsearchClientAutoConfiguration.class })
@ConditionalOnClass({ ElasticsearchTemplate.class })
@Import({ ElasticsearchDataConfiguration.BaseConfiguration.class,
ElasticsearchDataConfiguration.JavaClientConfiguration.class,
ElasticsearchDataConfiguration.ReactiveRestClientConfiguration.class })
public class ElasticsearchDataAutoConfiguration {
}

View File

@@ -0,0 +1,109 @@
/*
* Copyright 2012-2025 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.data.elasticsearch.autoconfigure;
import java.util.Collections;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.domain.EntityScanner;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.elasticsearch.annotations.Document;
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.ReactiveElasticsearchOperations;
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
import org.springframework.data.elasticsearch.core.convert.ElasticsearchCustomConversions;
import org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter;
import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchMappingContext;
/**
* Configuration classes for Spring Data for Elasticsearch
* <p>
* Those should be {@code @Import} in a regular auto-configuration class to guarantee
* their order of execution.
*
* @author Brian Clozel
* @author Scott Frederick
* @author Stephane Nicoll
*/
abstract class ElasticsearchDataConfiguration {
@Configuration(proxyBeanMethods = false)
static class BaseConfiguration {
@Bean
@ConditionalOnMissingBean
ElasticsearchCustomConversions elasticsearchCustomConversions() {
return new ElasticsearchCustomConversions(Collections.emptyList());
}
@Bean
@ConditionalOnMissingBean
SimpleElasticsearchMappingContext elasticsearchMappingContext(ApplicationContext applicationContext,
ElasticsearchCustomConversions elasticsearchCustomConversions) throws ClassNotFoundException {
SimpleElasticsearchMappingContext mappingContext = new SimpleElasticsearchMappingContext();
mappingContext.setInitialEntitySet(new EntityScanner(applicationContext).scan(Document.class));
mappingContext.setSimpleTypeHolder(elasticsearchCustomConversions.getSimpleTypeHolder());
return mappingContext;
}
@Bean
@ConditionalOnMissingBean
ElasticsearchConverter elasticsearchConverter(SimpleElasticsearchMappingContext mappingContext,
ElasticsearchCustomConversions elasticsearchCustomConversions) {
MappingElasticsearchConverter converter = new MappingElasticsearchConverter(mappingContext);
converter.setConversions(elasticsearchCustomConversions);
return converter;
}
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(ElasticsearchClient.class)
static class JavaClientConfiguration {
@Bean
@ConditionalOnMissingBean(value = ElasticsearchOperations.class, name = "elasticsearchTemplate")
@ConditionalOnBean(ElasticsearchClient.class)
ElasticsearchTemplate elasticsearchTemplate(ElasticsearchClient client, ElasticsearchConverter converter) {
return new ElasticsearchTemplate(client, converter);
}
}
@Configuration(proxyBeanMethods = false)
static class ReactiveRestClientConfiguration {
@Bean
@ConditionalOnMissingBean(value = ReactiveElasticsearchOperations.class, name = "reactiveElasticsearchTemplate")
@ConditionalOnBean(ReactiveElasticsearchClient.class)
ReactiveElasticsearchTemplate reactiveElasticsearchTemplate(ReactiveElasticsearchClient client,
ElasticsearchConverter converter) {
return new ReactiveElasticsearchTemplate(client, converter);
}
}
}

View File

@@ -0,0 +1,45 @@
/*
* Copyright 2012-2025 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.data.elasticsearch.autoconfigure;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Import;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.springframework.data.elasticsearch.repository.config.EnableElasticsearchRepositories;
import org.springframework.data.elasticsearch.repository.support.ElasticsearchRepositoryFactoryBean;
/**
* {@link EnableAutoConfiguration Auto-configuration} for Spring Data's Elasticsearch
* Repositories.
*
* @author Artur Konczak
* @author Mohsin Husen
* @since 4.0.0
* @see EnableElasticsearchRepositories
*/
@AutoConfiguration
@ConditionalOnClass(ElasticsearchRepository.class)
@ConditionalOnBooleanProperty(name = "spring.data.elasticsearch.repositories.enabled", matchIfMissing = true)
@ConditionalOnMissingBean(ElasticsearchRepositoryFactoryBean.class)
@Import(ElasticsearchRepositoriesRegistrar.class)
public class ElasticsearchRepositoriesAutoConfiguration {
}

View File

@@ -0,0 +1,56 @@
/*
* Copyright 2012-2025 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.data.elasticsearch.autoconfigure;
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.ElasticsearchRepositoryConfigExtension;
import org.springframework.data.elasticsearch.repository.config.EnableElasticsearchRepositories;
import org.springframework.data.repository.config.RepositoryConfigurationExtension;
/**
* {@link ImportBeanDefinitionRegistrar} used to auto-configure Spring Data Elasticsearch
* Repositories.
*
* @author Artur Konczak
* @author Mohsin Husen
*/
class ElasticsearchRepositoriesRegistrar extends AbstractRepositoryConfigurationSourceSupport {
@Override
protected Class<? extends Annotation> getAnnotation() {
return EnableElasticsearchRepositories.class;
}
@Override
protected Class<?> getConfiguration() {
return EnableElasticsearchRepositoriesConfiguration.class;
}
@Override
protected RepositoryConfigurationExtension getRepositoryConfigurationExtension() {
return new ElasticsearchRepositoryConfigExtension();
}
@EnableElasticsearchRepositories
private static final class EnableElasticsearchRepositoriesConfiguration {
}
}

View File

@@ -0,0 +1,47 @@
/*
* Copyright 2012-2025 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.data.elasticsearch.autoconfigure;
import reactor.core.publisher.Mono;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Import;
import org.springframework.data.elasticsearch.client.elc.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
* @since 4.0.0
* @see EnableReactiveElasticsearchRepositories
*/
@AutoConfiguration
@ConditionalOnClass({ ReactiveElasticsearchClient.class, ReactiveElasticsearchRepository.class, Mono.class })
@ConditionalOnBooleanProperty(name = "spring.data.elasticsearch.repositories.enabled", matchIfMissing = true)
@ConditionalOnMissingBean(ReactiveElasticsearchRepositoryFactoryBean.class)
@Import(ReactiveElasticsearchRepositoriesRegistrar.class)
public class ReactiveElasticsearchRepositoriesAutoConfiguration {
}

View File

@@ -0,0 +1,55 @@
/*
* Copyright 2012-2025 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.data.elasticsearch.autoconfigure;
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
*/
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 final class EnableElasticsearchRepositoriesConfiguration {
}
}

View File

@@ -0,0 +1,20 @@
/*
* Copyright 2012-2025 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.
*/
/**
* Auto-configuration for Spring Data Elasticsearch.
*/
package org.springframework.boot.data.elasticsearch.autoconfigure;

View File

@@ -0,0 +1,35 @@
{
"groups": [],
"properties": [
{
"name": "spring.data.elasticsearch.cluster-name",
"type": "java.lang.String",
"description": "Elasticsearch cluster name.",
"deprecation": {
"level": "error"
}
},
{
"name": "spring.data.elasticsearch.cluster-nodes",
"type": "java.lang.String",
"description": "Comma-separated list of cluster node addresses.",
"deprecation": {
"level": "error"
}
},
{
"name": "spring.data.elasticsearch.properties",
"type": "java.util.Map<java.lang.String,java.lang.String>",
"description": "Additional properties used to configure the client.",
"deprecation": {
"level": "error"
}
},
{
"name": "spring.data.elasticsearch.repositories.enabled",
"type": "java.lang.Boolean",
"description": "Whether to enable Elasticsearch repositories.",
"defaultValue": true
}
]
}

View File

@@ -0,0 +1,3 @@
org.springframework.boot.data.elasticsearch.autoconfigure.ElasticsearchDataAutoConfiguration
org.springframework.boot.data.elasticsearch.autoconfigure.ElasticsearchRepositoriesAutoConfiguration
org.springframework.boot.data.elasticsearch.autoconfigure.ReactiveElasticsearchRepositoriesAutoConfiguration

View File

@@ -0,0 +1,160 @@
/*
* Copyright 2012-2025 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.data.elasticsearch.autoconfigure;
import java.math.BigDecimal;
import java.util.Collections;
import org.assertj.core.api.InstanceOfAssertFactories;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.TestAutoConfigurationPackage;
import org.springframework.boot.data.elasticsearch.domain.city.City;
import org.springframework.boot.elasticsearch.autoconfigure.ElasticsearchClientAutoConfiguration;
import org.springframework.boot.elasticsearch.autoconfigure.ElasticsearchRestClientAutoConfiguration;
import org.springframework.boot.elasticsearch.autoconfigure.ReactiveElasticsearchClientAutoConfiguration;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.elasticsearch.client.elc.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.client.elc.ReactiveElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
import org.springframework.data.elasticsearch.core.convert.ElasticsearchCustomConversions;
import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchMappingContext;
import org.springframework.data.mapping.model.SimpleTypeHolder;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
/**
* Tests for {@link ElasticsearchDataAutoConfiguration}.
*
* @author Phillip Webb
* @author Artur Konczak
* @author Brian Clozel
* @author Peter-Josef Meisch
* @author Scott Frederick
* @author Stephane Nicoll
*/
class ElasticsearchDataAutoConfigurationTests {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(ElasticsearchRestClientAutoConfiguration.class,
ElasticsearchClientAutoConfiguration.class, ElasticsearchDataAutoConfiguration.class,
ReactiveElasticsearchClientAutoConfiguration.class));
@Test
void defaultRestBeansRegistered() {
this.contextRunner.run((context) -> assertThat(context).hasSingleBean(ElasticsearchTemplate.class)
.hasSingleBean(ReactiveElasticsearchTemplate.class)
.hasSingleBean(ElasticsearchConverter.class)
.hasSingleBean(ElasticsearchConverter.class)
.hasSingleBean(ElasticsearchCustomConversions.class));
}
@Test
void defaultConversionsRegisterBigDecimalAsSimpleType() {
this.contextRunner.run((context) -> {
SimpleElasticsearchMappingContext mappingContext = context.getBean(SimpleElasticsearchMappingContext.class);
assertThat(mappingContext)
.extracting("simpleTypeHolder", InstanceOfAssertFactories.type(SimpleTypeHolder.class))
.satisfies((simpleTypeHolder) -> assertThat(simpleTypeHolder.isSimpleType(BigDecimal.class)).isTrue());
});
}
@Test
void customConversionsShouldBeUsed() {
this.contextRunner.withUserConfiguration(CustomElasticsearchCustomConversions.class).run((context) -> {
assertThat(context).hasSingleBean(ElasticsearchCustomConversions.class).hasBean("testCustomConversions");
assertThat(context.getBean(ElasticsearchConverter.class)
.getConversionService()
.canConvert(ElasticsearchTemplate.class, Boolean.class)).isTrue();
});
}
@Test
void customRestTemplateShouldBeUsed() {
this.contextRunner.withUserConfiguration(CustomRestTemplate.class)
.run((context) -> assertThat(context).getBeanNames(ElasticsearchTemplate.class)
.hasSize(1)
.contains("elasticsearchTemplate"));
}
@Test
void customReactiveRestTemplateShouldBeUsed() {
this.contextRunner.withUserConfiguration(CustomReactiveElasticsearchTemplate.class)
.run((context) -> assertThat(context).getBeanNames(ReactiveElasticsearchTemplate.class)
.hasSize(1)
.contains("reactiveElasticsearchTemplate"));
}
@Test
void shouldFilterInitialEntityScanWithDocumentAnnotation() {
this.contextRunner.withUserConfiguration(EntityScanConfig.class).run((context) -> {
SimpleElasticsearchMappingContext mappingContext = context.getBean(SimpleElasticsearchMappingContext.class);
assertThat(mappingContext.hasPersistentEntityFor(City.class)).isTrue();
});
}
@Configuration(proxyBeanMethods = false)
static class CustomElasticsearchCustomConversions {
@Bean
ElasticsearchCustomConversions testCustomConversions() {
return new ElasticsearchCustomConversions(Collections.singletonList(new MyConverter()));
}
}
@Configuration(proxyBeanMethods = false)
static class CustomRestTemplate {
@Bean
ElasticsearchTemplate elasticsearchTemplate() {
return mock(ElasticsearchTemplate.class);
}
}
@Configuration(proxyBeanMethods = false)
static class CustomReactiveElasticsearchTemplate {
@Bean
ReactiveElasticsearchTemplate reactiveElasticsearchTemplate() {
return mock(ReactiveElasticsearchTemplate.class);
}
}
@Configuration(proxyBeanMethods = false)
@TestAutoConfigurationPackage(City.class)
static class EntityScanConfig {
}
static class MyConverter implements Converter<ElasticsearchTemplate, Boolean> {
@Override
public Boolean convert(ElasticsearchTemplate source) {
return null;
}
}
}

View File

@@ -0,0 +1,71 @@
/*
* Copyright 2012-2025 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.data.elasticsearch.domain.city;
import java.io.Serializable;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Setting;
@Document(indexName = "city")
@Setting(shards = 1, replicas = 0, refreshInterval = "-1")
public class City implements Serializable {
private static final long serialVersionUID = 1L;
@Id
private Long id;
private String name;
private String state;
private String country;
private String map;
protected City() {
}
public City(String name, String country) {
this.name = name;
this.country = country;
}
public String getName() {
return this.name;
}
public String getState() {
return this.state;
}
public String getCountry() {
return this.country;
}
public String getMap() {
return this.map;
}
@Override
public String toString() {
return getName() + "," + getState() + "," + getCountry();
}
}

View File

@@ -0,0 +1,31 @@
/*
* Copyright 2012-2025 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.data.elasticsearch.domain.city;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.repository.Repository;
public interface CityRepository extends Repository<City, Long> {
Page<City> findAll(Pageable pageable);
Page<City> findByNameLikeAndCountryLikeAllIgnoringCase(String name, String country, Pageable pageable);
City findByNameAndCountryAllIgnoringCase(String name, String country);
}

View File

@@ -0,0 +1,23 @@
/*
* Copyright 2012-2025 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.data.elasticsearch.domain.city;
import org.springframework.data.repository.reactive.ReactiveCrudRepository;
public interface ReactiveCityRepository extends ReactiveCrudRepository<City, String> {
}