Commit edea2238 authored by Phillip Webb's avatar Phillip Webb

Merge branch '2.1.x'

Closes gh-17422
parents e0048f23 2f88dd73
...@@ -92,7 +92,9 @@ public interface BindHandler { ...@@ -92,7 +92,9 @@ public interface BindHandler {
} }
/** /**
* Called when binding finishes, regardless of whether the property was bound or not. * Called when binding finishes with either bound or unbound result. This method will
* not be called when binding failed, even if a handler rurns a result from
* {@link #onFailure}.
* @param name the name of the element being bound * @param name the name of the element being bound
* @param target the item being bound * @param target the item being bound
* @param context the bind context * @param context the bind context
......
...@@ -66,18 +66,21 @@ public class ValidationBindHandler extends AbstractBindHandler { ...@@ -66,18 +66,21 @@ public class ValidationBindHandler extends AbstractBindHandler {
} }
@Override @Override
public void onFinish(ConfigurationPropertyName name, Bindable<?> target, BindContext context, Object result) public Object onFailure(ConfigurationPropertyName name, Bindable<?> target, BindContext context, Exception error)
throws Exception { throws Exception {
Object result = super.onFailure(name, target, context, error);
if (result != null) {
this.exceptions.clear();
}
validate(name, target, context, result); validate(name, target, context, result);
super.onFinish(name, target, context, result); return result;
} }
@Override @Override
public Object onFailure(ConfigurationPropertyName name, Bindable<?> target, BindContext context, Exception error) public void onFinish(ConfigurationPropertyName name, Bindable<?> target, BindContext context, Object result)
throws Exception { throws Exception {
Object result = super.onFailure(name, target, context, error); validate(name, target, context, result);
validate(name, target, context, null); super.onFinish(name, target, context, result);
return result;
} }
private void validate(ConfigurationPropertyName name, Bindable<?> target, BindContext context, Object result) { private void validate(ConfigurationPropertyName name, Bindable<?> target, BindContext context, Object result) {
......
...@@ -167,7 +167,7 @@ class ValidationBindHandlerTests { ...@@ -167,7 +167,7 @@ class ValidationBindHandlerTests {
@Test @Test
void bindShouldValidateIfOtherHandlersInChainIgnoreError() { void bindShouldValidateIfOtherHandlersInChainIgnoreError() {
TestHandler testHandler = new TestHandler(); TestHandler testHandler = new TestHandler(null);
this.handler = new ValidationBindHandler(testHandler, this.validator); this.handler = new ValidationBindHandler(testHandler, this.validator);
this.sources.add(new MockConfigurationPropertySource("foo", "hello")); this.sources.add(new MockConfigurationPropertySource("foo", "hello"));
ExampleValidatedBean bean = new ExampleValidatedBean(); ExampleValidatedBean bean = new ExampleValidatedBean();
...@@ -177,6 +177,21 @@ class ValidationBindHandlerTests { ...@@ -177,6 +177,21 @@ class ValidationBindHandlerTests {
.withCauseInstanceOf(BindValidationException.class); .withCauseInstanceOf(BindValidationException.class);
} }
@Test
void bindShouldValidateIfOtherHandlersInChainReplaceErrorWithResult() {
TestHandler testHandler = new TestHandler(new ExampleValidatedBeanSubclass());
this.handler = new ValidationBindHandler(testHandler, this.validator);
this.sources.add(new MockConfigurationPropertySource("foo", "hello"));
this.sources.add(new MockConfigurationPropertySource("foo.age", "bad"));
this.sources.add(new MockConfigurationPropertySource("foo.years", "99"));
ExampleValidatedBean bean = new ExampleValidatedBean();
assertThatExceptionOfType(BindException.class)
.isThrownBy(() -> this.binder.bind("foo",
Bindable.of(ExampleValidatedBean.class).withExistingValue(bean), this.handler))
.withCauseInstanceOf(BindValidationException.class)
.satisfies((ex) -> assertThat(ex.getCause()).hasMessageContaining("years"));
}
private BindValidationException bindAndExpectValidationError(Runnable action) { private BindValidationException bindAndExpectValidationError(Runnable action) {
try { try {
action.run(); action.run();
...@@ -219,6 +234,25 @@ class ValidationBindHandlerTests { ...@@ -219,6 +234,25 @@ class ValidationBindHandlerTests {
} }
public static class ExampleValidatedBeanSubclass extends ExampleValidatedBean {
@Min(100)
private int years;
ExampleValidatedBeanSubclass() {
setAge(20);
}
public int getYears() {
return this.years;
}
public void setYears(int years) {
this.years = years;
}
}
@Validated @Validated
public static class ExampleValidatedWithNestedBean { public static class ExampleValidatedWithNestedBean {
...@@ -286,10 +320,16 @@ class ValidationBindHandlerTests { ...@@ -286,10 +320,16 @@ class ValidationBindHandlerTests {
static class TestHandler extends AbstractBindHandler { static class TestHandler extends AbstractBindHandler {
private Object result;
TestHandler(Object result) {
this.result = result;
}
@Override @Override
public Object onFailure(ConfigurationPropertyName name, Bindable<?> target, BindContext context, public Object onFailure(ConfigurationPropertyName name, Bindable<?> target, BindContext context,
Exception error) throws Exception { Exception error) throws Exception {
return null; return this.result;
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment