diff --git a/spring-context/src/main/java/org/springframework/validation/DefaultMessageCodesResolver.java b/spring-context/src/main/java/org/springframework/validation/DefaultMessageCodesResolver.java index 44d8b65c72..7c1a084be2 100644 --- a/spring-context/src/main/java/org/springframework/validation/DefaultMessageCodesResolver.java +++ b/spring-context/src/main/java/org/springframework/validation/DefaultMessageCodesResolver.java @@ -29,7 +29,8 @@ import org.springframework.util.StringUtils; * Default implementation of the {@link MessageCodesResolver} interface. * *

Will create two message codes for an object error, in the following order (when - * using the {@link Style#PREFIX_ERROR_CODE prefixed} {@link #setStyle(Style) style}): + * using the {@link Format#PREFIX_ERROR_CODE prefixed} + * {@link #setMessageCodeFormatter(MessageCodeFormatter) formatter}): *

* *

By default the {@code errorCode}s will be placed at the beginning of constructed - * message strings. The {@link #setStyle(Style) style} property can be used to specify - * alternative {@link Style styles} of concatination. + * message strings. The {@link #setMessageCodeFormatter(MessageCodeFormatter) + * messageCodeFormatter} property can be used to specify an alternative concatenation + * {@link MessageCodeFormatter format}. * *

In order to group all codes into a specific category within your resource bundles, * e.g. "validation.typeMismatch.name" instead of the default "typeMismatch.name", @@ -82,6 +84,7 @@ import org.springframework.util.StringUtils; * * @author Juergen Hoeller * @author Phillip Webb + * @author Chris Beams * @since 1.0.1 */ @SuppressWarnings("serial") @@ -92,12 +95,12 @@ public class DefaultMessageCodesResolver implements MessageCodesResolver, Serial */ public static final String CODE_SEPARATOR = "."; - private static final Style DEFAULT_STYLE = Style.PREFIX_ERROR_CODE; + private static final MessageCodeFormatter DEFAULT_FORMATTER = Format.PREFIX_ERROR_CODE; private String prefix = ""; - private Style style = DEFAULT_STYLE; + private MessageCodeFormatter formatter = DEFAULT_FORMATTER; /** @@ -110,11 +113,12 @@ public class DefaultMessageCodesResolver implements MessageCodesResolver, Serial } /** - * Specify the style of message code that will be built by this resolver. - *

Default is {@link Style#PREFIX_ERROR_CODE}. + * Specify the format for message codes built by this resolver. + *

The default is {@link Format#PREFIX_ERROR_CODE}. + * @since 3.2 */ - public void setStyle(Style style) { - this.style = (style == null ? DEFAULT_STYLE : style); + public void setMessageCodeFormatter(MessageCodeFormatter formatter) { + this.formatter = (formatter == null ? DEFAULT_FORMATTER : formatter); } /** @@ -163,29 +167,7 @@ public class DefaultMessageCodesResolver implements MessageCodesResolver, Serial } private void addCode(Collection codeList, String errorCode, String objectName, String field) { - String code = getCode(errorCode, objectName, field); - codeList.add(postProcessMessageCode(code)); - } - - private String getCode(String errorCode, String objectName, String field) { - switch (this.style) { - case PREFIX_ERROR_CODE: - return toDelimitedString(errorCode, objectName, field); - case POSTFIX_ERROR_CODE: - return toDelimitedString(objectName, field, errorCode); - } - throw new IllegalStateException("Unknown style " + this.style); - } - - private String toDelimitedString(String... elements) { - StringBuilder rtn = new StringBuilder(); - for (String element : elements) { - if(StringUtils.hasLength(element)) { - rtn.append(rtn.length() == 0 ? "" : CODE_SEPARATOR); - rtn.append(element); - } - } - return rtn.toString(); + codeList.add(postProcessMessageCode(this.formatter.format(errorCode, objectName, field))); } /** @@ -222,21 +204,51 @@ public class DefaultMessageCodesResolver implements MessageCodesResolver, Serial /** - * The various styles that can be used to construct message codes. + * Common message code formats. + * + * @author Phil Webb + * @author Chris Beams + * @since 3.2 + * @see MessageCodeFormatter + * @see DefaultMessageCodesResolver#setMessageCodeFormatter(MessageCodeFormatter) */ - public static enum Style { + public static enum Format implements MessageCodeFormatter { /** - * Prefix the error code at the beginning of the generated message code. eg: + * Prefix the error code at the beginning of the generated message code. e.g.: * {@code errorCode + "." + object name + "." + field} */ - PREFIX_ERROR_CODE, + PREFIX_ERROR_CODE { + public String format(String errorCode, String objectName, String field) { + return toDelimitedString(errorCode, objectName, field); + } + }, /** - * Postfix the error code at the end of the generated message code. eg: + * Postfix the error code at the end of the generated message code. e.g.: * {@code object name + "." + field + "." + errorCode} */ - POSTFIX_ERROR_CODE + POSTFIX_ERROR_CODE { + public String format(String errorCode, String objectName, String field) { + return toDelimitedString(objectName, field, errorCode); + } + }; + + /** + * Concatenate the given elements, delimiting each with + * {@link DefaultMessageCodesResolver#CODE_SEPARATOR}, skipping zero-length or + * null elements altogether. + */ + public static String toDelimitedString(String... elements) { + StringBuilder rtn = new StringBuilder(); + for (String element : elements) { + if(StringUtils.hasLength(element)) { + rtn.append(rtn.length() == 0 ? "" : CODE_SEPARATOR); + rtn.append(element); + } + } + return rtn.toString(); + } } } diff --git a/spring-context/src/main/java/org/springframework/validation/MessageCodeFormatter.java b/spring-context/src/main/java/org/springframework/validation/MessageCodeFormatter.java new file mode 100644 index 0000000000..0ce9bdd5f7 --- /dev/null +++ b/spring-context/src/main/java/org/springframework/validation/MessageCodeFormatter.java @@ -0,0 +1,38 @@ +/* + * Copyright 2002-2012 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.validation; + +/** + * A strategy interface for formatting message codes. + * + * @author Chris Beams + * @since 3.2 + * @see DefaultMessageCodesResolver + */ +public interface MessageCodeFormatter { + + /** + * Build and return a message code consisting of the given fields, usually delimited + * by {@link DefaultMessageCodesResolver#CODE_SEPARATOR}. + * @param errorCode e.g.: "typeMismatch" + * @param objectName e.g.: "user" + * @param field e.g. "age" + * @return concatenated message code, e.g.: "typeMismatch.user.age" + * @see DefaultMessageCodesResolver.Format + */ + String format(String errorCode, String objectName, String field); +} \ No newline at end of file diff --git a/spring-context/src/test/java/org/springframework/validation/DefaultMessageCodesResolverTests.java b/spring-context/src/test/java/org/springframework/validation/DefaultMessageCodesResolverTests.java index 18bb109b5a..db86c2384d 100644 --- a/spring-context/src/test/java/org/springframework/validation/DefaultMessageCodesResolverTests.java +++ b/spring-context/src/test/java/org/springframework/validation/DefaultMessageCodesResolverTests.java @@ -22,7 +22,7 @@ import static org.junit.Assert.assertThat; import org.junit.Test; import org.springframework.beans.TestBean; -import org.springframework.validation.DefaultMessageCodesResolver.Style; +import org.springframework.validation.DefaultMessageCodesResolver.Format; /** * Tests for {@link DefaultMessageCodesResolver}. @@ -123,8 +123,8 @@ public class DefaultMessageCodesResolverTests { } @Test - public void shouldSupportPostfixStyle() throws Exception { - resolver.setStyle(Style.POSTFIX_ERROR_CODE); + public void shouldSupportPostfixFormat() throws Exception { + resolver.setMessageCodeFormatter(Format.POSTFIX_ERROR_CODE); String[] codes = resolver.resolveMessageCodes("errorCode", "objectName"); assertThat(codes, is(equalTo(new String[] { "objectName.errorCode", @@ -132,8 +132,8 @@ public class DefaultMessageCodesResolverTests { } @Test - public void shouldSupportFieldPostfixStyle() throws Exception { - resolver.setStyle(Style.POSTFIX_ERROR_CODE); + public void shouldSupportFieldPostfixFormat() throws Exception { + resolver.setMessageCodeFormatter(Format.POSTFIX_ERROR_CODE); String[] codes = resolver.resolveMessageCodes("errorCode", "objectName", "field", TestBean.class); assertThat(codes, is(equalTo(new String[] { @@ -142,4 +142,18 @@ public class DefaultMessageCodesResolverTests { "org.springframework.beans.TestBean.errorCode", "errorCode" }))); } + + @Test + public void shouldSupportCustomFormat() throws Exception { + resolver.setMessageCodeFormatter(new MessageCodeFormatter() { + public String format(String errorCode, String objectName, String field) { + return DefaultMessageCodesResolver.Format.toDelimitedString( + "CUSTOM-" + errorCode, objectName, field); + } + }); + String[] codes = resolver.resolveMessageCodes("errorCode", "objectName"); + assertThat(codes, is(equalTo(new String[] { + "CUSTOM-errorCode.objectName", + "CUSTOM-errorCode" }))); + } }