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 d29e09263d1..8ce9f32c8f0 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 @@ -296,10 +296,30 @@ public class ConfigurationPropertiesBindingPostProcessor implements BeanPostProc factory.bindPropertiesToTarget(); } catch (Exception ex) { - throw new BeanCreationException(beanName, "Could not bind properties", ex); + String targetClass = "[unknown]"; + if (target != null) { + ClassUtils.getShortName(target.getClass()); + } + throw new BeanCreationException(beanName, "Could not bind properties to " + + targetClass + " (" + getAnnotationDetails(annotation) + ")", ex); } } + private String getAnnotationDetails(ConfigurationProperties annotation) { + if (annotation == null) { + return ""; + } + StringBuilder details = new StringBuilder(); + details.append("target=").append( + (StringUtils.hasLength(annotation.value()) ? annotation.value() + : annotation.prefix())); + details.append(", ignoreInvalidFields=").append(annotation.ignoreInvalidFields()); + details.append(", ignoreUnknownFields=").append(annotation.ignoreUnknownFields()); + details.append(", ignoreNestedProperties=").append( + annotation.ignoreNestedProperties()); + return details.toString(); + } + private Validator determineValidator(Object bean) { if (ClassUtils.isAssignable(Validator.class, bean.getClass())) { if (this.validator == null) { diff --git a/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesBindingPostProcessorTests.java b/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesBindingPostProcessorTests.java index dedf4bf375c..debb44a57d1 100644 --- a/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesBindingPostProcessorTests.java +++ b/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesBindingPostProcessorTests.java @@ -20,7 +20,9 @@ import javax.annotation.PostConstruct; import javax.validation.constraints.NotNull; import org.junit.After; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.ExpectedException; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanCreationException; import org.springframework.beans.factory.FactoryBean; @@ -55,6 +57,9 @@ import static org.junit.Assert.fail; */ public class ConfigurationPropertiesBindingPostProcessorTests { + @Rule + public ExpectedException thrown = ExpectedException.none(); + private AnnotationConfigApplicationContext context; @After @@ -198,6 +203,16 @@ public class ConfigurationPropertiesBindingPostProcessorTests { equalTo("word".toCharArray())); } + @Test + public void notWritablePropertyException() throws Exception { + this.context = new AnnotationConfigApplicationContext(); + EnvironmentTestUtils.addEnvironment(this.context, "test.madeup:word"); + this.context.register(PropertyWithCharArray.class); + this.thrown.expect(BeanCreationException.class); + this.thrown.expectMessage("test"); + this.context.refresh(); + } + @Configuration @EnableConfigurationProperties public static class TestConfigurationWithValidatingSetter { @@ -314,7 +329,7 @@ public class ConfigurationPropertiesBindingPostProcessorTests { @Configuration @EnableConfigurationProperties - @ConfigurationProperties(prefix = "test") + @ConfigurationProperties(prefix = "test", ignoreUnknownFields = false) public static class PropertyWithCharArray { private char[] chars;