Make binder API private again

Closes gh-10867
This commit is contained in:
Stephane Nicoll 2017-11-17 11:23:34 +01:00
parent 0f69a157ac
commit 4ff8126217
6 changed files with 48 additions and 67 deletions

View File

@ -26,7 +26,6 @@ import org.springframework.boot.context.properties.bind.validation.ValidationBin
import org.springframework.boot.context.properties.source.ConfigurationPropertySource; import org.springframework.boot.context.properties.source.ConfigurationPropertySource;
import org.springframework.boot.context.properties.source.ConfigurationPropertySources; import org.springframework.boot.context.properties.source.ConfigurationPropertySources;
import org.springframework.boot.context.properties.source.UnboundElementsSourceFilter; import org.springframework.boot.context.properties.source.UnboundElementsSourceFilter;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.convert.ConversionService; import org.springframework.core.convert.ConversionService;
import org.springframework.core.env.PropertySource; import org.springframework.core.env.PropertySource;
import org.springframework.util.Assert; import org.springframework.util.Assert;
@ -39,10 +38,9 @@ import org.springframework.validation.Validator;
* {@link PropertySource}. * {@link PropertySource}.
* *
* @author Stephane Nicoll * @author Stephane Nicoll
* @since 2.0.0
* @see ConfigurationPropertiesBinderBuilder * @see ConfigurationPropertiesBinderBuilder
*/ */
public class ConfigurationPropertiesBinder { class ConfigurationPropertiesBinder {
private final Iterable<PropertySource<?>> propertySources; private final Iterable<PropertySource<?>> propertySources;
@ -61,20 +59,6 @@ public class ConfigurationPropertiesBinder {
this.configurationSources = ConfigurationPropertySources.from(propertySources); this.configurationSources = ConfigurationPropertySources.from(propertySources);
} }
/**
* Bind the specified {@code target} object if it is annotated with
* {@link ConfigurationProperties}, otherwise ignore it.
* @param target the target to bind the configuration property sources to
* @throws ConfigurationPropertiesBindingException if the binding failed
*/
public void bind(Object target) {
ConfigurationProperties annotation = AnnotationUtils
.findAnnotation(target.getClass(), ConfigurationProperties.class);
if (annotation != null) {
bind(target, annotation);
}
}
/** /**
* Bind the specified {@code target} object using the configuration defined by the * Bind the specified {@code target} object using the configuration defined by the
* specified {@code annotation}. * specified {@code annotation}.
@ -93,8 +77,10 @@ public class ConfigurationPropertiesBinder {
binder.bind(annotation.prefix(), bindable, handler); binder.bind(annotation.prefix(), bindable, handler);
} }
catch (Exception ex) { catch (Exception ex) {
throw new ConfigurationPropertiesBindingException(target.getClass(), String message = "Could not bind properties to '"
getAnnotationDetails(annotation), ex); + ClassUtils.getShortName(target.getClass()) + "': "
+ getAnnotationDetails(annotation);
throw new ConfigurationPropertiesBindingException(message, ex);
} }
} }

View File

@ -38,19 +38,18 @@ import org.springframework.validation.Validator;
* {@link ApplicationContext}. * {@link ApplicationContext}.
* *
* @author Stephane Nicoll * @author Stephane Nicoll
* @since 2.0.0
*/ */
public class ConfigurationPropertiesBinderBuilder { class ConfigurationPropertiesBinderBuilder {
/** /**
* The bean name of the configuration properties validator. * The bean name of the configuration properties validator.
*/ */
public static final String VALIDATOR_BEAN_NAME = "configurationPropertiesValidator"; private static final String VALIDATOR_BEAN_NAME = ConfigurationPropertiesBindingPostProcessor.VALIDATOR_BEAN_NAME;
/** /**
* The bean name of the configuration properties conversion service. * The bean name of the configuration properties conversion service.
*/ */
public static final String CONVERSION_SERVICE_BEAN_NAME = ConfigurableApplicationContext.CONVERSION_SERVICE_BEAN_NAME; private static final String CONVERSION_SERVICE_BEAN_NAME = ConfigurableApplicationContext.CONVERSION_SERVICE_BEAN_NAME;
private static final String[] VALIDATOR_CLASSES = { "javax.validation.Validator", private static final String[] VALIDATOR_CLASSES = { "javax.validation.Validator",
"javax.validation.ValidatorFactory", "javax.validation.ValidatorFactory",
@ -68,7 +67,7 @@ public class ConfigurationPropertiesBinderBuilder {
* Creates an instance with the {@link ApplicationContext} to use. * Creates an instance with the {@link ApplicationContext} to use.
* @param applicationContext the application context * @param applicationContext the application context
*/ */
public ConfigurationPropertiesBinderBuilder(ApplicationContext applicationContext) { ConfigurationPropertiesBinderBuilder(ApplicationContext applicationContext) {
Assert.notNull(applicationContext, "ApplicationContext must not be null"); Assert.notNull(applicationContext, "ApplicationContext must not be null");
this.applicationContext = applicationContext; this.applicationContext = applicationContext;
} }

View File

@ -17,32 +17,18 @@
package org.springframework.boot.context.properties; package org.springframework.boot.context.properties;
import org.springframework.core.NestedExceptionUtils; import org.springframework.core.NestedExceptionUtils;
import org.springframework.util.ClassUtils;
/** /**
* Exception thrown when a {@code @ConfigurationProperties} annotated object failed to be * Exception thrown when a {@code @ConfigurationProperties} annotated object failed to be
* bound. * bound.
* *
* @author Stephane Nicoll * @author Stephane Nicoll
* @since 2.0.0
*/ */
public class ConfigurationPropertiesBindingException extends RuntimeException { class ConfigurationPropertiesBindingException extends RuntimeException {
private final Class<?> targetClass; ConfigurationPropertiesBindingException(String message,
public ConfigurationPropertiesBindingException(Class<?> targetClass, String message,
Throwable cause) { Throwable cause) {
super("Could not bind properties to '" + ClassUtils.getShortName(targetClass) super(message, cause);
+ "': " + message, cause);
this.targetClass = targetClass;
}
/**
* Return the target type of the object that failed to be bound.
* @return the target {@link Class}
*/
public Class<?> getTargetClass() {
return this.targetClass;
} }
/** /**

View File

@ -55,6 +55,11 @@ public class ConfigurationPropertiesBindingPostProcessor
implements BeanPostProcessor, BeanFactoryAware, EnvironmentAware, implements BeanPostProcessor, BeanFactoryAware, EnvironmentAware,
ApplicationContextAware, InitializingBean, PriorityOrdered { ApplicationContextAware, InitializingBean, PriorityOrdered {
/**
* The bean name of the configuration properties validator.
*/
public static final String VALIDATOR_BEAN_NAME = "configurationPropertiesValidator";
private static final Log logger = LogFactory private static final Log logger = LogFactory
.getLog(ConfigurationPropertiesBindingPostProcessor.class); .getLog(ConfigurationPropertiesBindingPostProcessor.class);

View File

@ -25,6 +25,7 @@ import org.junit.Test;
import org.springframework.boot.context.properties.bind.validation.BindValidationException; import org.springframework.boot.context.properties.bind.validation.BindValidationException;
import org.springframework.boot.context.properties.bind.validation.ValidationErrors; import org.springframework.boot.context.properties.bind.validation.ValidationErrors;
import org.springframework.context.support.StaticApplicationContext; import org.springframework.context.support.StaticApplicationContext;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.convert.converter.Converter; import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.support.DefaultConversionService; import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.mock.env.MockEnvironment; import org.springframework.mock.env.MockEnvironment;
@ -63,7 +64,7 @@ public class ConfigurationPropertiesBinderBuilderTests {
.withEnvironment(this.environment) .withEnvironment(this.environment)
.withConversionService(conversionService).build(); .withConversionService(conversionService).build();
PropertyWithAddress target = new PropertyWithAddress(); PropertyWithAddress target = new PropertyWithAddress();
binder.bind(target); bind(binder, target);
assertThat(target.getAddress()).isNotNull(); assertThat(target.getAddress()).isNotNull();
assertThat(target.getAddress().streetName).isEqualTo("FooStreet"); assertThat(target.getAddress().streetName).isEqualTo("FooStreet");
assertThat(target.getAddress().number).isEqualTo(42); assertThat(target.getAddress().number).isEqualTo(42);
@ -86,7 +87,7 @@ public class ConfigurationPropertiesBinderBuilderTests {
ConfigurationPropertiesBinder binder = this.builder ConfigurationPropertiesBinder binder = this.builder
.withEnvironment(this.environment).build(); .withEnvironment(this.environment).build();
PropertyWithDuration target = new PropertyWithDuration(); PropertyWithDuration target = new PropertyWithDuration();
binder.bind(target); bind(binder, target);
assertThat(target.getDuration().getSeconds()).isEqualTo(60); assertThat(target.getDuration().getSeconds()).isEqualTo(60);
} }
@ -122,7 +123,7 @@ public class ConfigurationPropertiesBinderBuilderTests {
.withEnvironment(this.environment).build(); .withEnvironment(this.environment).build();
assertThat( assertThat(
bindWithValidationErrors(binder, new PropertyWithJSR303()).getAllErrors()) bindWithValidationErrors(binder, new PropertyWithJSR303()).getAllErrors())
.hasSize(2); .hasSize(2);
} }
@Test @Test
@ -132,7 +133,7 @@ public class ConfigurationPropertiesBinderBuilderTests {
ConfigurationPropertiesBinder binder = new ConfigurationPropertiesBinder( ConfigurationPropertiesBinder binder = new ConfigurationPropertiesBinder(
this.environment.getPropertySources(), null, null); this.environment.getPropertySources(), null, null);
PropertyWithJSR303 target = new PropertyWithJSR303(); PropertyWithJSR303 target = new PropertyWithJSR303();
binder.bind(target); bind(binder, target);
assertThat(target.getFoo()).isEqualTo("123456"); assertThat(target.getFoo()).isEqualTo("123456");
assertThat(target.getBar()).isEqualTo("654321"); assertThat(target.getBar()).isEqualTo("654321");
} }
@ -140,7 +141,7 @@ public class ConfigurationPropertiesBinderBuilderTests {
private ValidationErrors bindWithValidationErrors( private ValidationErrors bindWithValidationErrors(
ConfigurationPropertiesBinder binder, Object target) { ConfigurationPropertiesBinder binder, Object target) {
try { try {
binder.bind(target); bind(binder, target);
throw new AssertionError("Should have failed to bind " + target); throw new AssertionError("Should have failed to bind " + target);
} }
catch (ConfigurationPropertiesBindingException ex) { catch (ConfigurationPropertiesBindingException ex) {
@ -150,6 +151,11 @@ public class ConfigurationPropertiesBinderBuilderTests {
} }
} }
private void bind(ConfigurationPropertiesBinder binder, Object target) {
binder.bind(target, AnnotationUtils
.findAnnotation(target.getClass(), ConfigurationProperties.class));
}
@ConfigurationProperties(prefix = "test") @ConfigurationProperties(prefix = "test")
public static class PropertyWithAddress { public static class PropertyWithAddress {

View File

@ -25,6 +25,7 @@ import org.junit.Test;
import org.springframework.boot.context.properties.bind.BindException; import org.springframework.boot.context.properties.bind.BindException;
import org.springframework.boot.context.properties.bind.validation.BindValidationException; import org.springframework.boot.context.properties.bind.validation.BindValidationException;
import org.springframework.boot.context.properties.bind.validation.ValidationErrors; import org.springframework.boot.context.properties.bind.validation.ValidationErrors;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.env.MapPropertySource; import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.MutablePropertySources; import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.StandardEnvironment; import org.springframework.core.env.StandardEnvironment;
@ -61,7 +62,7 @@ public class ConfigurationPropertiesBinderTests {
ConfigurationPropertiesBinder binder = new ConfigurationPropertiesBinder( ConfigurationPropertiesBinder binder = new ConfigurationPropertiesBinder(
this.environment.getPropertySources(), null, null); this.environment.getPropertySources(), null, null);
PersonProperties target = new PersonProperties(); PersonProperties target = new PersonProperties();
binder.bind(target); bind(binder, target);
assertThat(target.name).isEqualTo("John Smith"); assertThat(target.name).isEqualTo("John Smith");
assertThat(target.age).isEqualTo(42); assertThat(target.age).isEqualTo(42);
} }
@ -74,7 +75,7 @@ public class ConfigurationPropertiesBinderTests {
this.environment.getPropertySources(), null, null); this.environment.getPropertySources(), null, null);
PersonProperties target = new PersonProperties(); PersonProperties target = new PersonProperties();
try { try {
binder.bind(target); bind(binder, target);
fail("Expected exception"); fail("Expected exception");
} }
catch (ConfigurationPropertiesBindingException ex) { catch (ConfigurationPropertiesBindingException ex) {
@ -92,17 +93,10 @@ public class ConfigurationPropertiesBinderTests {
ConfigurationPropertiesBinder binder = new ConfigurationPropertiesBinder( ConfigurationPropertiesBinder binder = new ConfigurationPropertiesBinder(
this.environment.getPropertySources(), null, null); this.environment.getPropertySources(), null, null);
PropertyWithIgnoreInvalidFields target = new PropertyWithIgnoreInvalidFields(); PropertyWithIgnoreInvalidFields target = new PropertyWithIgnoreInvalidFields();
binder.bind(target); bind(binder, target);
assertThat(target.getBar()).isEqualTo(0); assertThat(target.getBar()).isEqualTo(0);
} }
@Test
public void bindNonAnnotatedObject() {
ConfigurationPropertiesBinder binder = new ConfigurationPropertiesBinder(
this.environment.getPropertySources(), null, null);
binder.bind("FooBar");
}
@Test @Test
public void bindToEnum() { public void bindToEnum() {
bindToEnum("test.theValue=foo"); bindToEnum("test.theValue=foo");
@ -120,7 +114,7 @@ public class ConfigurationPropertiesBinderTests {
ConfigurationPropertiesBinder binder = new ConfigurationPropertiesBinder( ConfigurationPropertiesBinder binder = new ConfigurationPropertiesBinder(
this.environment.getPropertySources(), null, null); this.environment.getPropertySources(), null, null);
PropertyWithEnum target = new PropertyWithEnum(); PropertyWithEnum target = new PropertyWithEnum();
binder.bind(target); bind(binder, target);
assertThat(target.getTheValue()).isEqualTo(FooEnum.FOO); assertThat(target.getTheValue()).isEqualTo(FooEnum.FOO);
} }
@ -136,7 +130,7 @@ public class ConfigurationPropertiesBinderTests {
ConfigurationPropertiesBinder binder = new ConfigurationPropertiesBinder( ConfigurationPropertiesBinder binder = new ConfigurationPropertiesBinder(
this.environment.getPropertySources(), null, null); this.environment.getPropertySources(), null, null);
PropertyWithEnum target = new PropertyWithEnum(); PropertyWithEnum target = new PropertyWithEnum();
binder.bind(target); bind(binder, target);
assertThat(target.getTheValues()).contains(expected); assertThat(target.getTheValues()).contains(expected);
} }
@ -147,7 +141,7 @@ public class ConfigurationPropertiesBinderTests {
ConfigurationPropertiesBinder binder = new ConfigurationPropertiesBinder( ConfigurationPropertiesBinder binder = new ConfigurationPropertiesBinder(
this.environment.getPropertySources(), null, null); this.environment.getPropertySources(), null, null);
PropertyWithCharArray target = new PropertyWithCharArray(); PropertyWithCharArray target = new PropertyWithCharArray();
binder.bind(target); bind(binder, target);
assertThat(target.getChars()).isEqualTo("word".toCharArray()); assertThat(target.getChars()).isEqualTo("word".toCharArray());
} }
@ -163,7 +157,7 @@ public class ConfigurationPropertiesBinderTests {
ConfigurationPropertiesBinder binder = new ConfigurationPropertiesBinder( ConfigurationPropertiesBinder binder = new ConfigurationPropertiesBinder(
this.environment.getPropertySources(), null, null); this.environment.getPropertySources(), null, null);
PropertyWithRelaxedNames target = new PropertyWithRelaxedNames(); PropertyWithRelaxedNames target = new PropertyWithRelaxedNames();
binder.bind(target); bind(binder, target);
assertThat(target.getFooBar()).isEqualTo("test2"); assertThat(target.getFooBar()).isEqualTo("test2");
assertThat(target.getBarBAZ()).isEqualTo("testb"); assertThat(target.getBarBAZ()).isEqualTo("testb");
} }
@ -175,7 +169,7 @@ public class ConfigurationPropertiesBinderTests {
ConfigurationPropertiesBinder binder = new ConfigurationPropertiesBinder( ConfigurationPropertiesBinder binder = new ConfigurationPropertiesBinder(
this.environment.getPropertySources(), null, null); this.environment.getPropertySources(), null, null);
PropertyWithNestedValue target = new PropertyWithNestedValue(); PropertyWithNestedValue target = new PropertyWithNestedValue();
binder.bind(target); bind(binder, target);
assertThat(target.getNested().getValue()).isEqualTo("test1"); assertThat(target.getNested().getValue()).isEqualTo("test1");
} }
@ -186,7 +180,7 @@ public class ConfigurationPropertiesBinderTests {
ConfigurationPropertiesBinder binder = new ConfigurationPropertiesBinder( ConfigurationPropertiesBinder binder = new ConfigurationPropertiesBinder(
this.environment.getPropertySources(), null, null); this.environment.getPropertySources(), null, null);
PropertiesWithMap target = new PropertiesWithMap(); PropertiesWithMap target = new PropertiesWithMap();
binder.bind(target); bind(binder, target);
assertThat(target.getMap()).containsOnly(entry("foo", "bar")); assertThat(target.getMap()).containsOnly(entry("foo", "bar"));
} }
@ -199,7 +193,7 @@ public class ConfigurationPropertiesBinderTests {
ConfigurationPropertiesBinder binder = new ConfigurationPropertiesBinder( ConfigurationPropertiesBinder binder = new ConfigurationPropertiesBinder(
propertySources, null, null); propertySources, null, null);
PropertiesWithComplexMap target = new PropertiesWithComplexMap(); PropertiesWithComplexMap target = new PropertiesWithComplexMap();
binder.bind(target); bind(binder, target);
assertThat(target.getMap()).containsOnlyKeys("foo"); assertThat(target.getMap()).containsOnlyKeys("foo");
assertThat(target.getMap().get("foo")).containsOnly(entry("bar", "baz")); assertThat(target.getMap().get("foo")).containsOnly(entry("bar", "baz"));
} }
@ -214,7 +208,7 @@ public class ConfigurationPropertiesBinderTests {
ConfigurationPropertiesBinder binder = new ConfigurationPropertiesBinder( ConfigurationPropertiesBinder binder = new ConfigurationPropertiesBinder(
propertySources, null, null); propertySources, null, null);
PersonProperties target = new PersonProperties(); PersonProperties target = new PersonProperties();
binder.bind(target); bind(binder, target);
assertThat(target.name).isEqualTo("Jane"); assertThat(target.name).isEqualTo("Jane");
} }
@ -226,7 +220,7 @@ public class ConfigurationPropertiesBinderTests {
this.environment.getPropertySources(), null, null); this.environment.getPropertySources(), null, null);
PropertyWithValidatingSetter target = new PropertyWithValidatingSetter(); PropertyWithValidatingSetter target = new PropertyWithValidatingSetter();
try { try {
binder.bind(target); bind(binder, target);
fail("Expected exception"); fail("Expected exception");
} }
catch (ConfigurationPropertiesBindingException ex) { catch (ConfigurationPropertiesBindingException ex) {
@ -255,7 +249,7 @@ public class ConfigurationPropertiesBinderTests {
ConfigurationPropertiesBinder binder = new ConfigurationPropertiesBinder( ConfigurationPropertiesBinder binder = new ConfigurationPropertiesBinder(
this.environment.getPropertySources(), null, validator); this.environment.getPropertySources(), null, validator);
PropertyWithValidatingSetter target = new PropertyWithValidatingSetter(); PropertyWithValidatingSetter target = new PropertyWithValidatingSetter();
binder.bind(target); bind(binder, target);
assertThat(target.getFoo()).isEqualTo("bar"); assertThat(target.getFoo()).isEqualTo("bar");
verify(validator, times(0)).validate(eq(target), any(Errors.class)); verify(validator, times(0)).validate(eq(target), any(Errors.class));
} }
@ -263,7 +257,7 @@ public class ConfigurationPropertiesBinderTests {
private ValidationErrors bindWithValidationErrors( private ValidationErrors bindWithValidationErrors(
ConfigurationPropertiesBinder binder, Object target) { ConfigurationPropertiesBinder binder, Object target) {
try { try {
binder.bind(target); bind(binder, target);
throw new AssertionError("Should have failed to bind " + target); throw new AssertionError("Should have failed to bind " + target);
} }
catch (ConfigurationPropertiesBindingException ex) { catch (ConfigurationPropertiesBindingException ex) {
@ -273,6 +267,11 @@ public class ConfigurationPropertiesBinderTests {
} }
} }
private void bind(ConfigurationPropertiesBinder binder, Object target) {
binder.bind(target, AnnotationUtils
.findAnnotation(target.getClass(), ConfigurationProperties.class));
}
@ConfigurationProperties(value = "person", ignoreUnknownFields = false) @ConfigurationProperties(value = "person", ignoreUnknownFields = false)
static class PersonProperties { static class PersonProperties {