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:
Phillip Webb
2018-02-26 23:08:45 -08:00
parent 3244836003
commit 145400505d
2 changed files with 29 additions and 5 deletions

View File

@@ -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;

View File

@@ -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();
}
}
}