From df649084abfc5bd4cac4c18e614ec8e7f99bb404 Mon Sep 17 00:00:00 2001 From: Rossen Stoyanchev Date: Tue, 28 Feb 2012 13:22:13 -0500 Subject: [PATCH] Fix for bean validation messages in BindingResult Previously Web Flow's BindingResult implementation distinguished object from field-level errors by checking if the source of the error is null or otherwise a String. However, class-level bean validation errors have a field source represented by an empty String. After this change object and field-level errors are recognized by checking for String-based field source that is neither null nor empty. This commit also contains a fix for spring-faces tests where in JSF 2.1 the presence of an unreleased FacesContext may cause some tests to fail. --- build-spring-webflow/resources/changelog.txt | 4 ++-- .../springframework/binding/message/Message.java | 16 +++++++++++++++- .../faces/webflow/JSFMockHelper.java | 8 ++++++-- .../webflow/mvc/view/BindingModel.java | 8 ++++---- 4 files changed, 27 insertions(+), 9 deletions(-) diff --git a/build-spring-webflow/resources/changelog.txt b/build-spring-webflow/resources/changelog.txt index 34c34041..ed7ee50a 100644 --- a/build-spring-webflow/resources/changelog.txt +++ b/build-spring-webflow/resources/changelog.txt @@ -5,8 +5,8 @@ http://www.springframework.org/webflow Changes in version 2.3.1.RELEASE ----------------------------------------------- Upgrade JSF Mojarra version to 2.1.7 -Improve Jsf2FlowFacesContext.isValidationFailed() to check Web Flow's MessageContext for errors - +Modify Jsf2FlowFacesContext.isValidationFailed() to check Web Flow's MessageContext for errors +Recognize class-level bean validation messages in BindingResult.getGlobalErrors() Changes in version 2.3.0.RELEASE (Feb 28, 2011) ----------------------------------------------- diff --git a/spring-binding/src/main/java/org/springframework/binding/message/Message.java b/spring-binding/src/main/java/org/springframework/binding/message/Message.java index bc3909c5..4b7ba94a 100644 --- a/spring-binding/src/main/java/org/springframework/binding/message/Message.java +++ b/spring-binding/src/main/java/org/springframework/binding/message/Message.java @@ -18,6 +18,7 @@ package org.springframework.binding.message; import java.io.Serializable; import org.springframework.core.style.ToStringCreator; +import org.springframework.util.StringUtils; /** * An object of communication that provides text information. For example, a validation message may inform a web @@ -49,7 +50,8 @@ public class Message implements Serializable { /** * A reference to the source element this message is associated with. This could be a field on a form in UI, or null - * if the message is not associated with a any particular element. + * (or empty "" in the case of global bean validation) if the message is not associated with a any particular + * element. * @return the source */ public Object getSource() { @@ -72,6 +74,18 @@ public class Message implements Serializable { return severity; } + /** + * Whether the message is associated with a field. + * @return {@code true} if the source is a String that has text; {@code false} otherwise. + */ + public boolean hasField() { + if (this.source instanceof String) { + return StringUtils.hasText((String) this.source); + } else { + return false; + } + } + public String toString() { return new ToStringCreator(this).append("source", source).append("severity", severity).append("text", text) .toString(); diff --git a/spring-faces/src/test/java/org/springframework/faces/webflow/JSFMockHelper.java b/spring-faces/src/test/java/org/springframework/faces/webflow/JSFMockHelper.java index c73b6d0b..8e9423ce 100644 --- a/spring-faces/src/test/java/org/springframework/faces/webflow/JSFMockHelper.java +++ b/spring-faces/src/test/java/org/springframework/faces/webflow/JSFMockHelper.java @@ -113,6 +113,11 @@ public class JSFMockHelper { public void setUp() throws Exception { + // Ensure no pre-existing FacesContext .. + if (FacesContext.getCurrentInstance() != null) { + FacesContext.getCurrentInstance().release(); + } + // Set up a new thread context class loader threadContextClassLoader = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader( @@ -132,8 +137,7 @@ public class JSFMockHelper { FactoryFinder.setFactory(FactoryFinder.FACES_CONTEXT_FACTORY, MockBaseFacesContextFactory.class.getName()); FactoryFinder.setFactory(FactoryFinder.LIFECYCLE_FACTORY, MockLifecycleFactory.class.getName()); FactoryFinder.setFactory(FactoryFinder.RENDER_KIT_FACTORY, MockRenderKitFactory.class.getName()); - FactoryFinder.setFactory(FactoryFinder.PARTIAL_VIEW_CONTEXT_FACTORY, MockPartialViewContextFactory.class - .getName()); + FactoryFinder.setFactory(FactoryFinder.PARTIAL_VIEW_CONTEXT_FACTORY, MockPartialViewContextFactory.class.getName()); lifecycleFactory = (MockLifecycleFactory) FactoryFinder.getFactory(FactoryFinder.LIFECYCLE_FACTORY); lifecycle = (MockLifecycle) lifecycleFactory.getLifecycle(LifecycleFactory.DEFAULT_LIFECYCLE); facesContextFactory = (FacesContextFactory) FactoryFinder.getFactory(FactoryFinder.FACES_CONTEXT_FACTORY); diff --git a/spring-webflow/src/main/java/org/springframework/webflow/mvc/view/BindingModel.java b/spring-webflow/src/main/java/org/springframework/webflow/mvc/view/BindingModel.java index 24f32991..4e8e62ff 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/mvc/view/BindingModel.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/mvc/view/BindingModel.java @@ -111,7 +111,7 @@ public class BindingModel extends AbstractErrors implements BindingResult { } public List getGlobalErrors() { - return toErrors(messageContext.getMessagesByCriteria(ERRORS_NULL_SOURCE)); + return toErrors(messageContext.getMessagesByCriteria(ERRORS_WITHOUT_FIELD_SOURCE)); } public List getFieldErrors(String field) { @@ -318,15 +318,15 @@ public class BindingModel extends AbstractErrors implements BindingResult { } }; - private static final MessageCriteria ERRORS_NULL_SOURCE = new MessageCriteria() { + private static final MessageCriteria ERRORS_WITHOUT_FIELD_SOURCE = new MessageCriteria() { public boolean test(Message message) { - return message.getSource() == null && message.getSeverity() == Severity.ERROR; + return (!message.hasField() && message.getSeverity() == Severity.ERROR); } }; private static final MessageCriteria ERRORS_FIELD_SOURCE = new MessageCriteria() { public boolean test(Message message) { - return message.getSeverity() == Severity.ERROR && message.getSource() instanceof String; + return (message.hasField() && message.getSeverity() == Severity.ERROR); } };