backed out 2.0.x validation enhancements in favor of adding them in 3.0.0 aligned with spring 3
This commit is contained in:
@@ -1,50 +0,0 @@
|
||||
package org.springframework.binding.validation;
|
||||
|
||||
/**
|
||||
* Failure message codes factory specialization that applies default Spring MVC errorCode-to-messageCodes mapping rules.
|
||||
* The difference between this subclass and the default {@link ValidationFailureMessageCodesFactory} is where the
|
||||
* constraint code falls in the message code. Specifically, for a property validation failure the default algorithm
|
||||
* results in these codes:
|
||||
*
|
||||
* <pre>
|
||||
* ${failureMessageCodePrefix}.${model}.${property}.${constraint}
|
||||
* ${failureMessageCodePrefix}.${propertyType}.${constraint}
|
||||
* ${failureMessageCodePrefix}.${constraint}
|
||||
* </pre>
|
||||
*
|
||||
* while this original Spring MVC algorithm results in these codes:
|
||||
*
|
||||
* <pre>
|
||||
* ${failureMessageCodePrefix}.${constraint}.${model}.${property}
|
||||
* ${failureMessageCodePrefix}.${constraint}.${propertyType}
|
||||
* ${failureMessageCodePrefix}.${constraint}
|
||||
* </pre>
|
||||
*
|
||||
* Notice how the constraint comes after model/property qualifiers in the default algorithm, while the original Spring
|
||||
* MVC algorithm has the constraint come before. The default algorithm is believed to be more object oriented and
|
||||
* generally preferred for new applications. The Spring MVC algorithm is supported for backwards compatibility and
|
||||
* consistency with existing Spring MVC web applications.
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public class DefaultSpringMvcValidationFailureMessageCodesFactory extends ValidationFailureMessageCodesFactory {
|
||||
|
||||
public String[] createMessageCodes(ValidationFailure failure, ValidationFailureModelContext modelContext) {
|
||||
String constraintMessageCode = appendFailureMessageCodePrefix().append(codeSeparator()).append(
|
||||
failure.getConstraint()).toString();
|
||||
if (failure.getProperty() != null) {
|
||||
String propertyConstraintMessageCode = appendFailureMessageCodePrefix().append(codeSeparator()).append(
|
||||
failure.getConstraint()).append(codeSeparator()).append(modelContext.getModel()).append(
|
||||
codeSeparator()).append(failure.getProperty()).toString();
|
||||
String typeConstraintMessageCode = appendFailureMessageCodePrefix().append(codeSeparator()).append(
|
||||
failure.getConstraint()).append(codeSeparator()).append(modelContext.getPropertyType().getName())
|
||||
.toString();
|
||||
return new String[] { propertyConstraintMessageCode, typeConstraintMessageCode, constraintMessageCode };
|
||||
} else {
|
||||
String objectConstraintMessageCode = appendFailureMessageCodePrefix().append(codeSeparator()).append(
|
||||
failure.getConstraint()).append(codeSeparator()).append(modelContext.getModel()).toString();
|
||||
return new String[] { objectConstraintMessageCode, constraintMessageCode };
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,208 +0,0 @@
|
||||
/*
|
||||
* Copyright 2008 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.binding.validation;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.binding.collection.StringKeyedMapAdapter;
|
||||
import org.springframework.binding.convert.ConversionService;
|
||||
import org.springframework.binding.expression.Expression;
|
||||
import org.springframework.binding.expression.ExpressionParser;
|
||||
import org.springframework.binding.expression.support.FluentParserContext;
|
||||
import org.springframework.binding.message.Message;
|
||||
import org.springframework.binding.message.MessageResolver;
|
||||
import org.springframework.context.MessageSource;
|
||||
import org.springframework.context.MessageSourceResolvable;
|
||||
import org.springframework.context.support.DefaultMessageSourceResolvable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Maps validation failures to messages resolvable in a {@link MessageSource}. Configurable with an
|
||||
* {@link ExpressionParser} to allow messages containing #{expressions} to be parameterized with failure arguments.
|
||||
* Configurable with a {@link ConversionService} to support String-encoding failure arguments.
|
||||
*
|
||||
* Employs the following algorithm to map property validation failure to a message:
|
||||
* <ol>
|
||||
* <li>Try the ${failureMessageCodePrefix}.${model}.${property}.${constraint} code; if matches, resolve message and
|
||||
* return.
|
||||
* <li>Try the ${failureMessageCodePrefix}.${propertyType}.${constraint} code; if matches, resolve message and return.
|
||||
* <li>Try the ${failureMessageCodePrefix}.${constraint} code; if matches, resolve message and return.
|
||||
* </ol>
|
||||
*
|
||||
* Named message arguments may be denoted by using ${} or #{} expressions. For property validation failures, the value
|
||||
* of the "label" argument is automatically mapped to the message with code
|
||||
* ${labelMessageCodePrefix}.${objectName}.${propertyName}, allowing localization of the property label. Also, the
|
||||
* "value" argument holds a reference to the invalid user-entered value that triggered the failure.
|
||||
*
|
||||
* messages.properties example:
|
||||
*
|
||||
* <pre>
|
||||
* validation.booking.checkinDate.required=The Checkin Date is required
|
||||
* validation.java.util.Date.required=Dates are required
|
||||
* validation.required=#{label} is required
|
||||
* validation.range=#{label} must be between #{min} and #{max} but it was #{value}
|
||||
*
|
||||
* label.booking.checkoutDate=Check Out Date
|
||||
* label.booking.amount=Amount
|
||||
* </pre>
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public class DefaultValidationFailureMessageResolverFactory implements ValidationFailureMessageResolverFactory {
|
||||
|
||||
protected static final char CODE_SEPARATOR = '.';
|
||||
|
||||
private ExpressionParser expressionParser;
|
||||
|
||||
private ConversionService conversionService;
|
||||
|
||||
private String labelMessageCodePrefix = "label";
|
||||
|
||||
private ValidationFailureMessageCodesFactory failureMessageCodesFactory = new ValidationFailureMessageCodesFactory();
|
||||
|
||||
/**
|
||||
* Creates a new message resolver factory.
|
||||
* @param expressionParser the expression parser
|
||||
* @param conversionService the conversion service
|
||||
*/
|
||||
public DefaultValidationFailureMessageResolverFactory(ExpressionParser expressionParser,
|
||||
ConversionService conversionService) {
|
||||
Assert.notNull(expressionParser, "The expressionParser is required");
|
||||
this.expressionParser = expressionParser;
|
||||
this.conversionService = conversionService;
|
||||
}
|
||||
|
||||
/**
|
||||
* A prefix to prepend to all validation failure message codes; default is "validation".
|
||||
* @param failureMessageCodePrefix the failure message code prefix
|
||||
*/
|
||||
public void setFailureMessageCodePrefix(String failureMessageCodePrefix) {
|
||||
failureMessageCodesFactory.setFailureMessageCodePrefix(failureMessageCodePrefix);
|
||||
}
|
||||
|
||||
/**
|
||||
* The prefix to prepend to all property label message codes; default is "label".
|
||||
* @param labelMessageCodePrefix the label message code prefix
|
||||
*/
|
||||
public void setLabelMessageCodePrefix(String labelMessageCodePrefix) {
|
||||
this.labelMessageCodePrefix = labelMessageCodePrefix;
|
||||
}
|
||||
|
||||
public MessageResolver createMessageResolver(ValidationFailure failure, ValidationFailureModelContext modelContext) {
|
||||
return new DefaultValidationMessageResolver(failure, modelContext);
|
||||
}
|
||||
|
||||
private class DefaultValidationMessageResolver implements MessageResolver {
|
||||
|
||||
private static final String LABEL_ARGUMENT = "label";
|
||||
|
||||
private static final String VALUE_ARGUMENT = "value";
|
||||
|
||||
private ValidationFailure failure;
|
||||
|
||||
private ValidationFailureModelContext modelContext;
|
||||
|
||||
public DefaultValidationMessageResolver(ValidationFailure failure, ValidationFailureModelContext modelContext) {
|
||||
this.modelContext = modelContext;
|
||||
this.failure = failure;
|
||||
}
|
||||
|
||||
public Message resolveMessage(MessageSource messageSource, Locale locale) {
|
||||
DefaultMessageSourceResolvable resolvable = new DefaultMessageSourceResolvable(failureMessageCodesFactory
|
||||
.createMessageCodes(failure, modelContext), failure.getMessage());
|
||||
String text = messageSource.getMessage(resolvable, locale);
|
||||
Expression expression = expressionParser.parseExpression(text, new FluentParserContext()
|
||||
.evaluate(Map.class).template());
|
||||
Map stringArgs = new HashMap();
|
||||
if (!stringArgs.containsKey(LABEL_ARGUMENT)) {
|
||||
String label;
|
||||
if (failure.getProperty() != null) {
|
||||
label = appendLabelPrefix().append(CODE_SEPARATOR).append(modelContext.getModel()).append(
|
||||
CODE_SEPARATOR).append(failure.getProperty()).toString();
|
||||
} else {
|
||||
label = appendLabelPrefix().append(CODE_SEPARATOR).append(modelContext.getModel()).toString();
|
||||
}
|
||||
stringArgs.put(LABEL_ARGUMENT, new DefaultMessageSourceResolvable(new String[] { label }, failure
|
||||
.getProperty()));
|
||||
}
|
||||
if (!stringArgs.containsKey(VALUE_ARGUMENT) && failure.getProperty() != null) {
|
||||
stringArgs.put(VALUE_ARGUMENT, modelContext.getInvalidValue());
|
||||
}
|
||||
if (failure.getArguments() != null) {
|
||||
Iterator it = failure.getArguments().entrySet().iterator();
|
||||
while (it.hasNext()) {
|
||||
Map.Entry entry = (Map.Entry) it.next();
|
||||
Object arg = entry.getValue();
|
||||
if (!(arg instanceof String) && !(arg instanceof MessageSourceResolvable)) {
|
||||
if (modelContext.getPropertyConverter() != null
|
||||
&& arg.getClass().equals(modelContext.getPropertyType())) {
|
||||
arg = conversionService.executeConversion(modelContext.getPropertyConverter(), arg,
|
||||
String.class);
|
||||
} else {
|
||||
arg = conversionService.executeConversion(arg, String.class);
|
||||
}
|
||||
}
|
||||
stringArgs.put(entry.getKey(), arg);
|
||||
}
|
||||
}
|
||||
text = (String) expression.getValue(new LazyMessageResolvingMap(messageSource, locale, stringArgs));
|
||||
return new Message(failure.getProperty(), text, failure.getSeverity());
|
||||
}
|
||||
|
||||
private StringBuilder appendLabelPrefix() {
|
||||
return new StringBuilder().append(labelMessageCodePrefix);
|
||||
}
|
||||
}
|
||||
|
||||
private static class LazyMessageResolvingMap extends StringKeyedMapAdapter {
|
||||
|
||||
private MessageSource messageSource;
|
||||
|
||||
private Locale locale;
|
||||
|
||||
private Map args;
|
||||
|
||||
public LazyMessageResolvingMap(MessageSource messageSource, Locale locale, Map args) {
|
||||
this.messageSource = messageSource;
|
||||
this.locale = locale;
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
protected Object getAttribute(String key) {
|
||||
Object arg = args.get(key);
|
||||
if (arg instanceof MessageSourceResolvable) {
|
||||
arg = messageSource.getMessage(((MessageSourceResolvable) arg), locale);
|
||||
args.put(key, arg);
|
||||
}
|
||||
return arg;
|
||||
}
|
||||
|
||||
protected Iterator getAttributeNames() {
|
||||
return args.keySet().iterator();
|
||||
}
|
||||
|
||||
protected void removeAttribute(String key) {
|
||||
throw new UnsupportedOperationException("Should not be called");
|
||||
}
|
||||
|
||||
protected void setAttribute(String key, Object value) {
|
||||
throw new UnsupportedOperationException("Should not be called");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -28,6 +28,11 @@ import org.springframework.binding.message.MessageContext;
|
||||
*/
|
||||
public interface ValidationContext {
|
||||
|
||||
/**
|
||||
* A context for adding failure messages to display to the user directly.
|
||||
*/
|
||||
public MessageContext getMessageContext();
|
||||
|
||||
/**
|
||||
* The current user.
|
||||
*/
|
||||
@@ -45,53 +50,4 @@ public interface ValidationContext {
|
||||
*/
|
||||
public Object getUserValue(String property);
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public void addFailure(ValidationFailure failure);
|
||||
|
||||
/**
|
||||
* A context for adding messages to display to the user directly. The {@link #addFailure(ValidationFailure)}
|
||||
* operation provides a higher level of abstraction for reporting validation failures. This method provides more
|
||||
* control over the actual message added.
|
||||
*/
|
||||
public MessageContext getMessageContext();
|
||||
|
||||
}
|
||||
|
||||
@@ -1,119 +0,0 @@
|
||||
/*
|
||||
* Copyright 2008 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.binding.validation;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.binding.message.Severity;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* An indication of a validation failure. A failure is generated when a validation constraint is violated; for example
|
||||
* "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 {
|
||||
|
||||
private String property;
|
||||
|
||||
private String constraint;
|
||||
|
||||
private Severity severity;
|
||||
|
||||
private String message;
|
||||
|
||||
private Map details;
|
||||
|
||||
private Map arguments;
|
||||
|
||||
/**
|
||||
* Creates a new validation failure
|
||||
* @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)
|
||||
*/
|
||||
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.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 failure against the currently
|
||||
* validating object.
|
||||
*/
|
||||
public String getProperty() {
|
||||
return property;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* The severity of the failure, which measures the impact of the constraint violation.
|
||||
*/
|
||||
public Severity getSeverity() {
|
||||
return severity;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,166 +0,0 @@
|
||||
/*
|
||||
* Copyright 2004-2008 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.binding.validation;
|
||||
|
||||
import java.util.HashMap;
|
||||
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:
|
||||
*
|
||||
* <pre>
|
||||
* new ValidationFailureBuilder().forProperty("foo").constraint("required").build();
|
||||
* </pre>
|
||||
* @author Keith Donald
|
||||
*
|
||||
*/
|
||||
public class ValidationFailureBuilder {
|
||||
|
||||
private String property;
|
||||
|
||||
private String constraint;
|
||||
|
||||
private Severity severity;
|
||||
|
||||
private Map args;
|
||||
|
||||
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.
|
||||
* @param property the property name
|
||||
* @return this, for fluent call chaining
|
||||
*/
|
||||
public ValidationFailureBuilder forProperty(String property) {
|
||||
this.property = property;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of the constraint that failed.
|
||||
* @param constraint the name of the validation constraint
|
||||
* @return this, for fluent call chaining
|
||||
*/
|
||||
public ValidationFailureBuilder constraint(String constraint) {
|
||||
this.constraint = constraint;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 message(String message) {
|
||||
this.message = message;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a failure message argument.
|
||||
* @param name the argument name
|
||||
* @param value the argument value
|
||||
* @return this, for fluent call chaining
|
||||
*/
|
||||
public ValidationFailureBuilder arg(String name, Object value) {
|
||||
if (args == null) {
|
||||
args = new TreeMap();
|
||||
}
|
||||
args.put(name, value);
|
||||
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 argument name
|
||||
* @param code the code that will be used to resolve the argument
|
||||
* @see MessageSourceResolvable
|
||||
* @return this, for fluent call chaining
|
||||
*/
|
||||
public ValidationFailureBuilder resolvableArg(String name, String code) {
|
||||
return arg(name, new DefaultMessageSourceResolvable(code));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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(severity, property, constraint, message, details, args);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
package org.springframework.binding.validation;
|
||||
|
||||
/**
|
||||
* A helper factory for validation failure message codes. Subclasses may override
|
||||
* {@link #createMessageCodes(ValidationFailure, ValidationFailureModelContext)} to customize how failure message codes
|
||||
* are translated.
|
||||
*
|
||||
* For a property validation failure, the default algorithm in this class returns these message codes:
|
||||
*
|
||||
* <pre>
|
||||
* ${failureMessageCodePrefix}.${model}.${property}.${constraint}
|
||||
* ${failureMessageCodePrefix}.${propertyType}.${constraint}
|
||||
* ${failureMessageCodePrefix}.${constraint}
|
||||
* </pre>
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public class ValidationFailureMessageCodesFactory {
|
||||
|
||||
private String failureMessageCodePrefix = "validation";
|
||||
|
||||
/**
|
||||
* The prefix to prepend to all validation failure message codes.
|
||||
*/
|
||||
public String getFailureMessageCodePrefix() {
|
||||
return failureMessageCodePrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* A prefix to prepend to all validation failure message codes; default if not set explicitly is "validation".
|
||||
* @param failureMessageCodePrefix the failure message code prefix
|
||||
*/
|
||||
public void setFailureMessageCodePrefix(String failureMessageCodePrefix) {
|
||||
this.failureMessageCodePrefix = failureMessageCodePrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the message codes for the validation failure in the provided model context. Subclasses may override to
|
||||
* customize the failure message code mapping algorithm.
|
||||
* @param failure the validation failure
|
||||
* @param modelContext the failure model context
|
||||
* @return the failure message codes
|
||||
*/
|
||||
public String[] createMessageCodes(ValidationFailure failure, ValidationFailureModelContext modelContext) {
|
||||
String constraintMessageCode = appendFailureMessageCodePrefix().append(codeSeparator()).append(
|
||||
failure.getConstraint()).toString();
|
||||
if (failure.getProperty() != null) {
|
||||
String propertyConstraintMessageCode = appendFailureMessageCodePrefix().append(codeSeparator()).append(
|
||||
modelContext.getModel()).append(codeSeparator()).append(failure.getProperty()).append(
|
||||
codeSeparator()).append(failure.getConstraint()).toString();
|
||||
String typeConstraintMessageCode = appendFailureMessageCodePrefix().append(codeSeparator()).append(
|
||||
modelContext.getPropertyType().getName()).append(codeSeparator()).append(failure.getConstraint())
|
||||
.toString();
|
||||
return new String[] { propertyConstraintMessageCode, typeConstraintMessageCode, constraintMessageCode };
|
||||
} else {
|
||||
String objectConstraintMessageCode = appendFailureMessageCodePrefix().append(codeSeparator()).append(
|
||||
modelContext.getModel()).append(codeSeparator()).append(failure.getConstraint()).toString();
|
||||
return new String[] { objectConstraintMessageCode, constraintMessageCode };
|
||||
}
|
||||
}
|
||||
|
||||
protected StringBuilder appendFailureMessageCodePrefix() {
|
||||
return new StringBuilder().append(failureMessageCodePrefix);
|
||||
}
|
||||
|
||||
protected char codeSeparator() {
|
||||
return DefaultValidationFailureMessageResolverFactory.CODE_SEPARATOR;
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
/*
|
||||
* Copyright 2008 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.binding.validation;
|
||||
|
||||
import org.springframework.binding.message.Message;
|
||||
import org.springframework.binding.message.MessageContext;
|
||||
import org.springframework.binding.message.MessageResolver;
|
||||
|
||||
/**
|
||||
* Translates a ValidationFailure into a MessageResolver that can be used to add a localized failure {@link Message} to
|
||||
* a {@link MessageContext} .
|
||||
*
|
||||
* @author Keith Donald
|
||||
*/
|
||||
public interface ValidationFailureMessageResolverFactory {
|
||||
|
||||
/**
|
||||
* Creates a new MessageResolver that can resolve the failure {@link Message} for the reported ValidationFailure.
|
||||
* @param failure a validation failure reported by a validator
|
||||
* @param modelContext additional information about the model that failed to validate
|
||||
* @return the failure message resolver
|
||||
*/
|
||||
public MessageResolver createMessageResolver(ValidationFailure failure, ValidationFailureModelContext modelContext);
|
||||
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
package org.springframework.binding.validation;
|
||||
|
||||
/**
|
||||
* Provides additional model context regarding a validation failure. Used by a
|
||||
* {@link ValidationFailureMessageResolverFactory} to resolve failure messages.
|
||||
*/
|
||||
public interface ValidationFailureModelContext {
|
||||
|
||||
/**
|
||||
* The name of the model object that was validated.
|
||||
*/
|
||||
public String getModel();
|
||||
|
||||
/**
|
||||
* When reporting a property validation failure, the invalid user entered value.
|
||||
*/
|
||||
public Object getInvalidValue();
|
||||
|
||||
/**
|
||||
* When reporting a property validation failure, the type of the property that failed to validate.
|
||||
*/
|
||||
public Class getPropertyType();
|
||||
|
||||
/**
|
||||
* When reporting a property validation failure, the id of the custom converter used to format the UI display value.
|
||||
*/
|
||||
public String getPropertyConverter();
|
||||
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
package org.springframework.binding.validation;
|
||||
|
||||
import org.springframework.binding.validation.ConfirmationConstraint.ConfirmationForm;
|
||||
|
||||
public class AccountRegistrationForm {
|
||||
private String username;
|
||||
private String password;
|
||||
private String confirmedPassword;
|
||||
|
||||
public void validate(ValidationContext context) {
|
||||
context.setProperty("username");
|
||||
context.validate(new RequiredConstraint());
|
||||
context.validate(new LengthConstraint(3, 10));
|
||||
|
||||
context.setProperty("password");
|
||||
context.validate(new RequiredConstraint());
|
||||
context.validate(new LengthConstraint(6, 10));
|
||||
context.validate(new PasswordStrengthConstraint());
|
||||
|
||||
context.setProperty("confirmedPassword");
|
||||
context.validate(new ConfirmationConstraint(), new ConfirmationForm(password, confirmedPassword));
|
||||
}
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
package org.springframework.binding.validation;
|
||||
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
public class ConfirmationConstraint {
|
||||
|
||||
public void validate(ConfirmationForm form, ValidationContext context) {
|
||||
if (form.getValue() == null) {
|
||||
return;
|
||||
}
|
||||
if (!ObjectUtils.nullSafeEquals(form.getValue(), form.getConfirmedValue())) {
|
||||
context.addDefaultFailure();
|
||||
}
|
||||
}
|
||||
|
||||
public static class ConfirmationForm {
|
||||
|
||||
private Object value;
|
||||
|
||||
private Object confirmedValue;
|
||||
|
||||
public ConfirmationForm(String value, String confirmedValue) {
|
||||
this.value = value;
|
||||
this.confirmedValue = confirmedValue;
|
||||
}
|
||||
|
||||
public Object getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(Object value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public Object getConfirmedValue() {
|
||||
return confirmedValue;
|
||||
}
|
||||
|
||||
public void setConfirmedValue(Object confirmedValue) {
|
||||
this.confirmedValue = confirmedValue;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
package org.springframework.binding.validation;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
public class DefaultSpringMvcValidationFailureMessageCodesFactoryTests extends TestCase {
|
||||
private DefaultSpringMvcValidationFailureMessageCodesFactory factory = new DefaultSpringMvcValidationFailureMessageCodesFactory();
|
||||
|
||||
public void testCreateGeneralModelFailureMessageCodes() {
|
||||
ValidationFailure failure = new ValidationFailureBuilder().constraint("invalid").build();
|
||||
String[] codes = factory.createMessageCodes(failure, new TestValidationFailureModelContext("testBean", null,
|
||||
null, null));
|
||||
assertEquals("validation.invalid.testBean", codes[0]);
|
||||
assertEquals("validation.invalid", codes[1]);
|
||||
}
|
||||
|
||||
public void testCreatePropertyFailureMessageCodes() {
|
||||
ValidationFailure failure = new ValidationFailureBuilder().forProperty("foo").constraint("required").build();
|
||||
String[] codes = factory.createMessageCodes(failure, new TestValidationFailureModelContext("testBean", null,
|
||||
String.class, null));
|
||||
assertEquals("validation.required.testBean.foo", codes[0]);
|
||||
assertEquals("validation.required.java.lang.String", codes[1]);
|
||||
assertEquals("validation.required", codes[2]);
|
||||
}
|
||||
}
|
||||
@@ -1,123 +0,0 @@
|
||||
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;
|
||||
|
||||
private ValidationFailureBuilder builder = new ValidationFailureBuilder();
|
||||
|
||||
public void setUp() {
|
||||
factory = new DefaultValidationFailureMessageResolverFactory(parser, conversionService);
|
||||
messageSource.setBasename("org.springframework.binding.validation.messages");
|
||||
}
|
||||
|
||||
public void testResolveMessage() {
|
||||
ValidationFailure failure = builder.forProperty("foo").constraint("required").build();
|
||||
MessageResolver resolver = factory.createMessageResolver(failure, new TestValidationFailureModelContext(
|
||||
"testBean", "", String.class, null));
|
||||
Message message = resolver.resolveMessage(messageSource, Locale.getDefault());
|
||||
assertEquals("Foo is required", message.getText());
|
||||
}
|
||||
|
||||
public void testResolveMessageNoPropertyLabel() {
|
||||
ValidationFailure failure = builder.forProperty("bogus").constraint("required").build();
|
||||
MessageResolver resolver = factory.createMessageResolver(failure, new TestValidationFailureModelContext(
|
||||
"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 TestValidationFailureModelContext(
|
||||
"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() {
|
||||
ValidationFailure failure = builder.forProperty("checkinDate").constraint("invalidFormat").resolvableArg(
|
||||
"format", "formats.dateFormat").build();
|
||||
MessageResolver resolver = factory.createMessageResolver(failure, new TestValidationFailureModelContext(
|
||||
"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() {
|
||||
ValidationFailure failure = builder.forProperty("checkinDate").constraint("invalidFormat2").resolvableArg(
|
||||
"format", "formats.dateFormat").build();
|
||||
MessageResolver resolver = factory.createMessageResolver(failure, new TestValidationFailureModelContext(
|
||||
"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() {
|
||||
ValidationFailure failure = builder.forProperty("amount").constraint("range").arg("min", new Integer(1)).arg(
|
||||
"max", new Integer(100)).build();
|
||||
MessageResolver resolver = factory.createMessageResolver(failure, new TestValidationFailureModelContext(
|
||||
"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());
|
||||
ValidationFailure failure = builder.forProperty("amount").constraint("range").arg("min", new Money(1)).arg(
|
||||
"max", new Money(100)).build();
|
||||
MessageResolver resolver = factory.createMessageResolver(failure, new TestValidationFailureModelContext(
|
||||
"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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
package org.springframework.binding.validation;
|
||||
|
||||
public class LengthConstraint {
|
||||
|
||||
private Integer min;
|
||||
|
||||
private Integer max;
|
||||
|
||||
public LengthConstraint(int min, int max) {
|
||||
this.min = new Integer(min);
|
||||
this.max = new Integer(max);
|
||||
}
|
||||
|
||||
public Integer getMin() {
|
||||
return min;
|
||||
}
|
||||
|
||||
public Integer getMax() {
|
||||
return max;
|
||||
}
|
||||
|
||||
public void validate(String value, ValidationContext context) {
|
||||
if (value == null || value.length() < min.intValue() || value.length() > max.intValue()) {
|
||||
context.addFailure(createFailure());
|
||||
}
|
||||
}
|
||||
|
||||
protected ValidationFailure createFailure() {
|
||||
return new ValidationFailureBuilder().arg("min", getMin()).arg("max", getMax()).build();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
package org.springframework.binding.validation;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class PasswordStrengthConstraint {
|
||||
|
||||
private Pattern pattern = Pattern.compile("^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])[0-9a-zA-Z]$");
|
||||
|
||||
public void validate(String password, ValidationContext context) {
|
||||
Matcher matcher = pattern.matcher(password);
|
||||
if (!matcher.find()) {
|
||||
context.addFailure(createFailure());
|
||||
}
|
||||
}
|
||||
|
||||
protected ValidationFailure createFailure() {
|
||||
return new ValidationFailureBuilder().warning().detail("cause").detail("recommendedAction")
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package org.springframework.binding.validation;
|
||||
|
||||
public class RequiredConstraint {
|
||||
|
||||
public void validate(Object value, ValidationContext context) {
|
||||
if (value == null) {
|
||||
context.addDefaultFailure();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
/*
|
||||
* Copyright 2008 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.binding.validation;
|
||||
|
||||
import org.springframework.binding.validation.ValidationFailureMessageResolverFactory;
|
||||
import org.springframework.binding.validation.ValidationFailureModelContext;
|
||||
|
||||
/**
|
||||
* Provides additional model context regarding a validation failure. Used by a
|
||||
* {@link ValidationFailureMessageResolverFactory} to resolve failure messages.
|
||||
*/
|
||||
public class TestValidationFailureModelContext implements ValidationFailureModelContext {
|
||||
|
||||
private String model;
|
||||
|
||||
private Object invalidValue;
|
||||
|
||||
private Class propertyType;
|
||||
|
||||
private String propertyConverter;
|
||||
|
||||
/**
|
||||
* Creates a new validation model context.
|
||||
* @param model the name of the model object that was validated
|
||||
* @param invalidValue the invalid value the user entered (may be null)
|
||||
* @param propertyType the type of the property that failed to validate (may be null)
|
||||
* @param propertyConverter the id of the custom converter configured to format the property value (may be null)
|
||||
*/
|
||||
public TestValidationFailureModelContext(String model, Object invalidValue, Class propertyType,
|
||||
String propertyConverter) {
|
||||
this.model = model;
|
||||
this.invalidValue = invalidValue;
|
||||
this.propertyType = propertyType;
|
||||
this.propertyConverter = propertyConverter;
|
||||
}
|
||||
|
||||
public String getModel() {
|
||||
return model;
|
||||
}
|
||||
|
||||
public Object getInvalidValue() {
|
||||
return invalidValue;
|
||||
}
|
||||
|
||||
public Class getPropertyType() {
|
||||
return propertyType;
|
||||
}
|
||||
|
||||
public String getPropertyConverter() {
|
||||
return propertyConverter;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
package org.springframework.binding.validation;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
public class ValidationFailureMessageCodesFactoryTests extends TestCase {
|
||||
private ValidationFailureMessageCodesFactory factory = new ValidationFailureMessageCodesFactory();
|
||||
|
||||
public void testCreateGeneralModelFailureMessageCodes() {
|
||||
ValidationFailure failure = new ValidationFailureBuilder().constraint("invalid").build();
|
||||
String[] codes = factory.createMessageCodes(failure, new TestValidationFailureModelContext("testBean", null,
|
||||
null, null));
|
||||
assertEquals("validation.testBean.invalid", codes[0]);
|
||||
assertEquals("validation.invalid", codes[1]);
|
||||
}
|
||||
|
||||
public void testCreatePropertyFailureMessageCodes() {
|
||||
ValidationFailure failure = new ValidationFailureBuilder().forProperty("foo").constraint("required").build();
|
||||
String[] codes = factory.createMessageCodes(failure, new TestValidationFailureModelContext("testBean", null,
|
||||
String.class, null));
|
||||
assertEquals("validation.testBean.foo.required", codes[0]);
|
||||
assertEquals("validation.java.lang.String.required", codes[1]);
|
||||
assertEquals("validation.required", codes[2]);
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
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
|
||||
@@ -8,33 +8,26 @@ import org.springframework.binding.mapping.MappingResults;
|
||||
import org.springframework.binding.mapping.MappingResultsCriteria;
|
||||
import org.springframework.binding.message.MessageContext;
|
||||
import org.springframework.binding.validation.ValidationContext;
|
||||
import org.springframework.binding.validation.ValidationFailure;
|
||||
import org.springframework.binding.validation.ValidationFailureMessageResolverFactory;
|
||||
import org.springframework.binding.validation.ValidationFailureModelContext;
|
||||
import org.springframework.webflow.execution.RequestContext;
|
||||
|
||||
public class DefaultValidationContext implements ValidationContext {
|
||||
|
||||
private String modelName;
|
||||
|
||||
private Object model;
|
||||
|
||||
private String converterId;
|
||||
|
||||
private RequestContext requestContext;
|
||||
|
||||
private String eventId;
|
||||
|
||||
private MappingResults mappingResults;
|
||||
|
||||
private ValidationFailureMessageResolverFactory failureMessageResolverFactory;
|
||||
|
||||
public DefaultValidationContext(RequestContext requestContext, String eventId, MappingResults mappingResults) {
|
||||
this.requestContext = requestContext;
|
||||
this.eventId = eventId;
|
||||
this.mappingResults = mappingResults;
|
||||
}
|
||||
|
||||
public MessageContext getMessageContext() {
|
||||
return requestContext.getMessageContext();
|
||||
}
|
||||
|
||||
public String getUserEvent() {
|
||||
return eventId;
|
||||
}
|
||||
@@ -48,48 +41,6 @@ public class DefaultValidationContext implements ValidationContext {
|
||||
return result != null ? result.getOriginalValue() : null;
|
||||
}
|
||||
|
||||
public void setProperty(String property) {
|
||||
throw new UnsupportedOperationException("Not yet implemented");
|
||||
}
|
||||
|
||||
public void validate(Object constraint, Object propertyContext) {
|
||||
throw new UnsupportedOperationException("Not yet implemented");
|
||||
}
|
||||
|
||||
public void validate(Object constraint) {
|
||||
throw new UnsupportedOperationException("Not yet implemented");
|
||||
}
|
||||
|
||||
public void addDefaultFailure() {
|
||||
throw new UnsupportedOperationException("Not yet implemented");
|
||||
}
|
||||
|
||||
public void addFailure(final ValidationFailure failure) {
|
||||
ValidationFailureModelContext modelContext = new ValidationFailureModelContext() {
|
||||
public String getModel() {
|
||||
return modelName;
|
||||
}
|
||||
|
||||
public Object getInvalidValue() {
|
||||
return getUserValue(failure.getProperty());
|
||||
}
|
||||
|
||||
public Class getPropertyType() {
|
||||
MappingResult result = getMappingResult(failure.getProperty());
|
||||
return result != null ? result.getMapping().getTargetExpression().getValueType(model) : null;
|
||||
}
|
||||
|
||||
public String getPropertyConverter() {
|
||||
return converterId;
|
||||
}
|
||||
};
|
||||
getMessageContext().addMessage(failureMessageResolverFactory.createMessageResolver(failure, modelContext));
|
||||
}
|
||||
|
||||
public MessageContext getMessageContext() {
|
||||
return requestContext.getMessageContext();
|
||||
}
|
||||
|
||||
private MappingResult getMappingResult(String property) {
|
||||
if (mappingResults != null) {
|
||||
List results = mappingResults.getResults(new PropertyMappingResult(property));
|
||||
|
||||
Reference in New Issue
Block a user