Polish ConfigurationPropertiesBinder

Remove unused code and polish implementation so that the binder is not
created on each invocation.
This commit is contained in:
Phillip Webb 2018-01-04 16:25:03 -08:00
parent df277fb1b8
commit 937a62e0b8
3 changed files with 24 additions and 128 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2017 the original author or authors.
* Copyright 2012-2018 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.
@ -38,7 +38,6 @@ import org.springframework.validation.Validator;
* {@link PropertySource}.
*
* @author Stephane Nicoll
* @see ConfigurationPropertiesBinderBuilder
*/
class ConfigurationPropertiesBinder {
@ -50,6 +49,8 @@ class ConfigurationPropertiesBinder {
private Iterable<ConfigurationPropertySource> configurationSources;
private final Binder binder;
ConfigurationPropertiesBinder(Iterable<PropertySource<?>> propertySources,
ConversionService conversionService, Validator validator) {
Assert.notNull(propertySources, "PropertySources must not be null");
@ -57,6 +58,10 @@ class ConfigurationPropertiesBinder {
this.conversionService = conversionService;
this.validator = validator;
this.configurationSources = ConfigurationPropertySources.from(propertySources);
this.binder = new Binder(this.configurationSources,
new PropertySourcesPlaceholdersResolver(this.propertySources),
this.conversionService);
}
/**
@ -67,14 +72,11 @@ class ConfigurationPropertiesBinder {
* @throws ConfigurationPropertiesBindingException if the binding failed
*/
void bind(Object target, ConfigurationProperties annotation) {
Binder binder = new Binder(this.configurationSources,
new PropertySourcesPlaceholdersResolver(this.propertySources),
this.conversionService);
Validator validator = determineValidator(target);
BindHandler handler = getBindHandler(annotation, validator);
Bindable<?> bindable = Bindable.ofInstance(target);
try {
binder.bind(annotation.prefix(), bindable, handler);
this.binder.bind(annotation.prefix(), bindable, handler);
}
catch (Exception ex) {
String message = "Could not bind properties to '"

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2017 the original author or authors.
* Copyright 2012-2018 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.
@ -27,7 +27,6 @@ import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.converter.GenericConverter;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.PropertySource;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
@ -72,42 +71,10 @@ class ConfigurationPropertiesBinderBuilder {
this.applicationContext = applicationContext;
}
/**
* Specify the {@link ConversionService} to use or {@code null} to use the default.
* <p>
* By default, use a {@link ConversionService} bean named
* {@value #CONVERSION_SERVICE_BEAN_NAME} if any. Otherwise create a
* {@link DefaultConversionService} with any {@link ConfigurationPropertiesBinding}
* qualified {@link Converter} and {@link GenericConverter} beans found in the
* context.
* @param conversionService the conversion service to use or {@code null}
* @return this instance
*/
ConfigurationPropertiesBinderBuilder withConversionService(
ConversionService conversionService) {
this.conversionService = conversionService;
return this;
}
/**
* Specify the {@link Validator} to use or {@code null} to use the default.
* <p>
* By default, use a {@link Validator} bean named {@value #VALIDATOR_BEAN_NAME} if
* any. If not, create a JSR 303 Validator if the necessary libraries are available.
* No validation occurs otherwise.
* @param validator the validator to use or {@code null}
* @return this instance
*/
ConfigurationPropertiesBinderBuilder withValidator(Validator validator) {
this.validator = validator;
return this;
}
/**
* Specify the {@link PropertySource property sources} to use.
* @param propertySources the configuration the binder should use
* @return this instance
* @see #withEnvironment(ConfigurableEnvironment)
*/
ConfigurationPropertiesBinderBuilder withPropertySources(
Iterable<PropertySource<?>> propertySources) {
@ -115,18 +82,6 @@ class ConfigurationPropertiesBinderBuilder {
return this;
}
/**
* Specify the {@link ConfigurableEnvironment Environment} to use, use all available
* {@link PropertySource}.
* @param environment the environment to use
* @return this instance
* @see #withPropertySources(Iterable)
*/
ConfigurationPropertiesBinderBuilder withEnvironment(
ConfigurableEnvironment environment) {
return withPropertySources(environment.getPropertySources());
}
/**
* Build a {@link ConfigurationPropertiesBinder} based on the state of the builder,
* discovering the {@link ConversionService} and {@link Validator} if necessary.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2017 the original author or authors.
* Copyright 2012-2018 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.
@ -26,12 +26,10 @@ import org.springframework.boot.context.properties.bind.validation.BindValidatio
import org.springframework.boot.context.properties.bind.validation.ValidationErrors;
import org.springframework.context.support.StaticApplicationContext;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.mock.env.MockEnvironment;
import org.springframework.test.context.support.TestPropertySourceUtils;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.util.StringUtils;
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;
@ -54,28 +52,11 @@ public class ConfigurationPropertiesBinderBuilderTests {
private final MockEnvironment environment = new MockEnvironment();
@Test
public void useCustomConversionService() {
DefaultConversionService conversionService = new DefaultConversionService();
conversionService.addConverter(new AddressConverter());
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment,
"test.address=FooStreet 42");
ConfigurationPropertiesBinder binder = this.builder
.withEnvironment(this.environment)
.withConversionService(conversionService).build();
PropertyWithAddress target = new PropertyWithAddress();
bind(binder, target);
assertThat(target.getAddress()).isNotNull();
assertThat(target.getAddress().streetName).isEqualTo("FooStreet");
assertThat(target.getAddress().number).isEqualTo(42);
}
@Test
public void detectDefaultConversionService() {
this.applicationContext.registerSingleton("conversionService",
DefaultConversionService.class);
ConfigurationPropertiesBinder binder = this.builder
.withEnvironment(this.environment).build();
ConfigurationPropertiesBinder binder = builderWithSources().build();
assertThat(ReflectionTestUtils.getField(binder, "conversionService"))
.isSameAs(this.applicationContext.getBean("conversionService"));
}
@ -84,48 +65,42 @@ public class ConfigurationPropertiesBinderBuilderTests {
public void bindToJavaTimeDuration() {
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment,
"test.duration=PT1M");
ConfigurationPropertiesBinder binder = this.builder
.withEnvironment(this.environment).build();
ConfigurationPropertiesBinder binder = builderWithSources().build();
PropertyWithDuration target = new PropertyWithDuration();
bind(binder, target);
assertThat(target.getDuration().getSeconds()).isEqualTo(60);
}
@Test
public void useCustomValidator() {
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
ConfigurationPropertiesBinder binder = this.builder
.withEnvironment(this.environment).withValidator(validator).build();
assertThat(ReflectionTestUtils.getField(binder, "validator")).isSameAs(validator);
}
@Test
public void detectDefaultValidator() {
this.applicationContext.registerSingleton(ConfigurationPropertiesBindingPostProcessor.VALIDATOR_BEAN_NAME,
this.applicationContext.registerSingleton(
ConfigurationPropertiesBindingPostProcessor.VALIDATOR_BEAN_NAME,
LocalValidatorFactoryBean.class);
ConfigurationPropertiesBinder binder = this.builder
.withEnvironment(this.environment).build();
assertThat(ReflectionTestUtils.getField(binder, "validator")).isSameAs(
this.applicationContext.getBean(ConfigurationPropertiesBindingPostProcessor.VALIDATOR_BEAN_NAME));
ConfigurationPropertiesBinder binder = builderWithSources().build();
assertThat(ReflectionTestUtils.getField(binder, "validator"))
.isSameAs(this.applicationContext.getBean(
ConfigurationPropertiesBindingPostProcessor.VALIDATOR_BEAN_NAME));
}
@Test
public void validationWithoutJsr303() {
ConfigurationPropertiesBinder binder = this.builder
.withEnvironment(this.environment).build();
ConfigurationPropertiesBinder binder = builderWithSources().build();
assertThat(bindWithValidationErrors(binder, new PropertyWithoutJSR303())
.getAllErrors()).hasSize(1);
}
@Test
public void validationWithJsr303() {
ConfigurationPropertiesBinder binder = this.builder
.withEnvironment(this.environment).build();
ConfigurationPropertiesBinder binder = builderWithSources().build();
assertThat(
bindWithValidationErrors(binder, new PropertyWithJSR303()).getAllErrors())
.hasSize(2);
}
private ConfigurationPropertiesBinderBuilder builderWithSources() {
return this.builder.withPropertySources(this.environment.getPropertySources());
}
@Test
public void validationWithJsr303AndValidInput() {
TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.environment,
@ -156,42 +131,6 @@ public class ConfigurationPropertiesBinderBuilderTests {
ConfigurationProperties.class));
}
@ConfigurationProperties(prefix = "test")
public static class PropertyWithAddress {
private Address address;
public Address getAddress() {
return this.address;
}
public void setAddress(Address address) {
this.address = address;
}
}
private static class Address {
private String streetName;
private Integer number;
Address(String streetName, Integer number) {
this.streetName = streetName;
this.number = number;
}
}
private static class AddressConverter implements Converter<String, Address> {
@Override
public Address convert(String source) {
String[] split = StringUtils.split(source, " ");
return new Address(split[0], Integer.valueOf(split[1]));
}
}
@ConfigurationProperties(prefix = "test")
public static class PropertyWithDuration {