From b345fc857407e7457cbfb2e4bec259fae84a1a32 Mon Sep 17 00:00:00 2001 From: Madhura Bhave Date: Thu, 10 Jan 2019 12:56:06 -0800 Subject: [PATCH] Fix validation when key matching the prefix is set Fixes gh-15597 --- .../validation/ValidationBindHandler.java | 11 +++++ .../ValidationBindHandlerTests.java | 49 +++++++++++++++++-- 2 files changed, 57 insertions(+), 3 deletions(-) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/validation/ValidationBindHandler.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/validation/ValidationBindHandler.java index dcf5faf0c4e..f02c169821e 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/validation/ValidationBindHandler.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/validation/ValidationBindHandler.java @@ -76,6 +76,17 @@ public class ValidationBindHandler extends AbstractBindHandler { super.onFinish(name, target, context, result); } + @Override + public Object onFailure(ConfigurationPropertyName name, Bindable target, + BindContext context, Exception error) throws Exception { + Object result = super.onFailure(name, target, context, error); + validate(name, target, context, null); + if (!this.exceptions.isEmpty()) { + throw this.exceptions.pop(); + } + return result; + } + private void validate(ConfigurationPropertyName name, Bindable target, BindContext context, Object result) { Object validationTarget = getValidationTarget(target, context, result); diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/validation/ValidationBindHandlerTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/validation/ValidationBindHandlerTests.java index db5780e98f6..a96e437926f 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/validation/ValidationBindHandlerTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/validation/ValidationBindHandlerTests.java @@ -27,6 +27,8 @@ import javax.validation.constraints.NotNull; import org.junit.Before; import org.junit.Test; +import org.springframework.boot.context.properties.bind.AbstractBindHandler; +import org.springframework.boot.context.properties.bind.BindContext; import org.springframework.boot.context.properties.bind.BindException; import org.springframework.boot.context.properties.bind.Bindable; import org.springframework.boot.context.properties.bind.Binder; @@ -35,6 +37,7 @@ import org.springframework.boot.context.properties.source.ConfigurationPropertyN import org.springframework.boot.context.properties.source.ConfigurationPropertySource; import org.springframework.boot.context.properties.source.MockConfigurationPropertySource; import org.springframework.boot.origin.Origin; +import org.springframework.core.convert.ConverterNotFoundException; import org.springframework.validation.FieldError; import org.springframework.validation.ObjectError; import org.springframework.validation.annotation.Validated; @@ -57,12 +60,14 @@ public class ValidationBindHandlerTests { private Binder binder; + private LocalValidatorFactoryBean validator; + @Before public void setup() { this.binder = new Binder(this.sources); - LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean(); - validator.afterPropertiesSet(); - this.handler = new ValidationBindHandler(validator); + this.validator = new LocalValidatorFactoryBean(); + this.validator.afterPropertiesSet(); + this.handler = new ValidationBindHandler(this.validator); } @Test @@ -162,6 +167,34 @@ public class ValidationBindHandlerTests { this.handler); } + @Test + public void bindShouldNotValidateIfOtherHandlersInChainThrowError() { + this.sources.add(new MockConfigurationPropertySource("foo", "hello")); + ExampleValidatedBean bean = new ExampleValidatedBean(); + assertThatExceptionOfType(BindException.class) + .isThrownBy( + () -> this.binder.bind("foo", + Bindable.of(ExampleValidatedBean.class) + .withExistingValue(bean), + this.handler)) + .withCauseInstanceOf(ConverterNotFoundException.class); + } + + @Test + public void bindShouldValidateIfOtherHandlersInChainIgnoreError() { + TestHandler testHandler = new TestHandler(); + this.handler = new ValidationBindHandler(testHandler, this.validator); + this.sources.add(new MockConfigurationPropertySource("foo", "hello")); + ExampleValidatedBean bean = new ExampleValidatedBean(); + assertThatExceptionOfType(BindException.class) + .isThrownBy( + () -> this.binder.bind("foo", + Bindable.of(ExampleValidatedBean.class) + .withExistingValue(bean), + this.handler)) + .withCauseInstanceOf(BindValidationException.class); + } + private BindValidationException bindAndExpectValidationError(Runnable action) { try { action.run(); @@ -265,4 +298,14 @@ public class ValidationBindHandlerTests { } + static class TestHandler extends AbstractBindHandler { + + @Override + public Object onFailure(ConfigurationPropertyName name, Bindable target, + BindContext context, Exception error) throws Exception { + return null; + } + + } + }