diff --git a/build-spring-webflow/resources/changelog.txt b/build-spring-webflow/resources/changelog.txt index c915632e..7b469c18 100644 --- a/build-spring-webflow/resources/changelog.txt +++ b/build-spring-webflow/resources/changelog.txt @@ -2,7 +2,7 @@ SPRING WEB FLOW CHANGELOG ========================= http://www.springframework.org/webflow -Changes in version 2.0.6 (2009.02.26) +Changes in version 2.0.6 (2009.03.12) ------------------------------------- Bug Fixes * Fixed bug where FlowHandlerMapping could not handle null flow id scenarios (SWF-968) @@ -14,9 +14,10 @@ Bug Fixes * Fixed bug where form:checkbox and form:checkboxes tags did not apply type conversion properly in views rendered by Web Flows (SWF-986) * Fixed bug where Errors nestedPath attribute was not respected in views rendered by Web Flow (SWF-973) * Fixed bug where Errors nestedPath attribute was not respected when using Errors API programatically within a Validator called by Web Flow (SWF-973) +* Made MessageCodesResolver pluggable on MvcViewFactoryCreator; configure a DefaultMessageCodesResolver to resolve error message codes consistent with default Spring MVC behavior (SWF-977). Improvements -* Improved FlowExecution test documentation (SWF-???, SWF-???) +* Improved FlowExecution test documentation Changes in version 2.0.5 (14.11.2008) ------------------------------------- diff --git a/spring-webflow/src/main/java/org/springframework/webflow/mvc/builder/MvcViewFactoryCreator.java b/spring-webflow/src/main/java/org/springframework/webflow/mvc/builder/MvcViewFactoryCreator.java index 29746c1b..7f94e046 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/mvc/builder/MvcViewFactoryCreator.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/mvc/builder/MvcViewFactoryCreator.java @@ -25,6 +25,8 @@ import org.springframework.binding.expression.beanwrapper.BeanWrapperExpressionP import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.util.StringUtils; +import org.springframework.validation.DefaultMessageCodesResolver; +import org.springframework.validation.MessageCodesResolver; import org.springframework.web.servlet.View; import org.springframework.web.servlet.ViewResolver; import org.springframework.webflow.engine.builder.BinderConfiguration; @@ -34,6 +36,7 @@ import org.springframework.webflow.mvc.portlet.PortletMvcViewFactory; import org.springframework.webflow.mvc.servlet.ServletMvcViewFactory; import org.springframework.webflow.mvc.view.AbstractMvcViewFactory; import org.springframework.webflow.mvc.view.FlowViewResolver; +import org.springframework.webflow.validation.WebFlowMessageCodesResolver; /** * Returns {@link ViewFactory view factories} that create native Spring MVC-based views. Used by a FlowBuilder to @@ -66,6 +69,8 @@ public class MvcViewFactoryCreator implements ViewFactoryCreator, ApplicationCon private String fieldMarkerPrefix; + private MessageCodesResolver messageCodesResolver; + /** * Create a new Spring MVC View Factory Creator. * @see #setDefaultViewSuffix(String) @@ -74,6 +79,7 @@ public class MvcViewFactoryCreator implements ViewFactoryCreator, ApplicationCon * @see #setUseSpringBeanBinding(boolean) * @see #setFlowViewResolver(FlowViewResolver) * @see #setViewResolvers(List) + * @see #setMessageCodesResolver(MessageCodesResolver) */ public MvcViewFactoryCreator() { @@ -146,6 +152,16 @@ public class MvcViewFactoryCreator implements ViewFactoryCreator, ApplicationCon this.flowViewResolver = new DelegatingFlowViewResolver(viewResolvers); } + /** + * Sets the message codes resolver strategy to use to resolve bind and validation error message codes. If not set, + * {@link WebFlowMessageCodesResolver} is the default. Plug in a {@link DefaultMessageCodesResolver} to resolve + * message codes consistently between Spring MVC Controllers and Web Flow. + * @param messageCodesResolver the message codes resolver + */ + public void setMessageCodesResolver(MessageCodesResolver messageCodesResolver) { + this.messageCodesResolver = messageCodesResolver; + } + // implementing ApplicationContextAware public void setApplicationContext(ApplicationContext applicationContext) { @@ -172,10 +188,10 @@ public class MvcViewFactoryCreator implements ViewFactoryCreator, ApplicationCon ConversionService conversionService, BinderConfiguration binderConfiguration) { if (environment == MvcEnvironment.SERVLET) { return new ServletMvcViewFactory(viewId, flowViewResolver, expressionParser, conversionService, - binderConfiguration); + binderConfiguration, messageCodesResolver); } else if (environment == MvcEnvironment.PORTLET) { return new PortletMvcViewFactory(viewId, flowViewResolver, expressionParser, conversionService, - binderConfiguration); + binderConfiguration, messageCodesResolver); } else { throw new IllegalStateException("Web MVC Environment " + environment + " not supported "); } diff --git a/spring-webflow/src/main/java/org/springframework/webflow/mvc/portlet/PortletMvcViewFactory.java b/spring-webflow/src/main/java/org/springframework/webflow/mvc/portlet/PortletMvcViewFactory.java index a1baf554..8e5fe64a 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/mvc/portlet/PortletMvcViewFactory.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/mvc/portlet/PortletMvcViewFactory.java @@ -18,6 +18,7 @@ package org.springframework.webflow.mvc.portlet; import org.springframework.binding.convert.ConversionService; import org.springframework.binding.expression.Expression; import org.springframework.binding.expression.ExpressionParser; +import org.springframework.validation.MessageCodesResolver; import org.springframework.web.servlet.View; import org.springframework.webflow.engine.builder.BinderConfiguration; import org.springframework.webflow.execution.RequestContext; @@ -40,10 +41,12 @@ public class PortletMvcViewFactory extends AbstractMvcViewFactory { * @param expressionParser the expression parser * @param conversionService the conversion service * @param binderConfiguration the model binding configuration + * @param messageCodesResolver */ public PortletMvcViewFactory(Expression viewId, FlowViewResolver viewResolver, ExpressionParser expressionParser, - ConversionService conversionService, BinderConfiguration binderConfiguration) { - super(viewId, viewResolver, expressionParser, conversionService, binderConfiguration); + ConversionService conversionService, BinderConfiguration binderConfiguration, + MessageCodesResolver messageCodesResolver) { + super(viewId, viewResolver, expressionParser, conversionService, binderConfiguration, messageCodesResolver); } protected AbstractMvcView createMvcView(View view, RequestContext context) { diff --git a/spring-webflow/src/main/java/org/springframework/webflow/mvc/servlet/ServletMvcViewFactory.java b/spring-webflow/src/main/java/org/springframework/webflow/mvc/servlet/ServletMvcViewFactory.java index e4dc6e51..ce5214e7 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/mvc/servlet/ServletMvcViewFactory.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/mvc/servlet/ServletMvcViewFactory.java @@ -18,6 +18,7 @@ package org.springframework.webflow.mvc.servlet; import org.springframework.binding.convert.ConversionService; import org.springframework.binding.expression.Expression; import org.springframework.binding.expression.ExpressionParser; +import org.springframework.validation.MessageCodesResolver; import org.springframework.web.servlet.View; import org.springframework.webflow.engine.builder.BinderConfiguration; import org.springframework.webflow.execution.RequestContext; @@ -41,8 +42,9 @@ public class ServletMvcViewFactory extends AbstractMvcViewFactory { * @param binderConfiguration the model binding configuration */ public ServletMvcViewFactory(Expression viewId, FlowViewResolver viewResolver, ExpressionParser expressionParser, - ConversionService conversionService, BinderConfiguration binderConfiguration) { - super(viewId, viewResolver, expressionParser, conversionService, binderConfiguration); + ConversionService conversionService, BinderConfiguration binderConfiguration, + MessageCodesResolver messageCodesResolver) { + super(viewId, viewResolver, expressionParser, conversionService, binderConfiguration, messageCodesResolver); } protected AbstractMvcView createMvcView(View view, RequestContext context) { diff --git a/spring-webflow/src/main/java/org/springframework/webflow/mvc/view/AbstractMvcView.java b/spring-webflow/src/main/java/org/springframework/webflow/mvc/view/AbstractMvcView.java index 42bf496c..37e534ad 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/mvc/view/AbstractMvcView.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/mvc/view/AbstractMvcView.java @@ -88,7 +88,7 @@ public abstract class AbstractMvcView implements View { private BinderConfiguration binderConfiguration; - private MessageCodesResolver bindingErrorMessageCodesResolver = new WebFlowMessageCodesResolver(); + private MessageCodesResolver messageCodesResolver = new WebFlowMessageCodesResolver(); /** * Creates a new MVC view. @@ -126,10 +126,10 @@ public abstract class AbstractMvcView implements View { /** * Set the message codes resolver to use to resolve bind and validation failure message codes. - * @param bindingErrorMessageCodesResolver the binding error message code resolver to use + * @param messageCodesResolver the binding error message code resolver to use */ - public void setBindingErrorMessageCodesResolver(MessageCodesResolver bindingErrorMessageCodesResolver) { - this.bindingErrorMessageCodesResolver = bindingErrorMessageCodesResolver; + public void setMessageCodesResolver(MessageCodesResolver messageCodesResolver) { + this.messageCodesResolver = messageCodesResolver; } /** @@ -498,7 +498,7 @@ public abstract class AbstractMvcView implements View { String model = getModelExpression().getExpressionString(); String field = error.getMapping().getTargetExpression().getExpressionString(); Class fieldType = error.getMapping().getTargetExpression().getValueType(getModelObject()); - String[] messageCodes = bindingErrorMessageCodesResolver.resolveMessageCodes(error.getCode(), model, field, + String[] messageCodes = messageCodesResolver.resolveMessageCodes(error.getCode(), model, field, fieldType); return new MessageBuilder().error().source(field).codes(messageCodes).resolvableArg(field).defaultText( error.getCode() + " on " + field).build(); @@ -517,7 +517,7 @@ public abstract class AbstractMvcView implements View { logger.debug("Validating model"); } new ValidationHelper(model, requestContext, eventId, getModelExpression().getExpressionString(), - expressionParser, bindingErrorMessageCodesResolver, mappingResults).validate(); + expressionParser, messageCodesResolver, mappingResults).validate(); } private static class PropertyNotFoundError implements MappingResultsCriteria { diff --git a/spring-webflow/src/main/java/org/springframework/webflow/mvc/view/AbstractMvcViewFactory.java b/spring-webflow/src/main/java/org/springframework/webflow/mvc/view/AbstractMvcViewFactory.java index 77845d48..b930bd16 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/mvc/view/AbstractMvcViewFactory.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/mvc/view/AbstractMvcViewFactory.java @@ -19,6 +19,7 @@ import org.springframework.binding.convert.ConversionService; import org.springframework.binding.expression.Expression; import org.springframework.binding.expression.ExpressionParser; import org.springframework.util.StringUtils; +import org.springframework.validation.MessageCodesResolver; import org.springframework.webflow.engine.builder.BinderConfiguration; import org.springframework.webflow.execution.RequestContext; import org.springframework.webflow.execution.View; @@ -45,6 +46,8 @@ public abstract class AbstractMvcViewFactory implements ViewFactory { private String fieldMarkerPrefix; + private MessageCodesResolver messageCodesResolver; + /** * Creates a new MVC view factory. * @param viewId the id of the view as an expression @@ -54,12 +57,14 @@ public abstract class AbstractMvcViewFactory implements ViewFactory { * @param binderConfiguration the model binding configuration */ public AbstractMvcViewFactory(Expression viewId, FlowViewResolver viewResolver, ExpressionParser expressionParser, - ConversionService conversionService, BinderConfiguration binderConfiguration) { + ConversionService conversionService, BinderConfiguration binderConfiguration, + MessageCodesResolver messageCodesResolver) { this.viewId = viewId; this.viewResolver = viewResolver; this.expressionParser = expressionParser; this.conversionService = conversionService; this.binderConfiguration = binderConfiguration; + this.messageCodesResolver = messageCodesResolver; } public void setEventIdParameterName(String eventIdParameterName) { @@ -77,6 +82,7 @@ public abstract class AbstractMvcViewFactory implements ViewFactory { mvcView.setExpressionParser(expressionParser); mvcView.setConversionService(conversionService); mvcView.setBinderConfiguration(binderConfiguration); + mvcView.setMessageCodesResolver(messageCodesResolver); if (StringUtils.hasText(eventIdParameterName)) { mvcView.setEventIdParameterName(eventIdParameterName); } 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 b71b67b5..f62d2f55 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 @@ -54,7 +54,7 @@ public class ValidationHelper { private final ExpressionParser expressionParser; - private final MessageCodesResolver bindingErrorMessageCodesResolver; + private final MessageCodesResolver messageCodesResolver; private final MappingResults mappingResults; @@ -76,7 +76,7 @@ public class ValidationHelper { * @param mappingResults object mapping results */ public ValidationHelper(Object model, RequestContext requestContext, String eventId, String modelName, - ExpressionParser expressionParser, MessageCodesResolver bindingErrorMessageCodesResolver, + ExpressionParser expressionParser, MessageCodesResolver messageCodesResolver, MappingResults mappingResults) { Assert.notNull(model, "The model to validate is required"); Assert.notNull(requestContext, "The request context for the validator is required"); @@ -85,7 +85,7 @@ public class ValidationHelper { this.eventId = eventId; this.modelName = modelName; this.expressionParser = expressionParser; - this.bindingErrorMessageCodesResolver = bindingErrorMessageCodesResolver; + this.messageCodesResolver = messageCodesResolver; this.mappingResults = mappingResults; } @@ -128,7 +128,7 @@ public class ValidationHelper { validateMethod = ReflectionUtils.findMethod(model.getClass(), methodName, new Class[] { Errors.class }); if (validateMethod != null) { MessageContextErrors errors = new MessageContextErrors(requestContext.getMessageContext(), modelName, - model, expressionParser, bindingErrorMessageCodesResolver, mappingResults); + model, expressionParser, messageCodesResolver, mappingResults); if (logger.isDebugEnabled()) { logger.debug("Invoking current state model validation method '" + methodName + "(Errors)'"); } @@ -157,7 +157,7 @@ public class ValidationHelper { logger.debug("Invoking default model validation method 'validate(Errors)'"); } MessageContextErrors errors = new MessageContextErrors(requestContext.getMessageContext(), modelName, - model, expressionParser, bindingErrorMessageCodesResolver, mappingResults); + model, expressionParser, messageCodesResolver, mappingResults); ReflectionUtils.invokeMethod(validateMethod, model, new Object[] { errors }); return true; } @@ -205,7 +205,7 @@ public class ValidationHelper { + ClassUtils.getShortName(model.getClass()) + ", Errors)'"); } MessageContextErrors errors = new MessageContextErrors(requestContext.getMessageContext(), modelName, - model, expressionParser, bindingErrorMessageCodesResolver, mappingResults); + model, expressionParser, messageCodesResolver, mappingResults); ReflectionUtils.invokeMethod(validateMethod, validator, new Object[] { model, errors }); return true; } @@ -227,7 +227,7 @@ public class ValidationHelper { logger.debug("Invoking Spring Validator '" + ClassUtils.getShortName(validator.getClass()) + "'"); } MessageContextErrors errors = new MessageContextErrors(requestContext.getMessageContext(), modelName, - model, expressionParser, bindingErrorMessageCodesResolver, mappingResults); + model, expressionParser, messageCodesResolver, mappingResults); ((Validator) validator).validate(model, errors); return true; } @@ -252,7 +252,7 @@ public class ValidationHelper { + ".validate(" + ClassUtils.getShortName(model.getClass()) + ", Errors)'"); } MessageContextErrors errors = new MessageContextErrors(requestContext.getMessageContext(), modelName, - model, expressionParser, bindingErrorMessageCodesResolver, mappingResults); + model, expressionParser, messageCodesResolver, mappingResults); ReflectionUtils.invokeMethod(validateMethod, validator, new Object[] { model, errors }); return true; }