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 2a2291bdca..4feca9dba8 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 @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2021 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. @@ -16,6 +16,8 @@ package org.springframework.boot.autoconfigure.data.elasticsearch; +import java.util.Collections; + import org.elasticsearch.action.support.IndicesOptions; import org.elasticsearch.action.support.WriteRequest; import org.elasticsearch.client.RestHighLevelClient; @@ -31,6 +33,7 @@ import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate; import org.springframework.data.elasticsearch.core.ReactiveElasticsearchOperations; import org.springframework.data.elasticsearch.core.ReactiveElasticsearchTemplate; 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; import org.springframework.web.reactive.function.client.WebClient; @@ -43,6 +46,7 @@ import org.springframework.web.reactive.function.client.WebClient; * * @author Brian Clozel * @author Scott Frederick + * @author Stephane Nicoll */ abstract class ElasticsearchDataConfiguration { @@ -51,14 +55,26 @@ abstract class ElasticsearchDataConfiguration { @Bean @ConditionalOnMissingBean - ElasticsearchConverter elasticsearchConverter(SimpleElasticsearchMappingContext mappingContext) { - return new MappingElasticsearchConverter(mappingContext); + ElasticsearchCustomConversions elasticsearchCustomConversions() { + return new ElasticsearchCustomConversions(Collections.emptyList()); + } + + @Bean + @ConditionalOnMissingBean + SimpleElasticsearchMappingContext mappingContext( + ElasticsearchCustomConversions elasticsearchCustomConversions) { + SimpleElasticsearchMappingContext mappingContext = new SimpleElasticsearchMappingContext(); + mappingContext.setSimpleTypeHolder(elasticsearchCustomConversions.getSimpleTypeHolder()); + return mappingContext; } @Bean @ConditionalOnMissingBean - SimpleElasticsearchMappingContext mappingContext() { - return new SimpleElasticsearchMappingContext(); + ElasticsearchConverter elasticsearchConverter(SimpleElasticsearchMappingContext mappingContext, + ElasticsearchCustomConversions elasticsearchCustomConversions) { + MappingElasticsearchConverter converter = new MappingElasticsearchConverter(mappingContext); + converter.setConversions(elasticsearchCustomConversions); + return converter; } } 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 7a7c0b244d..66d0cc0d9d 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 @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2021 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. @@ -16,6 +16,10 @@ package org.springframework.boot.autoconfigure.data.elasticsearch; +import java.math.BigDecimal; +import java.util.Collections; + +import org.assertj.core.api.InstanceOfAssertFactories; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -25,9 +29,13 @@ import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchRestCli 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.core.ElasticsearchRestTemplate; import org.springframework.data.elasticsearch.core.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; @@ -40,10 +48,11 @@ import static org.mockito.Mockito.mock; * @author Brian Clozel * @author Peter-Josef Meisch * @author Scott Frederick + * @author Stephane Nicoll */ class ElasticsearchDataAutoConfigurationTests { - private ApplicationContextRunner contextRunner = new ApplicationContextRunner() + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() .withConfiguration(AutoConfigurations.of(ElasticsearchRestClientAutoConfiguration.class, ReactiveElasticsearchRestClientAutoConfiguration.class, ElasticsearchDataAutoConfiguration.class)); @@ -61,7 +70,26 @@ class ElasticsearchDataAutoConfigurationTests { void defaultRestBeansRegistered() { this.contextRunner.run((context) -> assertThat(context).hasSingleBean(ElasticsearchRestTemplate.class) .hasSingleBean(ReactiveElasticsearchTemplate.class).hasSingleBean(ElasticsearchConverter.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(ElasticsearchRestTemplate.class, Boolean.class)).isTrue(); + }); } @Test @@ -77,6 +105,16 @@ class ElasticsearchDataAutoConfigurationTests { .contains("reactiveElasticsearchTemplate")); } + @Configuration(proxyBeanMethods = false) + static class CustomElasticsearchCustomConversions { + + @Bean + ElasticsearchCustomConversions testCustomConversions() { + return new ElasticsearchCustomConversions(Collections.singletonList(new MyConverter())); + } + + } + @Configuration(proxyBeanMethods = false) static class CustomRestTemplate { @@ -97,4 +135,13 @@ class ElasticsearchDataAutoConfigurationTests { } + static class MyConverter implements Converter { + + @Override + public Boolean convert(ElasticsearchRestTemplate source) { + return null; + } + + } + }