mirror of
https://github.com/spring-projects/spring-boot.git
synced 2024-07-15 01:07:30 +08:00
Support Formatter conversion service beans
Update `ConversionServiceDeducer` to also include `Formatter` beans when they are qualified with `@ConfigurationPropertiesBinding`. Fixes gh-23576
This commit is contained in:
parent
206356728c
commit
1db2f5f960
@ -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 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public ConversionService create() {
|
public 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,12 +18,14 @@ 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.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
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;
|
||||||
@ -66,6 +68,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;
|
||||||
@ -597,7 +600,7 @@ public class ConfigurationPropertiesTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void loadShouldUseConfigurationConverter() {
|
public 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");
|
||||||
@ -613,13 +616,21 @@ public class ConfigurationPropertiesTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void loadShouldUseGenericConfigurationConverter() {
|
public 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
|
||||||
|
public 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
|
||||||
public void loadWhenGenericConfigurationConverterIsNotQualifiedShouldNotConvert() {
|
public void loadWhenGenericConfigurationConverterIsNotQualifiedShouldNotConvert() {
|
||||||
assertThatExceptionOfType(BeanCreationException.class).isThrownBy(
|
assertThatExceptionOfType(BeanCreationException.class).isThrownBy(
|
||||||
@ -1043,6 +1054,17 @@ public class ConfigurationPropertiesTests {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
static class FormatterConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@ConfigurationPropertiesBinding
|
||||||
|
Formatter<Person> personFormatter() {
|
||||||
|
return new PersonFormatter();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
static class NonQualifiedGenericConverterConfiguration {
|
static class NonQualifiedGenericConverterConfiguration {
|
||||||
|
|
||||||
@ -1731,12 +1753,27 @@ public 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]));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -1752,6 +1789,14 @@ public 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…
Reference in New Issue
Block a user