multiple message code resolver fixes
This commit is contained in:
@@ -1,48 +1,140 @@
|
||||
package org.springframework.webflow.validation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.validation.DefaultMessageCodesResolver;
|
||||
import org.springframework.validation.MessageCodesResolver;
|
||||
|
||||
/**
|
||||
* Message Codes Resolver that implements the default Web Flow 2.x algorithm. The default algorithm differs from the
|
||||
* Spring MVC {@link DefaultMessageCodesResolver} by appending the errorCode <em>last</em> instead of first. For
|
||||
* example: myBean.myProperty.required instead of required.myBean.myProperty.
|
||||
*
|
||||
* Specifically:
|
||||
* <p>
|
||||
* Will create two message codes for an object error, in the following order:
|
||||
* <ul>
|
||||
* <li>1.: objectName.errorCode
|
||||
* <li>2.: errorCode
|
||||
* </ul>
|
||||
*
|
||||
* <p>
|
||||
* Will create four message codes for a field error, in the following order:
|
||||
* <ul>
|
||||
* <li>1.: object name.field.rrorCode
|
||||
* <li>2.: field.errorCode
|
||||
* <li>3.: fieldType.errorCode
|
||||
* <li>4.: errorCode
|
||||
* </ul>
|
||||
*
|
||||
* <p>
|
||||
* For example, in case of code "typeMismatch", object name "user", field "age" of type Integer:
|
||||
* <ul>
|
||||
* <li>1. try "user.age.typeMismatch"
|
||||
* <li>2. try "age.typeMismatch"
|
||||
* <li>3. try "java.lang.Integer.typeMismatch"
|
||||
* <li>4. try "typeMismatch"
|
||||
* </ul>
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public class WebFlowMessageCodesResolver implements MessageCodesResolver {
|
||||
|
||||
private String failureMessageCodePrefix = "";
|
||||
/**
|
||||
* The separator that this implementation uses when resolving message codes.
|
||||
*/
|
||||
public static final String CODE_SEPARATOR = ".";
|
||||
|
||||
private String prefix = "";
|
||||
|
||||
/**
|
||||
* The prefix to prepend to all validation failure message codes.
|
||||
* Specify a prefix to be applied to any code built by this resolver.
|
||||
* <p>
|
||||
* Default is none. Specify, for example, "validation." to get error codes like "validation.name.typeMismatch".
|
||||
*/
|
||||
public String getFailureMessageCodePrefix() {
|
||||
return failureMessageCodePrefix;
|
||||
public void setPrefix(String prefix) {
|
||||
this.prefix = (prefix != null ? prefix : "");
|
||||
}
|
||||
|
||||
/**
|
||||
* A prefix to prepend to all validation failure message codes; default if not set explicitly is "validation".
|
||||
* @param failureMessageCodePrefix the failure message code prefix
|
||||
* Return the prefix to be applied to any code built by this resolver.
|
||||
* <p>
|
||||
* Returns an empty String in case of no prefix.
|
||||
*/
|
||||
public void setFailureMessageCodePrefix(String failureMessageCodePrefix) {
|
||||
this.failureMessageCodePrefix = failureMessageCodePrefix;
|
||||
protected String getPrefix() {
|
||||
return this.prefix;
|
||||
}
|
||||
|
||||
public String[] resolveMessageCodes(String errorCode, String objectName) {
|
||||
String constraintMessageCode = appendFailureMessageCodePrefix().append(codeSeparator()).append(errorCode)
|
||||
.toString();
|
||||
String objectConstraintMessageCode = appendFailureMessageCodePrefix().append(codeSeparator())
|
||||
.append(objectName).append(codeSeparator()).append(errorCode).toString();
|
||||
return new String[] { objectConstraintMessageCode, constraintMessageCode };
|
||||
return new String[] { postProcessMessageCode(objectName + CODE_SEPARATOR + errorCode),
|
||||
postProcessMessageCode(errorCode) };
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the code list for the given code and field: an object/field-specific code, a field-specific code, a plain
|
||||
* error code.
|
||||
* <p>
|
||||
* Arrays, Lists and Maps are resolved both for specific elements and the whole collection.
|
||||
* <p>
|
||||
* See the {@link DefaultMessageCodesResolver class level Javadoc} for details on the generated codes.
|
||||
* @return the list of codes
|
||||
*/
|
||||
public String[] resolveMessageCodes(String errorCode, String objectName, String field, Class fieldType) {
|
||||
String propertyConstraintMessageCode = appendFailureMessageCodePrefix().append(codeSeparator()).append(
|
||||
objectName).append(codeSeparator()).append(field).append(codeSeparator()).append(errorCode).toString();
|
||||
String typeConstraintMessageCode = appendFailureMessageCodePrefix().append(codeSeparator()).append(fieldType)
|
||||
.append(codeSeparator()).append(errorCode).toString();
|
||||
return new String[] { propertyConstraintMessageCode, typeConstraintMessageCode, propertyConstraintMessageCode };
|
||||
List codeList = new ArrayList();
|
||||
List fieldList = new ArrayList();
|
||||
buildFieldList(field, fieldList);
|
||||
for (Iterator it = fieldList.iterator(); it.hasNext();) {
|
||||
String fieldInList = (String) it.next();
|
||||
codeList
|
||||
.add(postProcessMessageCode(objectName + CODE_SEPARATOR + fieldInList + CODE_SEPARATOR + errorCode));
|
||||
}
|
||||
int dotIndex = field.lastIndexOf('.');
|
||||
if (dotIndex != -1) {
|
||||
buildFieldList(field.substring(dotIndex + 1), fieldList);
|
||||
}
|
||||
for (Iterator it = fieldList.iterator(); it.hasNext();) {
|
||||
String fieldInList = (String) it.next();
|
||||
codeList.add(postProcessMessageCode(fieldInList + CODE_SEPARATOR + errorCode));
|
||||
}
|
||||
if (fieldType != null) {
|
||||
codeList.add(postProcessMessageCode(fieldType.getName() + CODE_SEPARATOR + errorCode));
|
||||
}
|
||||
codeList.add(postProcessMessageCode(errorCode));
|
||||
return StringUtils.toStringArray(codeList);
|
||||
}
|
||||
|
||||
protected StringBuilder appendFailureMessageCodePrefix() {
|
||||
return new StringBuilder().append(failureMessageCodePrefix);
|
||||
/**
|
||||
* Add both keyed and non-keyed entries for the supplied <code>field</code> to the supplied field list.
|
||||
*/
|
||||
protected void buildFieldList(String field, List fieldList) {
|
||||
fieldList.add(field);
|
||||
String plainField = field;
|
||||
int keyIndex = plainField.lastIndexOf('[');
|
||||
while (keyIndex != -1) {
|
||||
int endKeyIndex = plainField.indexOf(']', keyIndex);
|
||||
if (endKeyIndex != -1) {
|
||||
plainField = plainField.substring(0, keyIndex) + plainField.substring(endKeyIndex + 1);
|
||||
fieldList.add(plainField);
|
||||
keyIndex = plainField.lastIndexOf('[');
|
||||
} else {
|
||||
keyIndex = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected char codeSeparator() {
|
||||
return '.';
|
||||
/**
|
||||
* Post-process the given message code, built by this resolver.
|
||||
* <p>
|
||||
* The default implementation applies the specified prefix, if any.
|
||||
* @param code the message code as built by this resolver
|
||||
* @return the final message code to be returned
|
||||
* @see #setPrefix
|
||||
*/
|
||||
protected String postProcessMessageCode(String code) {
|
||||
return getPrefix() + code;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
package org.springframework.webflow.validation;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
public class WebFlowMessageResolverTests extends TestCase {
|
||||
private WebFlowMessageCodesResolver messageCodesResolver = new WebFlowMessageCodesResolver();
|
||||
|
||||
public void testResolveObjectMessageCodes() {
|
||||
String[] codes = messageCodesResolver.resolveMessageCodes("required", "testBean");
|
||||
assertEquals(2, codes.length);
|
||||
assertEquals("testBean.required", codes[0]);
|
||||
assertEquals("required", codes[1]);
|
||||
}
|
||||
|
||||
public void testResolveObjectMessageCodesWithPrefix() {
|
||||
messageCodesResolver.setPrefix("validation.");
|
||||
String[] codes = messageCodesResolver.resolveMessageCodes("required", "testBean");
|
||||
assertEquals(2, codes.length);
|
||||
assertEquals("validation.testBean.required", codes[0]);
|
||||
assertEquals("validation.required", codes[1]);
|
||||
}
|
||||
|
||||
public void testResolveFieldMessageCodes() {
|
||||
String[] codes = messageCodesResolver.resolveMessageCodes("required", "testBean", "foo", String.class);
|
||||
assertEquals(4, codes.length);
|
||||
assertEquals("testBean.foo.required", codes[0]);
|
||||
assertEquals("foo.required", codes[1]);
|
||||
assertEquals("java.lang.String.required", codes[2]);
|
||||
assertEquals("required", codes[3]);
|
||||
}
|
||||
|
||||
public void testResolveFieldMessageCodesKeyedField() {
|
||||
String[] codes = messageCodesResolver.resolveMessageCodes("required", "testBean", "foo[0]", String.class);
|
||||
assertEquals(6, codes.length);
|
||||
assertEquals("testBean.foo[0].required", codes[0]);
|
||||
assertEquals("testBean.foo.required", codes[1]);
|
||||
assertEquals("foo[0].required", codes[2]);
|
||||
assertEquals("foo.required", codes[3]);
|
||||
assertEquals("java.lang.String.required", codes[4]);
|
||||
assertEquals("required", codes[5]);
|
||||
}
|
||||
|
||||
public void testResolveFieldMessageCodesWithPrefix() {
|
||||
messageCodesResolver.setPrefix("validation.");
|
||||
String[] codes = messageCodesResolver.resolveMessageCodes("required", "testBean", "foo", String.class);
|
||||
assertEquals(4, codes.length);
|
||||
assertEquals("validation.testBean.foo.required", codes[0]);
|
||||
assertEquals("validation.foo.required", codes[1]);
|
||||
assertEquals("validation.java.lang.String.required", codes[2]);
|
||||
assertEquals("validation.required", codes[3]);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user