Merge branch '2.3.x' into master

Closes gh-23615
pull/23616/head
Phillip Webb 4 years ago
commit 8b740c07e3

@ -30,6 +30,7 @@ import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.convert.ConversionService; import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.converter.Converter; import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.converter.GenericConverter; import org.springframework.core.convert.converter.GenericConverter;
import org.springframework.format.Formatter;
/** /**
* Utility to deduce the {@link ConversionService} to use for configuration properties * Utility to deduce the {@link ConversionService} to use for configuration properties
@ -62,9 +63,13 @@ class ConversionServiceDeducer {
private final List<GenericConverter> genericConverters; private final List<GenericConverter> genericConverters;
@SuppressWarnings("rawtypes")
private final List<Formatter> formatters;
Factory(BeanFactory beanFactory) { Factory(BeanFactory beanFactory) {
this.converters = beans(beanFactory, Converter.class, ConfigurationPropertiesBinding.VALUE); this.converters = beans(beanFactory, Converter.class, ConfigurationPropertiesBinding.VALUE);
this.genericConverters = beans(beanFactory, GenericConverter.class, ConfigurationPropertiesBinding.VALUE); this.genericConverters = beans(beanFactory, GenericConverter.class, ConfigurationPropertiesBinding.VALUE);
this.formatters = beans(beanFactory, Formatter.class, ConfigurationPropertiesBinding.VALUE);
} }
private <T> List<T> beans(BeanFactory beanFactory, Class<T> type, String qualifier) { private <T> List<T> beans(BeanFactory beanFactory, Class<T> type, String qualifier) {
@ -80,7 +85,7 @@ class ConversionServiceDeducer {
} }
ConversionService create() { ConversionService create() {
if (this.converters.isEmpty() && this.genericConverters.isEmpty()) { if (this.converters.isEmpty() && this.genericConverters.isEmpty() && this.formatters.isEmpty()) {
return ApplicationConversionService.getSharedInstance(); return ApplicationConversionService.getSharedInstance();
} }
ApplicationConversionService conversionService = new ApplicationConversionService(); ApplicationConversionService conversionService = new ApplicationConversionService();
@ -90,6 +95,9 @@ class ConversionServiceDeducer {
for (GenericConverter genericConverter : this.genericConverters) { for (GenericConverter genericConverter : this.genericConverters) {
conversionService.addConverter(genericConverter); conversionService.addConverter(genericConverter);
} }
for (Formatter<?> formatter : this.formatters) {
conversionService.addFormatter(formatter);
}
return conversionService; return conversionService;
} }

@ -18,6 +18,7 @@ package org.springframework.boot.context.properties;
import java.beans.PropertyEditorSupport; import java.beans.PropertyEditorSupport;
import java.io.File; import java.io.File;
import java.text.ParseException;
import java.time.Duration; import java.time.Duration;
import java.time.Period; import java.time.Period;
import java.time.temporal.ChronoUnit; import java.time.temporal.ChronoUnit;
@ -26,6 +27,7 @@ import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Properties; import java.util.Properties;
import java.util.Set; import java.util.Set;
@ -81,6 +83,7 @@ import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.ProtocolResolver; import org.springframework.core.io.ProtocolResolver;
import org.springframework.core.io.Resource; import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader; import org.springframework.core.io.ResourceLoader;
import org.springframework.format.Formatter;
import org.springframework.mock.env.MockEnvironment; import org.springframework.mock.env.MockEnvironment;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.test.context.support.TestPropertySourceUtils; import org.springframework.test.context.support.TestPropertySourceUtils;
@ -618,7 +621,7 @@ class ConfigurationPropertiesTests {
} }
@Test @Test
void loadShouldUseConfigurationConverter() { void loadShouldUseConverterBean() {
prepareConverterContext(ConverterConfiguration.class, PersonProperties.class); prepareConverterContext(ConverterConfiguration.class, PersonProperties.class);
Person person = this.context.getBean(PersonProperties.class).getPerson(); Person person = this.context.getBean(PersonProperties.class).getPerson();
assertThat(person.firstName).isEqualTo("John"); assertThat(person.firstName).isEqualTo("John");
@ -634,13 +637,21 @@ class ConfigurationPropertiesTests {
} }
@Test @Test
void loadShouldUseGenericConfigurationConverter() { void loadShouldUseGenericConverterBean() {
prepareConverterContext(GenericConverterConfiguration.class, PersonProperties.class); prepareConverterContext(GenericConverterConfiguration.class, PersonProperties.class);
Person person = this.context.getBean(PersonProperties.class).getPerson(); Person person = this.context.getBean(PersonProperties.class).getPerson();
assertThat(person.firstName).isEqualTo("John"); assertThat(person.firstName).isEqualTo("John");
assertThat(person.lastName).isEqualTo("Smith"); assertThat(person.lastName).isEqualTo("Smith");
} }
@Test
void loadShouldUseFormatterBean() {
prepareConverterContext(FormatterConfiguration.class, PersonProperties.class);
Person person = this.context.getBean(PersonProperties.class).getPerson();
assertThat(person.firstName).isEqualTo("John");
assertThat(person.lastName).isEqualTo("Smith");
}
@Test @Test
void loadWhenGenericConfigurationConverterIsNotQualifiedShouldNotConvert() { void loadWhenGenericConfigurationConverterIsNotQualifiedShouldNotConvert() {
assertThatExceptionOfType(BeanCreationException.class).isThrownBy( assertThatExceptionOfType(BeanCreationException.class).isThrownBy(
@ -1326,6 +1337,17 @@ class ConfigurationPropertiesTests {
} }
@Configuration(proxyBeanMethods = false)
static class FormatterConfiguration {
@Bean
@ConfigurationPropertiesBinding
Formatter<Person> personFormatter() {
return new PersonFormatter();
}
}
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
static class NonQualifiedGenericConverterConfiguration { static class NonQualifiedGenericConverterConfiguration {
@ -2158,12 +2180,27 @@ class ConfigurationPropertiesTests {
} }
static class PersonFormatter implements Formatter<Person> {
@Override
public String print(Person person, Locale locale) {
return person.getFirstName() + " " + person.getLastName();
}
@Override
public Person parse(String text, Locale locale) throws ParseException {
String[] content = text.split(" ");
return new Person(content[0], content[1]);
}
}
static class PersonPropertyEditor extends PropertyEditorSupport { static class PersonPropertyEditor extends PropertyEditorSupport {
@Override @Override
public void setAsText(String text) throws IllegalArgumentException { public void setAsText(String text) throws IllegalArgumentException {
String[] split = text.split(","); String[] content = text.split(",");
setValue(new Person(split[1], split[0])); setValue(new Person(content[1], content[0]));
} }
} }
@ -2179,6 +2216,14 @@ class ConfigurationPropertiesTests {
this.lastName = lastName; this.lastName = lastName;
} }
String getFirstName() {
return this.firstName;
}
String getLastName() {
return this.lastName;
}
} }
static class Foo { static class Foo {

Loading…
Cancel
Save