diff --git a/spring-binding/src/main/java/org/springframework/binding/message/MessageBuilder.java b/spring-binding/src/main/java/org/springframework/binding/message/MessageBuilder.java index 656e49aa..2690b6f6 100644 --- a/spring-binding/src/main/java/org/springframework/binding/message/MessageBuilder.java +++ b/spring-binding/src/main/java/org/springframework/binding/message/MessageBuilder.java @@ -1,6 +1,10 @@ package org.springframework.binding.message; +import java.util.ArrayList; +import java.util.LinkedHashSet; +import java.util.List; import java.util.Locale; +import java.util.Set; import org.springframework.context.MessageSource; import org.springframework.context.MessageSourceResolvable; @@ -14,8 +18,7 @@ import org.springframework.context.MessageSourceResolvable; * Usage example: *

* - * new MessageBuilder().error().source(this).code("mycode").args(new Object[] { arg1, arg2 }).defaultText("Fallback text") - * .build(); + * new MessageBuilder().error().source(this).code("mycode").arg(arg1).arg(arg2).defaultText("text").build(); * *

* @author Keith Donald @@ -24,45 +27,14 @@ public class MessageBuilder { private Object source; - private String[] codes; + private Set codes = new LinkedHashSet(); private Severity severity; - private Object[] args; + private List args = new ArrayList(); private String defaultText; - /** - * Records that the message being built is from the source provided. - * @param source the source generating the message - * @return this, for fluent API usage - */ - public MessageBuilder source(Object source) { - this.source = source; - return this; - } - - /** - * Records that the message being built should have its text resolved using the code provided. - * @param code the message code - * @return this, for fluent API usage - */ - public MessageBuilder code(String code) { - codes = new String[] { code }; - return this; - } - - /** - * Records that the message being built should have its text resolved using the codes provided. The codes are tried - * in-order until their is a match. - * @param codes the message codes - * @return this, for fluent API usage - */ - public MessageBuilder codes(String[] codes) { - this.codes = codes; - return this; - } - /** * Records that the message being built is an informational message. * @return this, for fluent API usage @@ -91,28 +63,53 @@ public class MessageBuilder { } /** - * Records that the message being built has a single argument. - * @param arg the message argument + * Records that the message being built is against the provided source. + * @param source the source generating the message * @return this, for fluent API usage */ - public MessageBuilder arg(Object arg) { - this.args = new Object[] { arg }; + public MessageBuilder source(Object source) { + this.source = source; return this; } /** - * Records that the message being built has arguments. - * @param args the message arguments + * Records that the message being built should try and resolve its text using the code provided. Adds the code to + * the codes list. Successive calls to this method add additional codes. Codes are applied in the order they are + * added. + * @param code the message code * @return this, for fluent API usage */ - public MessageBuilder args(Object[] args) { - this.args = args; + public MessageBuilder code(String code) { + codes.add(code); + return this; + } + + /** + * Records that the message being built has a variable argument. Adds the arg to the args list. Successive calls to + * this method add additional args. Args are applied in the order they are added. + * @param arg the message argument value + * @return this, for fluent API usage + */ + public MessageBuilder arg(Object arg) { + args.add(arg); + return this; + } + + /** + * Records that the message being built has a variable argument, whose display value is also + * {@link MessageSourceResolvable}. Adds the arg to the args list. Successive calls to this method add additional + * resolvable args. Args are applied in the order they are added. + * @param arg the resolvable message argument + * @return this, for fluent API usage + */ + public MessageBuilder resolvableArg(Object arg) { + args.add(new ResolvableArgument(arg)); return this; } /** * Records the fallback text of the message being built. If the message has no codes, this will always be used as - * the text. + * the text. If the message has codes but none can be resolved, this will alway be used as the text. * @param text the default text * @return this, for fluent API usage */ @@ -133,7 +130,9 @@ public class MessageBuilder { throw new IllegalArgumentException( "A message code or the message text is required to build this message resolver"); } - return new BuiltMessageResolver(source, codes, severity, args, defaultText); + String[] codesArray = (String[]) codes.toArray(new String[codes.size()]); + Object[] argsArray = args.toArray(new Object[args.size()]); + return new BuiltMessageResolver(source, codesArray, severity, argsArray, defaultText); } private static class BuiltMessageResolver implements MessageResolver, MessageSourceResolvable { @@ -170,4 +169,26 @@ public class MessageBuilder { } } + private static class ResolvableArgument implements MessageSourceResolvable { + + private Object arg; + + public ResolvableArgument(Object arg) { + this.arg = arg; + } + + public Object[] getArguments() { + return null; + } + + public String[] getCodes() { + return new String[] { arg.toString() }; + } + + public String getDefaultMessage() { + return arg.toString(); + } + + } + } diff --git a/spring-binding/src/test/java/org/springframework/binding/message/DefaultMessageContextFactoryTests.java b/spring-binding/src/test/java/org/springframework/binding/message/DefaultMessageContextFactoryTests.java index abf6de0c..a63ab850 100644 --- a/spring-binding/src/test/java/org/springframework/binding/message/DefaultMessageContextFactoryTests.java +++ b/spring-binding/src/test/java/org/springframework/binding/message/DefaultMessageContextFactoryTests.java @@ -62,8 +62,8 @@ public class DefaultMessageContextFactoryTests extends TestCase { public void testResolveMessageWithMultipleCodes() { MessageContext context = factory.createMessageContext(); - context.addMessage(new MessageBuilder().error().source(this).codes(new String[] { "bogus", "argmessage" }) - .args(new Object[] { "Keith" }).defaultText("Hello world fallback!").build()); + context.addMessage(new MessageBuilder().error().source(this).code("bogus").code("argmessage").arg("Keith") + .defaultText("Hello world fallback!").build()); Message[] messages = context.getMessagesBySource(this); assertEquals(1, messages.length); assertEquals("Hello world Keith!", messages[0].getText()); diff --git a/spring-webflow/src/main/java/org/springframework/webflow/mvc/view/MvcView.java b/spring-webflow/src/main/java/org/springframework/webflow/mvc/view/MvcView.java index 445d3184..a8eb18fa 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/mvc/view/MvcView.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/mvc/view/MvcView.java @@ -206,7 +206,7 @@ class MvcView implements View { private MessageResolver message(MappingResult error) { String field = error.getMapping().getTargetExpression().getExpressionString(); String errorCode = error.getResult().getErrorCode(); - return new MessageBuilder().error().source(field).code(errorCode).arg(field).defaultText( + return new MessageBuilder().error().source(field).code(errorCode).resolvableArg(field).defaultText( errorCode + " on " + field).build(); }