validation testing

This commit is contained in:
Keith Donald
2009-03-03 21:38:02 +00:00
parent 0f2c5a8d3f
commit ffce230b01
10 changed files with 287 additions and 41 deletions

View File

@@ -124,7 +124,7 @@ public class DefaultValidationFailureMessageResolverFactory implements Validatio
public Message resolveMessage(MessageSource messageSource, Locale locale) {
DefaultMessageSourceResolvable resolvable = new DefaultMessageSourceResolvable(failureMessageCodesFactory
.createMessageCodes(failure, modelContext), failure.getDefaultMessage());
.createMessageCodes(failure, modelContext), failure.getMessage());
String text = messageSource.getMessage(resolvable, locale);
Expression expression = expressionParser.parseExpression(text, new FluentParserContext()
.evaluate(Map.class).template());

View File

@@ -46,10 +46,41 @@ public interface ValidationContext {
public Object getUserValue(String property);
/**
* Add a validation failure to this context. Called by a validator to report failures against the current object
* being validated. Use to report a general failure against the object, or a specific failure against a property on
* the object. The failure code provided is typically mapped to one or message codes that result in a Message being
* added to the {@link MessageContext}.
* Set the property of the model that is about to be validated. This property becomes the "current property"
* associated with this context.
* @param property the name of the property that will be validated
*/
public void setProperty(String property);
/**
* Validate the current property using the constraint provided. The value of the current property will be passed
* directly to the constraint for validation. Internally, the constraint may use {@link #addDefaultFailure()} to
* report a default failure, or {@link #addFailure(ValidationFailure)} to report a custom failure.
* @param constraint the validation constraint to invoek
*/
public void validate(Object constraint);
/**
* Validate the current property context using the constraint provided. Call this method when additional context
* besides just the property value is required for constraint validation. Internally, the constraint may use
* {@link #addDefaultFailure()} to report a default failure, or {@link #addFailure(ValidationFailure)} to report a
* custom failure.
* @param constraint the validation constraint to invoke
* @param propertyContext the property context object to validate
*/
public void validate(Object constraint, Object propertyContext);
/**
* Add the default validation failure for the current context. Called by a validation constraint to report failures
* against the current object being validated.
*/
public void addDefaultFailure();
/**
* Add a validation failure to this context. Called by a validation constraint to report failures against the
* current object being validated. Use to report a general failure against the object, or a specific failure against
* a property on the object. The failure code provided is typically mapped to one or message codes that result in a
* Message being added to the {@link MessageContext}.
* @param failure the validation failure
* @see #getMessageContext()
* @see ValidationFailureMessageResolverFactory

View File

@@ -15,6 +15,7 @@
*/
package org.springframework.binding.validation;
import java.util.Collections;
import java.util.Map;
import org.springframework.binding.message.Severity;
@@ -22,9 +23,10 @@ import org.springframework.util.Assert;
/**
* An indication of a validation failure. A failure is generated when a validation constraint is violated; for example
* "required", "maxLength", "invalidFormat", or "range". A failure has a severity describing the intensity of the
* violation. A failure may have additional arguments that can be used as named parameters in a UI display message. A
* failure can also have a default message to display if no suitable message can be resolved.
* "required", "length", "invalidFormat". A failure has a severity describing the intensity of the violation. A failure
* may have an explicit message summarizing what went wrong, and may also provide additional details, such as a cause or
* suggested recovery action. A failure may also have additional arguments that can be used as named parameters in any
* UI display messages.
*/
public class ValidationFailure {
@@ -34,38 +36,43 @@ public class ValidationFailure {
private Severity severity;
private Map arguments;
private String message;
private String defaultMessage;
private Map details;
private Map arguments;
/**
* Creates a new validation failure
* @param property the property that failed to validate (may be null to indicate a general failure)
* @param constraint the name of the validation constraint that failed (required)
* @param severity the severity of the failure (required)
* @param property the property that failed to validate (may be null)
* @param constraint the name of the validation constraint that failed (may be null)
* @param message an explicit failure message (may be null)
* @param details additional failure details (may be null)
* @param arguments named failure arguments (may be null)
* @param defaultMessage the default message text (may be null)
*/
public ValidationFailure(String property, String constraint, Severity severity, Map arguments, String defaultMessage) {
Assert.hasText(constraint, "The constraint is required");
public ValidationFailure(Severity severity, String property, String constraint, String message, Map details,
Map arguments) {
Assert.notNull(severity, "The severity is required");
this.property = property;
this.constraint = constraint;
this.severity = severity;
this.arguments = arguments;
this.defaultMessage = defaultMessage;
this.message = message;
this.details = details != null ? Collections.unmodifiableMap(details) : Collections.EMPTY_MAP;
this.arguments = arguments != null ? Collections.unmodifiableMap(arguments) : Collections.EMPTY_MAP;
}
/**
* The name of the property that failed to validate. May be null to indicate a general failure against the validated
* object.
* The name of the property that failed to validate. May be null to indicate a failure against the currently
* validating object.
*/
public String getProperty() {
return property;
}
/**
* The validation constraint that caused this failure to be reported.
* The name of the validation constraint that caused this failure to be reported. This constraint name can be used
* to resolve the failure message if no explicit {@link #getMessage()} is configured. May be null to indicate a
* failure against the currently validating constraint.
*/
public String getConstraint() {
return constraint;
@@ -79,20 +86,34 @@ public class ValidationFailure {
}
/**
* An map of arguments that can be used as named parameters in the message associated with this validation failure.
* Each constraint that can fail defines a set of arguments that are specific to it. For example, a range constriant
* might define arguments of "min" and "max" of Integer values. In the message bundle, you then might see
* "range=The ${label} field value must be between ${min} and ${max}".
* The message summarizing this failure. May be a literal string or a resolvable message code. Can be null. If null,
* the failure message will be resolved using the constraint that was being validated when this failure was
* reported.
*/
public String getMessage() {
return message;
}
/**
* A map of details providing additional information about this failure. Each entry in this map is a failure detail
* item that has a name and value. The name uniquely identifies the failure detail and describes its purpose; for
* example, a "cause" or "recommendedAction". The value is the failure detail message, either a literal string or
* resolvable code. If resolvable, the detail code is relative to the constraint associated with this failure.
* Returns an empty map if no details are present.
*/
public Map getDetails() {
return details;
}
/**
* An map of arguments that can be used as named parameters in resolvable messages associated with this validation
* failure. Each constraint that can fail defines a set of arguments that are specific to it. For example, a length
* constraint might define arguments of "min" and "max" of Integer values. In the message bundle, you then might see
* "length=The ${label} field value must be between ${min} and ${max}". Returns an empty map if no arguments are
* present.
*/
public Map getArguments() {
return arguments;
}
/**
* The default message to display if no suitable display message can be resolved for this failure.
*/
public String getDefaultMessage() {
return defaultMessage;
}
}

View File

@@ -15,6 +15,7 @@
*/
package org.springframework.binding.validation;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
@@ -41,7 +42,27 @@ public class ValidationFailureBuilder {
private Map args;
private String defaultText;
private String message;
private Map details;
/**
* Sets the failure to be of warning severity.
* @return this, for fluent call chaining
*/
public ValidationFailureBuilder warning() {
severity = Severity.WARNING;
return this;
}
/**
* Sets the failure to be of error severity. This is the default Severity.
* @return this, for fluent call chaining
*/
public ValidationFailureBuilder error() {
severity = Severity.ERROR;
return this;
}
/**
* Sets the property the failure occurred against.
@@ -64,20 +85,38 @@ public class ValidationFailureBuilder {
}
/**
* Sets the failure to be of warning severity.
* Sets an explicit failure message. The value may be a literal string or a resolvable message code.
* @param message the failure message
* @return this, for fluent call chaining
*/
public ValidationFailureBuilder warning() {
severity = Severity.WARNING;
public ValidationFailureBuilder message(String message) {
this.message = message;
return this;
}
/**
* Sets the failure to be of error severity.
* Add a detail to associate with the failure. The value provided serves as both the logical name of the detail and
* the code used to resolve the detail message text.
* @param nameAndValue the value to use as both the logical name of the message and the constraint-relative message
* code; for example, "cause" or "recommendedAction".
* @return this, for fluent call chaining
*/
public ValidationFailureBuilder error() {
severity = Severity.ERROR;
public ValidationFailureBuilder detail(String nameAndValue) {
return detail(nameAndValue, nameAndValue);
}
/**
* Add a detail to associate with the failure.
* @param name the logical name of the message; for example, "cause" or "recommendedAction"
* @param value the detail value, either a hard coded message string or a constraint-relative message code used to
* resolve the detail message text
* @return this, for fluent call chaining
*/
public ValidationFailureBuilder detail(String name, String value) {
if (details == null) {
details = new HashMap();
}
details.put(name, value);
return this;
}
@@ -108,14 +147,20 @@ public class ValidationFailureBuilder {
}
/**
* Build the ValidationFailure. Called after setting builder properties.
* Build the ValidationFailure. Call after setting builder properties.
* @see #forProperty(String)
* @see #constraint(String)
* @see #message(String)
* @see #detail(String)
* @see #arg(String, Object)
* @see #resolvableArg(String, String)
* @return this, for fluent call chaining
*/
public ValidationFailure build() {
if (severity == null) {
severity = Severity.ERROR;
}
return new ValidationFailure(property, constraint, severity, args, defaultText);
return new ValidationFailure(severity, property, constraint, message, details, args);
}
}