polish
This commit is contained in:
@@ -66,6 +66,7 @@ public class DefaultValidationFailureMessageResolverFactory implements Validatio
|
||||
ConversionService conversionService) {
|
||||
Assert.notNull(expressionParser, "The expressionParser is required");
|
||||
this.expressionParser = expressionParser;
|
||||
this.conversionService = conversionService;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -92,6 +93,8 @@ public class DefaultValidationFailureMessageResolverFactory implements Validatio
|
||||
|
||||
private static final String LABEL_ARGUMENT = "label";
|
||||
|
||||
private static final String VALUE_ARGUMENT = "value";
|
||||
|
||||
private ValidationFailure failure;
|
||||
|
||||
private ValidationFailureModelContext modelContext;
|
||||
@@ -116,7 +119,11 @@ public class DefaultValidationFailureMessageResolverFactory implements Validatio
|
||||
} else {
|
||||
label = appendLabelPrefix().append(CODE_SEPARATOR).append(modelContext.getObjectName()).toString();
|
||||
}
|
||||
stringArgs.put(LABEL_ARGUMENT, new DefaultMessageSourceResolvable(label));
|
||||
stringArgs.put(LABEL_ARGUMENT, new DefaultMessageSourceResolvable(new String[] { label }, failure
|
||||
.getPropertyName()));
|
||||
}
|
||||
if (!stringArgs.containsKey(VALUE_ARGUMENT) && failure.getPropertyName() != null) {
|
||||
stringArgs.put(VALUE_ARGUMENT, modelContext.getInvalidUserValue());
|
||||
}
|
||||
if (failure.getArguments() != null) {
|
||||
Iterator it = failure.getArguments().entrySet().iterator();
|
||||
@@ -140,7 +147,8 @@ public class DefaultValidationFailureMessageResolverFactory implements Validatio
|
||||
}
|
||||
|
||||
private String[] buildCodes() {
|
||||
String constraintMessageCode = appendMessageCodePrefix().append(failure.getConstraint()).toString();
|
||||
String constraintMessageCode = appendMessageCodePrefix().append(CODE_SEPARATOR).append(
|
||||
failure.getConstraint()).toString();
|
||||
if (failure.getPropertyName() != null) {
|
||||
String propertyConstraintMessageCode = appendMessageCodePrefix().append(CODE_SEPARATOR).append(
|
||||
modelContext.getObjectName()).append(CODE_SEPARATOR).append(failure.getPropertyName()).append(
|
||||
|
||||
@@ -19,6 +19,8 @@ import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import org.springframework.binding.message.Severity;
|
||||
import org.springframework.context.MessageSourceResolvable;
|
||||
import org.springframework.context.support.DefaultMessageSourceResolvable;
|
||||
|
||||
/**
|
||||
* A builder that provides a fluent interface for configuring a Validation failure. Example:
|
||||
@@ -80,7 +82,9 @@ public class ValidationFailureBuilder {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the failure to be of warning severity.
|
||||
* Adds a failure message argument.
|
||||
* @param name the arg name
|
||||
* @param value the arg value
|
||||
* @return this, for fluent call chaining
|
||||
*/
|
||||
public ValidationFailureBuilder arg(String name, Object value) {
|
||||
@@ -91,6 +95,18 @@ public class ValidationFailureBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a failure message argument whose value is also message source resolvable. Use this when the argument value
|
||||
* itself needs to be localized.
|
||||
* @param name the arg name
|
||||
* @param code the code that will be used to resolve the arg
|
||||
* @see MessageSourceResolvable
|
||||
* @return this, for fluent call chaining
|
||||
*/
|
||||
public ValidationFailureBuilder resolvableArg(String name, String code) {
|
||||
return arg(name, new DefaultMessageSourceResolvable(code));
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the ValidationFailure. Called after setting builder properties.
|
||||
* @return this, for fluent call chaining
|
||||
|
||||
@@ -12,14 +12,19 @@ public class ValidationFailureModelContext {
|
||||
|
||||
private String propertyTypeConverter;
|
||||
|
||||
private Object invalidValue;
|
||||
|
||||
/**
|
||||
* Creates a new validation model context.
|
||||
* @param objectName the object name
|
||||
* @param invalidValue the invalid value the user entered
|
||||
* @param propertyType the property type (may be null)
|
||||
* @param propertyTypeConverter the id of the property type converter (may be null)
|
||||
*/
|
||||
public ValidationFailureModelContext(String objectName, Class propertyType, String propertyTypeConverter) {
|
||||
public ValidationFailureModelContext(String objectName, Object invalidValue, Class propertyType,
|
||||
String propertyTypeConverter) {
|
||||
this.objectName = objectName;
|
||||
this.invalidValue = invalidValue;
|
||||
this.propertyType = propertyType;
|
||||
this.propertyTypeConverter = propertyTypeConverter;
|
||||
}
|
||||
@@ -31,6 +36,13 @@ public class ValidationFailureModelContext {
|
||||
return objectName;
|
||||
}
|
||||
|
||||
/**
|
||||
* The user entered value.
|
||||
*/
|
||||
public Object getInvalidUserValue() {
|
||||
return invalidValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* When reporting a property validation failure, the type of the property that failed to validate.
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
package org.springframework.binding.validation;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.jboss.el.ExpressionFactoryImpl;
|
||||
import org.springframework.binding.convert.converters.StringToObject;
|
||||
import org.springframework.binding.convert.service.DefaultConversionService;
|
||||
import org.springframework.binding.expression.el.ELExpressionParser;
|
||||
import org.springframework.binding.message.Message;
|
||||
import org.springframework.binding.message.MessageResolver;
|
||||
import org.springframework.context.support.ResourceBundleMessageSource;
|
||||
|
||||
public class DefaultValidationFailureMessageResolverFactoryTests extends TestCase {
|
||||
|
||||
private ELExpressionParser parser = new ELExpressionParser(new ExpressionFactoryImpl());
|
||||
|
||||
private DefaultConversionService conversionService = new DefaultConversionService();
|
||||
|
||||
private ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
|
||||
|
||||
private DefaultValidationFailureMessageResolverFactory factory;
|
||||
|
||||
public void setUp() {
|
||||
factory = new DefaultValidationFailureMessageResolverFactory(parser, conversionService);
|
||||
messageSource.setBasename("org.springframework.binding.validation.messages");
|
||||
}
|
||||
|
||||
public void testResolveMessage() {
|
||||
ValidationFailureBuilder builder = new ValidationFailureBuilder();
|
||||
ValidationFailure failure = builder.forProperty("foo").constraint("required").build();
|
||||
MessageResolver resolver = factory.createMessageResolver(failure, new ValidationFailureModelContext("testBean",
|
||||
"", String.class, null));
|
||||
Message message = resolver.resolveMessage(messageSource, Locale.getDefault());
|
||||
assertEquals("Foo is required", message.getText());
|
||||
}
|
||||
|
||||
public void testResolveMessageNoPropertyLabel() {
|
||||
ValidationFailureBuilder builder = new ValidationFailureBuilder();
|
||||
ValidationFailure failure = builder.forProperty("bogus").constraint("required").build();
|
||||
MessageResolver resolver = factory.createMessageResolver(failure, new ValidationFailureModelContext("testBean",
|
||||
"", String.class, null));
|
||||
Message message = resolver.resolveMessage(messageSource, Locale.getDefault());
|
||||
assertEquals("bogus is required", message.getText());
|
||||
}
|
||||
|
||||
public void testResolveMessageWithCustomArg() {
|
||||
ValidationFailureBuilder builder = new ValidationFailureBuilder();
|
||||
ValidationFailure failure = builder.forProperty("checkinDate").constraint("invalidFormat").arg("format",
|
||||
"yyyy-MM-dd").build();
|
||||
MessageResolver resolver = factory.createMessageResolver(failure, new ValidationFailureModelContext("testBean",
|
||||
"bogus", Date.class, null));
|
||||
Message message = resolver.resolveMessage(messageSource, Locale.getDefault());
|
||||
assertEquals("Check In Date must be in format yyyy-MM-dd", message.getText());
|
||||
}
|
||||
|
||||
public void testResolveMessageWithCustomResolvableArg() {
|
||||
ValidationFailureBuilder builder = new ValidationFailureBuilder();
|
||||
ValidationFailure failure = builder.forProperty("checkinDate").constraint("invalidFormat").resolvableArg(
|
||||
"format", "formats.dateFormat").build();
|
||||
MessageResolver resolver = factory.createMessageResolver(failure, new ValidationFailureModelContext("testBean",
|
||||
"bogus", Date.class, null));
|
||||
Message message = resolver.resolveMessage(messageSource, Locale.getDefault());
|
||||
assertEquals("Check In Date must be in format yyyy-MM-dd", message.getText());
|
||||
}
|
||||
|
||||
public void testResolveMessageWithValue() {
|
||||
ValidationFailureBuilder builder = new ValidationFailureBuilder();
|
||||
ValidationFailure failure = builder.forProperty("checkinDate").constraint("invalidFormat2").resolvableArg(
|
||||
"format", "formats.dateFormat").build();
|
||||
MessageResolver resolver = factory.createMessageResolver(failure, new ValidationFailureModelContext("testBean",
|
||||
"bogus", Date.class, null));
|
||||
Message message = resolver.resolveMessage(messageSource, Locale.getDefault());
|
||||
assertEquals("Check In Date must be in format yyyy-MM-dd but it was 'bogus'", message.getText());
|
||||
}
|
||||
|
||||
public void testResolveMessageWithArgDefaultConversion() {
|
||||
ValidationFailureBuilder builder = new ValidationFailureBuilder();
|
||||
ValidationFailure failure = builder.forProperty("amount").constraint("range").arg("min", new Integer(1)).arg(
|
||||
"max", new Integer(100)).build();
|
||||
MessageResolver resolver = factory.createMessageResolver(failure, new ValidationFailureModelContext("testBean",
|
||||
"bogus", Integer.class, null));
|
||||
Message message = resolver.resolveMessage(messageSource, Locale.getDefault());
|
||||
assertEquals("Amount must be between 1 and 100", message.getText());
|
||||
}
|
||||
|
||||
public void testResolveMessageWithArgCustomConversion() {
|
||||
conversionService.addConverter("stringToMoney", new StringToMoney());
|
||||
ValidationFailureBuilder builder = new ValidationFailureBuilder();
|
||||
ValidationFailure failure = builder.forProperty("amount").constraint("range").arg("min", new Money(1)).arg(
|
||||
"max", new Money(100)).build();
|
||||
MessageResolver resolver = factory.createMessageResolver(failure, new ValidationFailureModelContext("testBean",
|
||||
"bogus", Money.class, "stringToMoney"));
|
||||
Message message = resolver.resolveMessage(messageSource, Locale.getDefault());
|
||||
assertEquals("Amount must be between $1 and $100", message.getText());
|
||||
}
|
||||
|
||||
public static class Money {
|
||||
private int amount;
|
||||
|
||||
public Money(int amount) {
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
public int getAmount() {
|
||||
return amount;
|
||||
}
|
||||
}
|
||||
|
||||
public static class StringToMoney extends StringToObject {
|
||||
|
||||
public StringToMoney() {
|
||||
super(Money.class);
|
||||
}
|
||||
|
||||
protected Object toObject(String string, Class targetClass) throws Exception {
|
||||
throw new UnsupportedOperationException("Not supported");
|
||||
}
|
||||
|
||||
protected String toString(Object object) throws Exception {
|
||||
return "$" + String.valueOf(((Money) object).amount);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
validation.required=#{label} is required
|
||||
validation.invalidFormat=#{label} must be in format #{format}
|
||||
validation.invalidFormat2=#{label} must be in format #{format} but it was '#{value}'
|
||||
validation.range=#{label} must be between #{min} and #{max}
|
||||
|
||||
label.testBean.foo=Foo
|
||||
label.testBean.checkinDate=Check In Date
|
||||
label.testBean.amount=Amount
|
||||
|
||||
formats.dateFormat=yyyy-MM-dd
|
||||
Reference in New Issue
Block a user