From 0d4360ea203070dc5b63e493215290bfb580de5b Mon Sep 17 00:00:00 2001 From: Keith Donald Date: Thu, 13 Nov 2008 16:38:29 +0000 Subject: [PATCH] bug fixes --- .../webflow/validation/ValidationHelper.java | 88 ++++--- .../validation/ValidationHelperTests.java | 214 +++++++++++++++++- 2 files changed, 263 insertions(+), 39 deletions(-) diff --git a/spring-webflow/src/main/java/org/springframework/webflow/validation/ValidationHelper.java b/spring-webflow/src/main/java/org/springframework/webflow/validation/ValidationHelper.java index 86641802..07cf89ef 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/validation/ValidationHelper.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/validation/ValidationHelper.java @@ -69,7 +69,7 @@ public class ValidationHelper { */ public ValidationHelper(Object model, RequestContext requestContext, String eventId, String modelName, ExpressionParser expressionParser, MappingResults mappingResults) { - Assert.notNull(model, "The model to validate is requried"); + Assert.notNull(model, "The model to validate is required"); Assert.notNull(requestContext, "The request context for the validator is required"); this.model = model; this.requestContext = requestContext; @@ -90,44 +90,56 @@ public class ValidationHelper { } } - private boolean invokeModelValidationMethod(Object model) { - boolean methodInvoked = invokeValidateMethodForCurrentState(model); - if (!methodInvoked) { - methodInvoked = invokeDefaultValidateMethod(model); - } - return methodInvoked; + private void invokeModelValidationMethod(Object model) { + invokeValidateMethodForCurrentState(model); + invokeDefaultValidateMethod(model); } private boolean invokeValidateMethodForCurrentState(Object model) { String methodName = "validate" + StringUtils.capitalize(requestContext.getCurrentState().getId()); + // preferred Method validateMethod = ReflectionUtils.findMethod(model.getClass(), methodName, new Class[] { ValidationContext.class }); if (validateMethod != null) { ReflectionUtils.invokeMethod(validateMethod, model, new Object[] { new DefaultValidationContext( requestContext, eventId, mappingResults) }); return true; - } else { - validateMethod = ReflectionUtils.findMethod(model.getClass(), methodName, - new Class[] { MessageContext.class }); - if (validateMethod != null) { - ReflectionUtils - .invokeMethod(validateMethod, model, new Object[] { requestContext.getMessageContext() }); - return true; - } + } + // web flow 2.0.3 or < compatibility only + validateMethod = ReflectionUtils.findMethod(model.getClass(), methodName, new Class[] { MessageContext.class }); + if (validateMethod != null) { + ReflectionUtils.invokeMethod(validateMethod, model, new Object[] { requestContext.getMessageContext() }); + return true; + } + // mvc 2 compatibility only + validateMethod = ReflectionUtils.findMethod(model.getClass(), methodName, new Class[] { Errors.class }); + if (validateMethod != null) { + MessageContextErrors errors = new MessageContextErrors(requestContext.getMessageContext(), modelName, + model, expressionParser, mappingResults); + ReflectionUtils.invokeMethod(validateMethod, model, new Object[] { errors }); + return true; } return false; } private boolean invokeDefaultValidateMethod(Object model) { + // preferred Method validateMethod = ReflectionUtils.findMethod(model.getClass(), "validate", new Class[] { ValidationContext.class }); if (validateMethod != null) { ReflectionUtils.invokeMethod(validateMethod, model, new Object[] { new DefaultValidationContext( requestContext, eventId, mappingResults) }); return true; - } else { - return false; } + // mvc 2 compatibility only + validateMethod = ReflectionUtils.findMethod(model.getClass(), "validate", new Class[] { Errors.class }); + if (validateMethod != null) { + MessageContextErrors errors = new MessageContextErrors(requestContext.getMessageContext(), modelName, + model, expressionParser, mappingResults); + ReflectionUtils.invokeMethod(validateMethod, model, new Object[] { errors }); + return true; + } + return false; } private Object getModelValidator() { @@ -141,25 +153,14 @@ public class ValidationHelper { return null; } - private boolean invokeModelValidator(Object model, Object validator) { - if (validator instanceof Validator) { - // TODO - fallback to validator last not first - // existing validator, just invoke it - MessageContextErrors errors = new MessageContextErrors(requestContext.getMessageContext(), modelName, - model, expressionParser, mappingResults); - ((Validator) validator).validate(model, errors); - return true; - } - // try reflection - boolean methodInvoked = invokeValidatorValidateMethodForCurrentState(model, validator); - if (!methodInvoked) { - methodInvoked = invokeValidatorDefaultValidateMethod(model, validator); - } - return methodInvoked; + private void invokeModelValidator(Object model, Object validator) { + invokeValidatorValidateMethodForCurrentState(model, validator); + invokeValidatorDefaultValidateMethod(model, validator); } private boolean invokeValidatorValidateMethodForCurrentState(Object model, Object validator) { String methodName = "validate" + StringUtils.capitalize(requestContext.getCurrentState().getId()); + // preferred Method validateMethod = ReflectionUtils.findMethod(validator.getClass(), methodName, new Class[] { model.getClass(), ValidationContext.class }); if (validateMethod != null) { @@ -167,7 +168,7 @@ public class ValidationHelper { new DefaultValidationContext(requestContext, eventId, mappingResults) }); return true; } - // web flow 2.0.3 or < compatibility only + // mvc 2 compatibility only validateMethod = ReflectionUtils.findMethod(validator.getClass(), methodName, new Class[] { model.getClass(), Errors.class }); if (validateMethod != null) { @@ -176,6 +177,7 @@ public class ValidationHelper { ReflectionUtils.invokeMethod(validateMethod, validator, new Object[] { model, errors }); return true; } + // web flow 2.0.0 to 2.0.3 compatibility only [to remove in web flow 3] validateMethod = ReflectionUtils.findMethod(validator.getClass(), methodName, new Class[] { model.getClass(), MessageContext.class }); if (validateMethod != null) { @@ -187,15 +189,31 @@ public class ValidationHelper { } private boolean invokeValidatorDefaultValidateMethod(Object model, Object validator) { + if (validator instanceof Validator) { + // supports existing validators + MessageContextErrors errors = new MessageContextErrors(requestContext.getMessageContext(), modelName, + model, expressionParser, mappingResults); + ((Validator) validator).validate(model, errors); + return true; + } + // preferred Method validateMethod = ReflectionUtils.findMethod(validator.getClass(), "validate", new Class[] { model.getClass(), ValidationContext.class }); if (validateMethod != null) { ReflectionUtils.invokeMethod(validateMethod, validator, new Object[] { model, new DefaultValidationContext(requestContext, eventId, mappingResults) }); return true; - } else { - return false; } + // mvc 2 compatibility only + validateMethod = ReflectionUtils.findMethod(validator.getClass(), "validate", new Class[] { model.getClass(), + Errors.class }); + if (validateMethod != null) { + MessageContextErrors errors = new MessageContextErrors(requestContext.getMessageContext(), modelName, + model, expressionParser, mappingResults); + ReflectionUtils.invokeMethod(validateMethod, validator, new Object[] { model, errors }); + return true; + } + return false; } } \ No newline at end of file diff --git a/spring-webflow/src/test/java/org/springframework/webflow/validation/ValidationHelperTests.java b/spring-webflow/src/test/java/org/springframework/webflow/validation/ValidationHelperTests.java index 202958ab..f3ee5eaa 100644 --- a/spring-webflow/src/test/java/org/springframework/webflow/validation/ValidationHelperTests.java +++ b/spring-webflow/src/test/java/org/springframework/webflow/validation/ValidationHelperTests.java @@ -18,21 +18,28 @@ package org.springframework.webflow.validation; import junit.framework.TestCase; import org.springframework.binding.message.MessageContext; +import org.springframework.binding.validation.ValidationContext; import org.springframework.context.support.StaticApplicationContext; +import org.springframework.validation.Errors; +import org.springframework.validation.Validator; import org.springframework.webflow.engine.Flow; -import org.springframework.webflow.test.MockRequestContext; +import org.springframework.webflow.engine.StubViewFactory; +import org.springframework.webflow.engine.ViewState; +import org.springframework.webflow.test.MockRequestControlContext; /** * Unit test for {@link ValidationHelper} */ public class ValidationHelperTests extends TestCase { - private MockRequestContext requestContext; + private MockRequestControlContext requestContext; + private String eventId; + private String modelName; protected void setUp() throws Exception { - requestContext = new MockRequestContext(); + requestContext = new MockRequestControlContext(); eventId = "userEvent"; modelName = "model"; } @@ -47,7 +54,7 @@ public class ValidationHelperTests extends TestCase { assertEquals(0, messages.getMessagesBySource("validationcontext").length); } - public void testValidateWithValidatioContext() { + public void testValidateWithValidationContext() { Object model = new StubModelValidationContext(); ValidationHelper helper = new ValidationHelper(model, requestContext, eventId, modelName, null, null); helper.validate(); @@ -100,4 +107,203 @@ public class ValidationHelperTests extends TestCase { assertEquals(1, messages.getMessagesBySource("validationcontext-external").length); } + public void testStateAndFallbackModelValidationMethodInvoked() { + Model model = new Model(); + ValidationHelper helper = new ValidationHelper(model, requestContext, eventId, modelName, null, null); + ViewState state1 = new ViewState(requestContext.getRootFlow(), "state1", new StubViewFactory()); + requestContext.setCurrentState(state1); + helper.validate(); + assertTrue(model.state1Invoked); + assertTrue(model.fallbackInvoked); + } + + public void testFallbackModelValidationMethodInvoked() { + Model model = new Model(); + ValidationHelper helper = new ValidationHelper(model, requestContext, eventId, modelName, null, null); + ViewState state1 = new ViewState(requestContext.getRootFlow(), "state2", new StubViewFactory()); + requestContext.setCurrentState(state1); + helper.validate(); + assertFalse(model.state1Invoked); + assertTrue(model.fallbackInvoked); + } + + public void testStateAndFallbackErrorsModelValidationMethodInvoked() { + ErrorsModel model = new ErrorsModel(); + ValidationHelper helper = new ValidationHelper(model, requestContext, eventId, modelName, null, null); + ViewState state1 = new ViewState(requestContext.getRootFlow(), "state1", new StubViewFactory()); + requestContext.setCurrentState(state1); + helper.validate(); + assertTrue(model.state1Invoked); + assertTrue(model.fallbackInvoked); + } + + public void testFallbackModelErrorsValidationMethodInvoked() { + ErrorsModel model = new ErrorsModel(); + ValidationHelper helper = new ValidationHelper(model, requestContext, eventId, modelName, null, null); + ViewState state1 = new ViewState(requestContext.getRootFlow(), "state2", new StubViewFactory()); + requestContext.setCurrentState(state1); + helper.validate(); + assertFalse(model.state1Invoked); + assertTrue(model.fallbackInvoked); + } + + public void testStateAndFallbackValidatorInvoked() { + ModelValidator validator = new ModelValidator(); + StaticApplicationContext applicationContext = new StaticApplicationContext(); + applicationContext.getBeanFactory().registerSingleton("modelValidator", validator); + requestContext.getRootFlow().setApplicationContext(applicationContext); + + Object model = new Object(); + ValidationHelper helper = new ValidationHelper(model, requestContext, eventId, modelName, null, null); + ViewState state1 = new ViewState(requestContext.getRootFlow(), "state1", new StubViewFactory()); + requestContext.setCurrentState(state1); + helper.validate(); + assertTrue(validator.state1Invoked); + assertTrue(validator.fallbackInvoked); + } + + public void testFallbackValidatorInvoked() { + ModelValidator validator = new ModelValidator(); + StaticApplicationContext applicationContext = new StaticApplicationContext(); + applicationContext.getBeanFactory().registerSingleton("modelValidator", validator); + requestContext.getRootFlow().setApplicationContext(applicationContext); + + Object model = new Object(); + ValidationHelper helper = new ValidationHelper(model, requestContext, eventId, modelName, null, null); + ViewState state1 = new ViewState(requestContext.getRootFlow(), "state2", new StubViewFactory()); + requestContext.setCurrentState(state1); + helper.validate(); + assertFalse(validator.state1Invoked); + assertTrue(validator.fallbackInvoked); + } + + public void testStateAndFallbackLegacyValidatorInvoked() { + LegacyModelValidator validator = new LegacyModelValidator(); + StaticApplicationContext applicationContext = new StaticApplicationContext(); + applicationContext.getBeanFactory().registerSingleton("modelValidator", validator); + requestContext.getRootFlow().setApplicationContext(applicationContext); + + Object model = new Object(); + ValidationHelper helper = new ValidationHelper(model, requestContext, eventId, modelName, null, null); + ViewState state1 = new ViewState(requestContext.getRootFlow(), "state1", new StubViewFactory()); + requestContext.setCurrentState(state1); + helper.validate(); + assertTrue(validator.state1Invoked); + assertTrue(validator.fallbackInvoked); + } + + public void testFallbackLegacyValidatorInvoked() { + LegacyModelValidator validator = new LegacyModelValidator(); + StaticApplicationContext applicationContext = new StaticApplicationContext(); + applicationContext.getBeanFactory().registerSingleton("modelValidator", validator); + requestContext.getRootFlow().setApplicationContext(applicationContext); + + Object model = new Object(); + ValidationHelper helper = new ValidationHelper(model, requestContext, eventId, modelName, null, null); + ViewState state1 = new ViewState(requestContext.getRootFlow(), "state2", new StubViewFactory()); + requestContext.setCurrentState(state1); + helper.validate(); + assertFalse(validator.state1Invoked); + assertTrue(validator.fallbackInvoked); + } + + public void testStateAndFallbackErrorsValidatorInvoked() { + ErrorsModelValidator validator = new ErrorsModelValidator(); + StaticApplicationContext applicationContext = new StaticApplicationContext(); + applicationContext.getBeanFactory().registerSingleton("modelValidator", validator); + requestContext.getRootFlow().setApplicationContext(applicationContext); + + Object model = new Object(); + ValidationHelper helper = new ValidationHelper(model, requestContext, eventId, modelName, null, null); + ViewState state1 = new ViewState(requestContext.getRootFlow(), "state1", new StubViewFactory()); + requestContext.setCurrentState(state1); + helper.validate(); + assertTrue(validator.state1Invoked); + assertTrue(validator.fallbackInvoked); + } + + public void testFallbackErrorsValidatorInvoked() { + ErrorsModelValidator validator = new ErrorsModelValidator(); + StaticApplicationContext applicationContext = new StaticApplicationContext(); + applicationContext.getBeanFactory().registerSingleton("modelValidator", validator); + requestContext.getRootFlow().setApplicationContext(applicationContext); + + Object model = new Object(); + ValidationHelper helper = new ValidationHelper(model, requestContext, eventId, modelName, null, null); + ViewState state1 = new ViewState(requestContext.getRootFlow(), "state2", new StubViewFactory()); + requestContext.setCurrentState(state1); + helper.validate(); + assertFalse(validator.state1Invoked); + assertTrue(validator.fallbackInvoked); + } + + public static class Model { + private boolean state1Invoked; + private boolean fallbackInvoked; + + public void validateState1(ValidationContext context) { + state1Invoked = true; + } + + public void validate(ValidationContext context) { + fallbackInvoked = true; + } + } + + public static class ErrorsModel { + private boolean state1Invoked; + private boolean fallbackInvoked; + + public void validateState1(Errors errors) { + state1Invoked = true; + } + + public void validate(Errors errors) { + fallbackInvoked = true; + } + } + + public static class LegacyModelValidator implements Validator { + private boolean state1Invoked; + private boolean fallbackInvoked; + + public void validateState1(Object object, Errors errors) { + state1Invoked = true; + } + + public void validate(Object object, Errors errors) { + fallbackInvoked = true; + } + + public boolean supports(Class clazz) { + return true; + } + } + + public static class ModelValidator { + private boolean state1Invoked; + private boolean fallbackInvoked; + + public void validateState1(Object object, ValidationContext context) { + state1Invoked = true; + } + + public void validate(Object object, ValidationContext context) { + fallbackInvoked = true; + } + } + + public static class ErrorsModelValidator { + private boolean state1Invoked; + private boolean fallbackInvoked; + + public void validateState1(Object object, Errors context) { + state1Invoked = true; + } + + public void validate(Object object, Errors context) { + fallbackInvoked = true; + } + } + }