Only validate target values on zero depth
Update `ValidationBindHandler` so that validation only occurs when a value is bound, or the bind depth is zero. This prevents validation from triggering getters which may throw an exception. Fixes gh-12227
This commit is contained in:
@@ -69,7 +69,7 @@ public class ValidationBindHandler extends AbstractBindHandler {
|
||||
@Override
|
||||
public void onFinish(ConfigurationPropertyName name, Bindable<?> target,
|
||||
BindContext context, Object result) throws Exception {
|
||||
validate(name, target, result);
|
||||
validate(name, target, context, result);
|
||||
if (context.getDepth() == 0 && !this.exceptions.isEmpty()) {
|
||||
throw this.exceptions.pop();
|
||||
}
|
||||
@@ -77,17 +77,18 @@ public class ValidationBindHandler extends AbstractBindHandler {
|
||||
}
|
||||
|
||||
private void validate(ConfigurationPropertyName name, Bindable<?> target,
|
||||
Object result) {
|
||||
Object validationTarget = getValidationTarget(target, result);
|
||||
BindContext context, Object result) {
|
||||
Object validationTarget = getValidationTarget(target, context, result);
|
||||
Class<?> validationType = target.getBoxedType().resolve();
|
||||
validate(name, validationTarget, validationType);
|
||||
}
|
||||
|
||||
private Object getValidationTarget(Bindable<?> target, Object result) {
|
||||
private Object getValidationTarget(Bindable<?> target, BindContext context,
|
||||
Object result) {
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
if (target.getValue() != null) {
|
||||
if (context.getDepth() == 0 && target.getValue() != null) {
|
||||
return target.getValue().get();
|
||||
}
|
||||
return null;
|
||||
|
||||
@@ -153,6 +153,19 @@ public class ValidationBindHandlerTests {
|
||||
this.handler));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bindShouldNotValidateDepthGreaterThanZero() {
|
||||
// gh-12227
|
||||
MockConfigurationPropertySource source = new MockConfigurationPropertySource();
|
||||
source.put("foo.bar", "baz");
|
||||
this.sources.add(source);
|
||||
ExampleValidatedBeanWithGetterException existingValue = new ExampleValidatedBeanWithGetterException();
|
||||
this.binder.bind(ConfigurationPropertyName.of("foo"),
|
||||
Bindable.of(ExampleValidatedBeanWithGetterException.class)
|
||||
.withExistingValue(existingValue),
|
||||
this.handler);
|
||||
}
|
||||
|
||||
private BindValidationException bindAndExpectValidationError(Runnable action) {
|
||||
try {
|
||||
action.run();
|
||||
@@ -244,6 +257,16 @@ public class ValidationBindHandlerTests {
|
||||
public void setAddress(String address) {
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Validated
|
||||
public static class ExampleValidatedBeanWithGetterException {
|
||||
|
||||
public int getAge() {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user