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 30982e223b..2b47658654 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 @@ -16,10 +16,8 @@ package org.springframework.boot.context.properties.bind.validation; -import java.util.Deque; import java.util.LinkedHashMap; import java.util.LinkedHashSet; -import java.util.LinkedList; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; @@ -52,7 +50,7 @@ public class ValidationBindHandler extends AbstractBindHandler { private final Set boundProperties = new LinkedHashSet<>(); - private final Deque exceptions = new LinkedList<>(); + private BindValidationException exception; public ValidationBindHandler(Validator... validators) { this.validators = validators; @@ -94,7 +92,7 @@ public class ValidationBindHandler extends AbstractBindHandler { this.boundTypes.clear(); this.boundResults.clear(); this.boundProperties.clear(); - this.exceptions.clear(); + this.exception = null; } @Override @@ -105,13 +103,15 @@ public class ValidationBindHandler extends AbstractBindHandler { } private void validate(ConfigurationPropertyName name, Bindable target, BindContext context, Object result) { - Object validationTarget = getValidationTarget(target, context, result); - Class validationType = target.getBoxedType().resolve(); - if (validationTarget != null) { - validateAndPush(name, validationTarget, validationType); + if (this.exception == null) { + Object validationTarget = getValidationTarget(target, context, result); + Class validationType = target.getBoxedType().resolve(); + if (validationTarget != null) { + validateAndPush(name, validationTarget, validationType); + } } - if (context.getDepth() == 0 && !this.exceptions.isEmpty()) { - throw this.exceptions.pop(); + if (context.getDepth() == 0 && this.exception != null) { + throw this.exception; } } @@ -134,7 +134,7 @@ public class ValidationBindHandler extends AbstractBindHandler { } } if (result != null && result.hasErrors()) { - this.exceptions.push(new BindValidationException(result.getValidationErrors())); + this.exception = new BindValidationException(result.getValidationErrors()); } } 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 1c1cc730ac..a83e29ed4d 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 @@ -201,6 +201,15 @@ class ValidationBindHandlerTests { assertThat(cause.getMessage()).contains("rejected value [2]"); } + @Test + void validationShouldBeSkippedIfPreviousValidationErrorPresent() { + this.sources.add(new MockConfigurationPropertySource("foo.inner.person-age", 2)); + BindValidationException cause = bindAndExpectValidationError(() -> this.binder + .bind(ConfigurationPropertyName.of("foo"), Bindable.of(ExampleCamelCase.class), this.handler)); + FieldError fieldError = (FieldError) cause.getValidationErrors().getAllErrors().get(0); + assertThat(fieldError.getField()).isEqualTo("personAge"); + } + private BindValidationException bindAndExpectValidationError(Runnable action) { try { action.run();