added SmartValidator interface with general support for validation hints; added custom @Valid annotation with support for JSR-303 validation groups; JSR-303 SpringValidatorAdapter and MVC data binding provide support for validation groups (SPR-6373)

This commit is contained in:
Juergen Hoeller
2011-12-03 15:44:33 +00:00
parent 4bfcb79ae3
commit 49a2aaf023
11 changed files with 324 additions and 142 deletions

View File

@@ -706,8 +706,22 @@ public class DataBinder implements PropertyEditorRegistry, TypeConverter {
* @see #getBindingResult()
*/
public void validate() {
this.validator.validate(getTarget(), getBindingResult());
}
/**
* Invoke the specified Validator, if any, with the given validation hints.
* <p>Note: Validation hints may get ignored by the actual target Validator.
* @param validationHints one or more hint objects to be passed to a {@link SmartValidator}
* @see #setValidator(Validator)
* @see SmartValidator#validate(Object, Errors, Object...)
*/
public void validate(Object... validationHints) {
Validator validator = getValidator();
if (validator != null) {
if (validator instanceof SmartValidator) {
((SmartValidator) validator).validate(getTarget(), getBindingResult(), validationHints);
}
else if (validator != null) {
validator.validate(getTarget(), getBindingResult());
}
}

View File

@@ -0,0 +1,47 @@
/*
* Copyright 2002-2011 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;
/**
* Extended variant of the {@link Validator} interface, adding support for
* validation 'hints'.
*
* @author Juergen Hoeller
* @since 3.1
*/
public interface SmartValidator extends Validator {
/**
* Validate the supplied <code>target</code> object, which must be
* of a {@link Class} for which the {@link #supports(Class)} method
* typically has (or would) return <code>true</code>.
* <p>The supplied {@link Errors errors} instance can be used to report
* any resulting validation errors.
* <p><b>This variant of <code>validate</code> supports validation hints,
* such as validation groups against a JSR-303 provider</b> (in this case,
* the provided hint objects need to be annotation arguments of type Class).
* <p>Note: Validation hints may get ignored by the actual target Validator,
* in which case this method is supposed to be behave just like its regular
* {@link #validate(Object, Errors)} sibling.
* @param target the object that is to be validated (can be <code>null</code>)
* @param errors contextual state about the validation process (never <code>null</code>)
* @param validationHints one or more hint objects to be passed to the validation engine
* @see ValidationUtils
*/
void validate(Object target, Errors errors, Object... validationHints);
}

View File

@@ -0,0 +1,56 @@
/*
* Copyright 2002-2011 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.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Extended variant of JSR-303's {@link javax.validation.Valid},
* supporting the specification of validation groups. Designed for
* convenient use with Spring's JSR-303 support but not JSR-303 specific.
*
* <p>Can be used e.g. with Spring MVC handler methods arguments.
* Supported through {@link org.springframework.validation.SmartValidator}'s
* validation hint concept, with validation group classes acting as hint objects.
*
* @author Juergen Hoeller
* @since 3.1
* @see javax.validation.Validator#validate(Object, Class[])
* @see org.springframework.validation.SmartValidator#validate(Object, org.springframework.validation.Errors, Object...)
* @see org.springframework.validation.beanvalidation.SpringValidatorAdapter
*/
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Valid {
/**
* Specify one or more validation groups to apply to the validation step
* kicked off by this annotation.
* <p>JSR-303 defines validation groups as custom annotations which an application declares
* for the sole purpose of using them as type-safe group arguments, as implemented in
* {@link org.springframework.validation.beanvalidation.SpringValidatorAdapter}.
* <p>Other {@link org.springframework.validation.SmartValidator} implementations may
* support class arguments in other ways as well.
*/
Class[] value() default {};
}

View File

@@ -0,0 +1,8 @@
/**
* Support classes for annotation-based constraint evaluation,
* e.g. using a JSR-303 Bean Validation provider.
*
* <p>Provides an extended variant of JSR-303's <code>@Valid</code>,
* supporting the specification of validation groups.
*/
package org.springframework.validation.annotation;

View File

@@ -17,6 +17,7 @@
package org.springframework.validation.beanvalidation;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
@@ -33,7 +34,7 @@ import org.springframework.validation.BindingResult;
import org.springframework.validation.Errors;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.validation.Validator;
import org.springframework.validation.SmartValidator;
/**
* Adapter that takes a JSR-303 <code>javax.validator.Validator</code>
@@ -46,7 +47,7 @@ import org.springframework.validation.Validator;
* @author Juergen Hoeller
* @since 3.0
*/
public class SpringValidatorAdapter implements Validator, javax.validation.Validator {
public class SpringValidatorAdapter implements SmartValidator, javax.validation.Validator {
private static final Set<String> internalAnnotationAttributes = new HashSet<String>(3);
@@ -85,8 +86,29 @@ public class SpringValidatorAdapter implements Validator, javax.validation.Valid
}
public void validate(Object target, Errors errors) {
Set<ConstraintViolation<Object>> result = this.targetValidator.validate(target);
for (ConstraintViolation<Object> violation : result) {
processConstraintViolations(this.targetValidator.validate(target), errors);
}
public void validate(Object target, Errors errors, Object[] validationHints) {
Set<Class> groups = new LinkedHashSet<Class>();
if (validationHints != null) {
for (Object hint : validationHints) {
if (hint instanceof Class) {
groups.add((Class) hint);
}
}
}
processConstraintViolations(this.targetValidator.validate(target, groups.toArray(new Class[groups.size()])), errors);
}
/**
* Process the given JSR-303 ConstraintViolations, adding corresponding errors to
* the provided Spring {@link Errors} object.
* @param violations the JSR-303 ConstraintViolation results
* @param errors the Spring errors object to register to
*/
protected void processConstraintViolations(Set<ConstraintViolation<Object>> violations, Errors errors) {
for (ConstraintViolation<Object> violation : violations) {
String field = violation.getPropertyPath().toString();
FieldError fieldError = errors.getFieldError(field);
if (fieldError == null || !fieldError.isBindingFailure()) {