From da7e596b2a62828392ab3220adfeb5c79be7764a Mon Sep 17 00:00:00 2001 From: Keith Donald Date: Sun, 26 Jul 2009 21:22:13 +0000 Subject: [PATCH] default message factory --- .../support/FieldNotEditableResult.java | 21 +++++++----- .../binder/support/FieldNotFoundResult.java | 19 ++++++----- .../model/message/DefaultMessageFactory.java | 16 +++++++++ .../model/message/DefaultMessageResolver.java | 20 ++++++----- .../model/message/MessageBuilder.java | 12 +++++++ .../model/message/MessageResolverBuilder.java | 20 ++++++++--- .../message/StaticDefaultMessageFactory.java | 30 ++++++++++++++++ .../model/ui/support/DefaultFieldModel.java | 34 ++++++++++++++----- 8 files changed, 134 insertions(+), 38 deletions(-) create mode 100644 org.springframework.context/src/main/java/org/springframework/model/message/DefaultMessageFactory.java create mode 100644 org.springframework.context/src/main/java/org/springframework/model/message/StaticDefaultMessageFactory.java diff --git a/org.springframework.context/src/main/java/org/springframework/model/binder/support/FieldNotEditableResult.java b/org.springframework.context/src/main/java/org/springframework/model/binder/support/FieldNotEditableResult.java index 16cfb82ef5c..1e6c210196e 100644 --- a/org.springframework.context/src/main/java/org/springframework/model/binder/support/FieldNotEditableResult.java +++ b/org.springframework.context/src/main/java/org/springframework/model/binder/support/FieldNotEditableResult.java @@ -20,25 +20,26 @@ import org.springframework.core.style.StylerUtils; import org.springframework.model.alert.Alert; import org.springframework.model.alert.Severity; import org.springframework.model.binder.BindingResult; +import org.springframework.model.message.DefaultMessageFactory; import org.springframework.model.message.MessageBuilder; import org.springframework.model.message.ResolvableArgument; public class FieldNotEditableResult implements BindingResult { - private String property; + private String fieldName; private Object submittedValue; private MessageSource messageSource; - - public FieldNotEditableResult(String property, Object submittedValue, MessageSource messageSource) { - this.property = property; + + public FieldNotEditableResult(String fieldName, Object submittedValue, MessageSource messageSource) { + this.fieldName = fieldName; this.submittedValue = submittedValue; this.messageSource = messageSource; } public String getFieldName() { - return property; + return fieldName; } public Object getSubmittedValue() { @@ -62,11 +63,13 @@ public class FieldNotEditableResult implements BindingResult { public String getMessage() { MessageBuilder builder = new MessageBuilder(messageSource); builder.code("bindSuccess"); - builder.arg("label", new ResolvableArgument(property)); + builder.arg("label", new ResolvableArgument(fieldName)); builder.arg("value", submittedValue); - // TODO lazily create default message - builder.defaultMessage("Successfully bound user value " + StylerUtils.style(submittedValue) - + " to property '" + property + "'"); + builder.defaultMessage(new DefaultMessageFactory() { + public String createDefaultMessage() { + return "Failed to bind submitted value " + StylerUtils.style(submittedValue) + "; field '" + fieldName + "' is not editable"; + } + }); return builder.build(); } }; diff --git a/org.springframework.context/src/main/java/org/springframework/model/binder/support/FieldNotFoundResult.java b/org.springframework.context/src/main/java/org/springframework/model/binder/support/FieldNotFoundResult.java index 5cd278d2f35..2b248e06148 100644 --- a/org.springframework.context/src/main/java/org/springframework/model/binder/support/FieldNotFoundResult.java +++ b/org.springframework.context/src/main/java/org/springframework/model/binder/support/FieldNotFoundResult.java @@ -20,25 +20,26 @@ import org.springframework.core.style.StylerUtils; import org.springframework.model.alert.Alert; import org.springframework.model.alert.Severity; import org.springframework.model.binder.BindingResult; +import org.springframework.model.message.DefaultMessageFactory; import org.springframework.model.message.MessageBuilder; import org.springframework.model.message.ResolvableArgument; public class FieldNotFoundResult implements BindingResult { - private String property; + private String fieldName; private Object submittedValue; private MessageSource messageSource; - public FieldNotFoundResult(String property, Object submittedValue, MessageSource messageSource) { - this.property = property; + public FieldNotFoundResult(String fieldName, Object submittedValue, MessageSource messageSource) { + this.fieldName = fieldName; this.submittedValue = submittedValue; this.messageSource = messageSource; } public String getFieldName() { - return property; + return fieldName; } public Object getSubmittedValue() { @@ -62,11 +63,13 @@ public class FieldNotFoundResult implements BindingResult { public String getMessage() { MessageBuilder builder = new MessageBuilder(messageSource); builder.code("bindSuccess"); - builder.arg("label", new ResolvableArgument(property)); + builder.arg("label", new ResolvableArgument(fieldName)); builder.arg("value", submittedValue); - // TODO lazily create default message - builder.defaultMessage("Successfully bound user value " + StylerUtils.style(submittedValue) - + " to property '" + property + "'"); + builder.defaultMessage(new DefaultMessageFactory() { + public String createDefaultMessage() { + return "Failed to bind submitted value " + StylerUtils.style(submittedValue) + "; no field '" + fieldName + "' found"; + } + }); return builder.build(); } }; diff --git a/org.springframework.context/src/main/java/org/springframework/model/message/DefaultMessageFactory.java b/org.springframework.context/src/main/java/org/springframework/model/message/DefaultMessageFactory.java new file mode 100644 index 00000000000..6cd8e5e6af2 --- /dev/null +++ b/org.springframework.context/src/main/java/org/springframework/model/message/DefaultMessageFactory.java @@ -0,0 +1,16 @@ +package org.springframework.model.message; + +/** + * A factory for a default message to return if no message could be resolved. + * Allows the message String to be created lazily, only when it is needed. + * @author Keith Donald + * @since 3.0 + * @see MessageBuilder + */ +public interface DefaultMessageFactory { + + /** + * Create the default message. + */ + String createDefaultMessage(); +} diff --git a/org.springframework.context/src/main/java/org/springframework/model/message/DefaultMessageResolver.java b/org.springframework.context/src/main/java/org/springframework/model/message/DefaultMessageResolver.java index 37d4b5d3a15..7f6e7cbd92d 100644 --- a/org.springframework.context/src/main/java/org/springframework/model/message/DefaultMessageResolver.java +++ b/org.springframework.context/src/main/java/org/springframework/model/message/DefaultMessageResolver.java @@ -39,15 +39,15 @@ final class DefaultMessageResolver implements MessageResolver, MessageSourceReso private Map args; - private String defaultMessage; + private DefaultMessageFactory defaultMessageFactory; private ExpressionParser expressionParser; - public DefaultMessageResolver(String[] codes, Map args, String defaultText, - ExpressionParser expressionParser) { + public DefaultMessageResolver(String[] codes, Map args, + DefaultMessageFactory defaultMessageFactory, ExpressionParser expressionParser) { this.codes = codes; this.args = args; - this.defaultMessage = defaultText; + this.defaultMessageFactory = defaultMessageFactory; this.expressionParser = expressionParser; } @@ -55,10 +55,11 @@ final class DefaultMessageResolver implements MessageResolver, MessageSourceReso public String resolveMessage(MessageSource messageSource, Locale locale) { if (messageSource == null) { - if (defaultMessage != null) { - return defaultMessage; + if (defaultMessageFactory != null) { + return defaultMessageFactory.createDefaultMessage(); } else { - throw new MessageResolutionException("Unable to resolve message; MessagSource argument is null and no defaultMessage is configured"); + throw new MessageResolutionException( + "Unable to resolve message; MessagSource argument is null and no defaultMessage is configured"); } } String messageString; @@ -95,11 +96,12 @@ final class DefaultMessageResolver implements MessageResolver, MessageSourceReso } public String getDefaultMessage() { - return defaultMessage; + return defaultMessageFactory.createDefaultMessage(); } public String toString() { - return new ToStringCreator(this).append("codes", codes).append("defaultText", defaultMessage).toString(); + return new ToStringCreator(this).append("codes", codes).append("args", args).append("defaultMessageFactory", + defaultMessageFactory).toString(); } @SuppressWarnings("unchecked") diff --git a/org.springframework.context/src/main/java/org/springframework/model/message/MessageBuilder.java b/org.springframework.context/src/main/java/org/springframework/model/message/MessageBuilder.java index c9e043b544c..adc85422a3e 100644 --- a/org.springframework.context/src/main/java/org/springframework/model/message/MessageBuilder.java +++ b/org.springframework.context/src/main/java/org/springframework/model/message/MessageBuilder.java @@ -102,6 +102,18 @@ public class MessageBuilder { return this; } + /** + * Set the default message. + * If there are no codes to try, this will be used as the message. + * If there are codes to try but none of those resolve to a message, this will be used as the message. + * @param message the default text + * @return this, for fluent API usage + */ + public MessageBuilder defaultMessage(DefaultMessageFactory defaultMessageFactory) { + builder.defaultMessage(defaultMessageFactory); + return this; + } + /** * Set the message locale. * If not set, the default locale the Locale of the current request obtained from {@link LocaleContextHolder#getLocale()}. diff --git a/org.springframework.context/src/main/java/org/springframework/model/message/MessageResolverBuilder.java b/org.springframework.context/src/main/java/org/springframework/model/message/MessageResolverBuilder.java index e7c8362ff76..19e2631fddf 100644 --- a/org.springframework.context/src/main/java/org/springframework/model/message/MessageResolverBuilder.java +++ b/org.springframework.context/src/main/java/org/springframework/model/message/MessageResolverBuilder.java @@ -56,7 +56,7 @@ public class MessageResolverBuilder { private Map args = new LinkedHashMap(); - private String defaultMessage; + private DefaultMessageFactory defaultMessageFactory; private ExpressionParser expressionParser = new SpelExpressionParser(); @@ -97,10 +97,22 @@ public class MessageResolverBuilder { * @return this, for fluent API usage */ public MessageResolverBuilder defaultMessage(String message) { - defaultMessage = message; + return defaultMessage(new StaticDefaultMessageFactory(message)); + } + + /** + * Set the default message. + * If the MessageResolver has no codes to try, this will be used as the message. + * If the MessageResolver has codes to try but none of those resolve to a message, this will be used as the message. + * @param message the default text + * @return this, for fluent API usage + */ + public MessageResolverBuilder defaultMessage(DefaultMessageFactory defaultMessageFactory) { + this.defaultMessageFactory = defaultMessageFactory; return this; } + /** * Builds the resolver for the message. * Call after recording all builder instructions. @@ -108,12 +120,12 @@ public class MessageResolverBuilder { * @throws IllegalStateException if no codes have been added and there is no default message */ public MessageResolver build() { - if (codes == null && defaultMessage == null) { + if (codes == null && defaultMessageFactory == null) { throw new IllegalStateException( "A message code or the message text is required to build this message resolver"); } String[] codesArray = (String[]) codes.toArray(new String[codes.size()]); - return new DefaultMessageResolver(codesArray, args, defaultMessage, expressionParser); + return new DefaultMessageResolver(codesArray, args, defaultMessageFactory, expressionParser); } } \ No newline at end of file diff --git a/org.springframework.context/src/main/java/org/springframework/model/message/StaticDefaultMessageFactory.java b/org.springframework.context/src/main/java/org/springframework/model/message/StaticDefaultMessageFactory.java new file mode 100644 index 00000000000..52bcc5f8bb7 --- /dev/null +++ b/org.springframework.context/src/main/java/org/springframework/model/message/StaticDefaultMessageFactory.java @@ -0,0 +1,30 @@ +/* + * Copyright 2004-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.model.message; + +class StaticDefaultMessageFactory implements DefaultMessageFactory { + + private String defaultMessage; + + public StaticDefaultMessageFactory(String defaultMessage) { + this.defaultMessage = defaultMessage; + } + + public String createDefaultMessage() { + return defaultMessage; + } + +} diff --git a/org.springframework.context/src/main/java/org/springframework/model/ui/support/DefaultFieldModel.java b/org.springframework.context/src/main/java/org/springframework/model/ui/support/DefaultFieldModel.java index c5cc8c1ba8f..d6376bebe2a 100644 --- a/org.springframework.context/src/main/java/org/springframework/model/ui/support/DefaultFieldModel.java +++ b/org.springframework.context/src/main/java/org/springframework/model/ui/support/DefaultFieldModel.java @@ -34,6 +34,7 @@ import org.springframework.core.convert.TypeDescriptor; import org.springframework.core.style.StylerUtils; import org.springframework.model.alert.Alert; import org.springframework.model.alert.Severity; +import org.springframework.model.message.DefaultMessageFactory; import org.springframework.model.message.MessageBuilder; import org.springframework.model.message.ResolvableArgument; import org.springframework.model.ui.BindingStatus; @@ -210,16 +211,24 @@ public class DefaultFieldModel implements FieldModel { builder.arg("label", context.getLabel()); builder.arg("value", submittedValue); builder.arg("errorOffset", e.getErrorOffset()); - builder.defaultMessage("Failed to bind '" + context.getLabel() + "'; the submitted value " - + StylerUtils.style(submittedValue) + " has an invalid format and could no be parsed"); + builder.defaultMessage(new DefaultMessageFactory() { + public String createDefaultMessage() { + return "Failed to bind '" + context.getLabel() + "'; the submitted value " + + StylerUtils.style(submittedValue) + + " has an invalid format and could no be parsed"; + } + }); } else { - ConversionFailedException e = (ConversionFailedException) invalidSubmittedValueCause; + final ConversionFailedException e = (ConversionFailedException) invalidSubmittedValueCause; builder.arg("label", new ResolvableArgument(context.getLabel())); builder.arg("value", submittedValue); - builder.defaultMessage("Failed to bind '" + context.getLabel() + "'; the submitted value " - + StylerUtils.style(submittedValue) + " has could not be converted to " - + e.getTargetType().getName()); - + builder.defaultMessage(new DefaultMessageFactory() { + public String createDefaultMessage() { + return "Failed to bind '" + context.getLabel() + "'; the submitted value " + + StylerUtils.style(submittedValue) + " has could not be converted to " + + e.getTargetType().getName(); + } + }); } return builder.build(); } @@ -235,7 +244,6 @@ public class DefaultFieldModel implements FieldModel { } public String getMessage() { - buffer.getFlushException().printStackTrace(); return "Internal error occurred; message = [" + buffer.getFlushException().getMessage() + "]"; } @@ -250,6 +258,16 @@ public class DefaultFieldModel implements FieldModel { } public String getMessage() { + MessageBuilder builder = new MessageBuilder(context.getMessageSource()); + builder.code("bindSuccess"); + builder.arg("label", context.getLabel()); + builder.arg("value", submittedValue); + builder.defaultMessage(new DefaultMessageFactory() { + public String createDefaultMessage() { + return "Successfully bound submitted value " + StylerUtils.style(submittedValue) + + " to field '" + context.getLabel() + "'"; + } + }); return "Binding successful"; }