From 4ab77ca8937c021a11f9c271aa2144d2efe89150 Mon Sep 17 00:00:00 2001 From: Dave Syer Date: Thu, 5 Dec 2013 09:16:23 +0000 Subject: [PATCH] Added exceptionIfInvalid attribute to @ConfigurationProperties Default behaviour unchanged, but if you want to ignore validation errors you can switch them off for indivdual beans now. Fixes gh-144 --- .../bind/PropertiesConfigurationFactory.java | 6 ++ .../properties/ConfigurationProperties.java | 7 ++ ...urationPropertiesBindingPostProcessor.java | 1 + .../PropertiesConfigurationFactoryTests.java | 25 ++++++- .../EnableConfigurationPropertiesTests.java | 70 +++++++++++++++++++ 5 files changed, 106 insertions(+), 3 deletions(-) diff --git a/spring-boot/src/main/java/org/springframework/boot/bind/PropertiesConfigurationFactory.java b/spring-boot/src/main/java/org/springframework/boot/bind/PropertiesConfigurationFactory.java index 370405635e..ac1e88a10f 100644 --- a/spring-boot/src/main/java/org/springframework/boot/bind/PropertiesConfigurationFactory.java +++ b/spring-boot/src/main/java/org/springframework/boot/bind/PropertiesConfigurationFactory.java @@ -173,6 +173,12 @@ public class PropertiesConfigurationFactory implements FactoryBean, this.validator = validator; } + /** + * Flag to indicate that an exception should be raised if a Validator is available and + * validation fails. + * + * @param exceptionIfInvalid the flag to set + */ public void setExceptionIfInvalid(boolean exceptionIfInvalid) { this.exceptionIfInvalid = exceptionIfInvalid; } diff --git a/spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationProperties.java b/spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationProperties.java index 681245c58f..a161f62ddd 100644 --- a/spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationProperties.java +++ b/spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationProperties.java @@ -72,6 +72,13 @@ public @interface ConfigurationProperties { */ boolean ignoreUnknownFields() default true; + /** + * Flag to indicate that validation errors can be swallowed. If set they will be + * logged, but not propagate to the caller. + * @return the flag value (default true) + */ + boolean exceptionIfInvalid() default true; + /** * Optionally provide an explicit resource path to bind to instead of using the * default environment. diff --git a/spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationPropertiesBindingPostProcessor.java b/spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationPropertiesBindingPostProcessor.java index f23d0489a0..347f30b51c 100644 --- a/spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationPropertiesBindingPostProcessor.java +++ b/spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationPropertiesBindingPostProcessor.java @@ -302,6 +302,7 @@ public class ConfigurationPropertiesBindingPostProcessor implements BeanPostProc if (annotation != null) { factory.setIgnoreInvalidFields(annotation.ignoreInvalidFields()); factory.setIgnoreUnknownFields(annotation.ignoreUnknownFields()); + factory.setExceptionIfInvalid(annotation.exceptionIfInvalid()); factory.setIgnoreNestedProperties(annotation.ignoreNestedProperties()); String targetName = (StringUtils.hasLength(annotation.value()) ? annotation .value() : annotation.name()); diff --git a/spring-boot/src/test/java/org/springframework/boot/bind/PropertiesConfigurationFactoryTests.java b/spring-boot/src/test/java/org/springframework/boot/bind/PropertiesConfigurationFactoryTests.java index e894671441..eb571506d1 100644 --- a/spring-boot/src/test/java/org/springframework/boot/bind/PropertiesConfigurationFactoryTests.java +++ b/spring-boot/src/test/java/org/springframework/boot/bind/PropertiesConfigurationFactoryTests.java @@ -16,6 +16,8 @@ package org.springframework.boot.bind; +import java.io.IOException; + import javax.validation.Validation; import javax.validation.constraints.NotNull; @@ -85,6 +87,15 @@ public class PropertiesConfigurationFactoryTests { createFoo("bar: blah"); } + @Test + public void testValidationErrorCanBeSuppressed() throws Exception { + this.validator = new SpringValidatorAdapter(Validation + .buildDefaultValidatorFactory().getValidator()); + setupFactory(); + this.factory.setExceptionIfInvalid(false); + bindFoo("bar: blah"); + } + @Test public void testBindToNamedTarget() throws Exception { this.targetName = "foo"; @@ -93,15 +104,23 @@ public class PropertiesConfigurationFactoryTests { } private Foo createFoo(final String values) throws Exception { - this.factory = new PropertiesConfigurationFactory(Foo.class); + setupFactory(); + return bindFoo(values); + } + + private Foo bindFoo(final String values) throws Exception { this.factory.setProperties(PropertiesLoaderUtils .loadProperties(new ByteArrayResource(values.getBytes()))); + this.factory.afterPropertiesSet(); + return this.factory.getObject(); + } + + private void setupFactory() throws IOException { + this.factory = new PropertiesConfigurationFactory(Foo.class); this.factory.setValidator(this.validator); this.factory.setTargetName(this.targetName); this.factory.setIgnoreUnknownFields(this.ignoreUnknownFields); this.factory.setMessageSource(new StaticMessageSource()); - this.factory.afterPropertiesSet(); - return this.factory.getObject(); } // Foo needs to be public and to have setters for all properties diff --git a/spring-boot/src/test/java/org/springframework/boot/context/properties/EnableConfigurationPropertiesTests.java b/spring-boot/src/test/java/org/springframework/boot/context/properties/EnableConfigurationPropertiesTests.java index 289434c451..2075324dc2 100644 --- a/spring-boot/src/test/java/org/springframework/boot/context/properties/EnableConfigurationPropertiesTests.java +++ b/spring-boot/src/test/java/org/springframework/boot/context/properties/EnableConfigurationPropertiesTests.java @@ -21,9 +21,13 @@ import java.util.Arrays; import java.util.List; import javax.annotation.PostConstruct; +import javax.validation.constraints.NotNull; +import org.hamcrest.Matchers; import org.junit.After; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.ExpectedException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.TestUtils; import org.springframework.context.annotation.AnnotationConfigApplicationContext; @@ -31,6 +35,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.ImportResource; import org.springframework.stereotype.Component; +import org.springframework.validation.BindException; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; @@ -44,6 +49,9 @@ public class EnableConfigurationPropertiesTests { private AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); + @Rule + public ExpectedException expected = ExpectedException.none(); + @After public void close() { System.clearProperty("name"); @@ -111,6 +119,26 @@ public class EnableConfigurationPropertiesTests { assertEquals("foo", this.context.getBean(TestProperties.class).name); } + @Test + public void testExceptionOnValidation() { + this.context.register(ExceptionIfInvalidTestConfiguration.class); + TestUtils.addEnviroment(this.context, "name:foo"); + this.expected.expectCause(Matchers. instanceOf(BindException.class)); + this.context.refresh(); + } + + @Test + public void testNoExceptionOnValidation() { + this.context.register(NoExceptionIfInvalidTestConfiguration.class); + TestUtils.addEnviroment(this.context, "name:foo"); + this.context.refresh(); + assertEquals( + 1, + this.context + .getBeanNamesForType(NoExceptionIfInvalidTestProperties.class).length); + assertEquals("foo", this.context.getBean(TestProperties.class).name); + } + @Test public void testNestedPropertiesBinding() { this.context.register(NestedConfiguration.class); @@ -264,6 +292,16 @@ public class EnableConfigurationPropertiesTests { protected static class IgnoreNestedTestConfiguration { } + @Configuration + @EnableConfigurationProperties(ExceptionIfInvalidTestProperties.class) + protected static class ExceptionIfInvalidTestConfiguration { + } + + @Configuration + @EnableConfigurationProperties(NoExceptionIfInvalidTestProperties.class) + protected static class NoExceptionIfInvalidTestConfiguration { + } + @Configuration @EnableConfigurationProperties(DerivedProperties.class) protected static class DerivedConfiguration { @@ -379,6 +417,38 @@ public class EnableConfigurationPropertiesTests { } + @ConfigurationProperties + protected static class ExceptionIfInvalidTestProperties extends TestProperties { + + @NotNull + private String description; + + public String getDescription() { + return this.description; + } + + public void setDescription(String description) { + this.description = description; + } + + } + + @ConfigurationProperties(exceptionIfInvalid = false) + protected static class NoExceptionIfInvalidTestProperties extends TestProperties { + + @NotNull + private String description; + + public String getDescription() { + return this.description; + } + + public void setDescription(String description) { + this.description = description; + } + + } + protected static class MoreProperties { private String name;