added MethodValidationInterceptor/PostProcessor for Hibernate Validator 4.2 based method validation; renamed Spring's variant of @Valid to @Validated
This commit is contained in:
parent
2dba480d9d
commit
e648245eb3
|
|
@ -23,24 +23,31 @@ 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.
|
||||
* 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.
|
||||
*
|
||||
* <p>Can also be used with method level validation, indicating that a specific
|
||||
* class is supposed to be validated at the method level (acting as a pointcut
|
||||
* for the corresponding validation interceptor), but also optionally specifying
|
||||
* the validation groups for method-level validation in the annotated class.
|
||||
* Can also be used as a meta-annotation on a custom stereotype annotation.
|
||||
*
|
||||
* @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
|
||||
* @see org.springframework.validation.beanvalidation.MethodValidationPostProcessor
|
||||
*/
|
||||
@Target(ElementType.PARAMETER)
|
||||
@Target({ElementType.TYPE, ElementType.PARAMETER})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface Valid {
|
||||
public @interface Validated {
|
||||
|
||||
/**
|
||||
* Specify one or more validation groups to apply to the validation step
|
||||
|
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
* 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.beanvalidation;
|
||||
|
||||
import java.util.Set;
|
||||
import javax.validation.Validation;
|
||||
import javax.validation.Validator;
|
||||
import javax.validation.ValidatorFactory;
|
||||
|
||||
import org.aopalliance.intercept.MethodInterceptor;
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
import org.hibernate.validator.HibernateValidator;
|
||||
import org.hibernate.validator.method.MethodConstraintViolation;
|
||||
import org.hibernate.validator.method.MethodConstraintViolationException;
|
||||
import org.hibernate.validator.method.MethodValidator;
|
||||
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
/**
|
||||
* An AOP Alliance {@link MethodInterceptor} implementation that delegates to a
|
||||
* JSR-303 provider for performing method-level validation on annotated methods.
|
||||
*
|
||||
* <p>Applicable methods have JSR-303 constraint annotations on their parameters
|
||||
* and/or on their return value (in the latter case specified at the method level,
|
||||
* typically as inline annotation).
|
||||
*
|
||||
* <p>E.g.: <code>public @NotNull Object myValidMethod(@NotNull String arg1, @Max(10) int arg2)</code>
|
||||
*
|
||||
* <p>Validation groups can be specified through Spring's {@link Validated} annotation
|
||||
* at the type level of the containing target class, applying to all public service methods
|
||||
* of that class. By default, JSR-303 will validate against its default group only.
|
||||
*
|
||||
* <p>As of Spring 3.1, this functionality requires Hibernate Validator 4.2 or higher.
|
||||
* In Spring 3.2, this class will autodetect a Bean Validation 1.1 compliant provider
|
||||
* and automatically use the standard method validation support there (once available).
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.1
|
||||
* @see MethodValidationPostProcessor
|
||||
* @see org.hibernate.validator.method.MethodValidator
|
||||
*/
|
||||
public class MethodValidationInterceptor implements MethodInterceptor {
|
||||
|
||||
private final MethodValidator validator;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new MethodValidationInterceptor using a default JSR-303 validator underneath.
|
||||
*/
|
||||
public MethodValidationInterceptor() {
|
||||
this(Validation.byProvider(HibernateValidator.class).configure().buildValidatorFactory());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new MethodValidationInterceptor using the given JSR-303 ValidatorFactory.
|
||||
* @param validatorFactory the JSR-303 ValidatorFactory to use
|
||||
*/
|
||||
public MethodValidationInterceptor(ValidatorFactory validatorFactory) {
|
||||
this(validatorFactory.getValidator());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new MethodValidationInterceptor using the given JSR-303 Validator.
|
||||
* @param validatorFactory the JSR-303 Validator to use
|
||||
*/
|
||||
public MethodValidationInterceptor(Validator validator) {
|
||||
this.validator = validator.unwrap(MethodValidator.class);
|
||||
}
|
||||
|
||||
|
||||
public Object invoke(MethodInvocation invocation) throws Throwable {
|
||||
Class[] groups = determineValidationGroups(invocation);
|
||||
Set<MethodConstraintViolation<Object>> result = this.validator.validateAllParameters(
|
||||
invocation.getThis(), invocation.getMethod(), invocation.getArguments(), groups);
|
||||
if (!result.isEmpty()) {
|
||||
throw new MethodConstraintViolationException(result);
|
||||
}
|
||||
Object returnValue = invocation.proceed();
|
||||
result = this.validator.validateReturnValue(
|
||||
invocation.getThis(), invocation.getMethod(), returnValue, groups);
|
||||
if (!result.isEmpty()) {
|
||||
throw new MethodConstraintViolationException(result);
|
||||
}
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the validation groups to validate against for the given method invocation.
|
||||
* <p>Default are the validation groups as specified in the {@link Validated} annotation
|
||||
* on the containing target class of the method.
|
||||
* @param invocation the current MethodInvocation
|
||||
* @return the applicable validation groups as a Class array
|
||||
*/
|
||||
protected Class[] determineValidationGroups(MethodInvocation invocation) {
|
||||
Validated valid = AnnotationUtils.findAnnotation(invocation.getThis().getClass(), Validated.class);
|
||||
return (valid != null ? valid.value() : new Class[0]);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,158 @@
|
|||
/*
|
||||
* 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.beanvalidation;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import javax.validation.Validator;
|
||||
import javax.validation.ValidatorFactory;
|
||||
|
||||
import org.aopalliance.aop.Advice;
|
||||
|
||||
import org.springframework.aop.Advisor;
|
||||
import org.springframework.aop.Pointcut;
|
||||
import org.springframework.aop.framework.Advised;
|
||||
import org.springframework.aop.framework.AopInfrastructureBean;
|
||||
import org.springframework.aop.framework.ProxyConfig;
|
||||
import org.springframework.aop.framework.ProxyFactory;
|
||||
import org.springframework.aop.support.AopUtils;
|
||||
import org.springframework.aop.support.DefaultPointcutAdvisor;
|
||||
import org.springframework.aop.support.annotation.AnnotationMatchingPointcut;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanClassLoaderAware;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
/**
|
||||
* A convenient {@link BeanPostProcessor} implementation that delegates to a
|
||||
* JSR-303 provider for performing method-level validation on annotated methods.
|
||||
*
|
||||
* <p>Applicable methods have JSR-303 constraint annotations on their parameters
|
||||
* and/or on their return value (in the latter case specified at the method level,
|
||||
* typically as inline annotation).
|
||||
*
|
||||
* <p>E.g.: <code>public @NotNull Object myValidMethod(@NotNull String arg1, @Max(10) int arg2)</code>
|
||||
*
|
||||
* <p>Target classes with such annotated methods need to be annotated with Spring's
|
||||
* {@link Validated} annotation at the type level, for their methods to be searched for
|
||||
* inline constraint annotations. Validation groups can be specified through {@link Validated}
|
||||
* as well. By default, JSR-303 will validate against its default group only.
|
||||
*
|
||||
* <p>As of Spring 3.1, this functionality requires Hibernate Validator 4.2 or higher.
|
||||
* In Spring 3.2, this class will autodetect a Bean Validation 1.1 compliant provider
|
||||
* and automatically use the standard method validation support there (once available).
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.1
|
||||
* @see MethodValidationInterceptor
|
||||
* @see org.hibernate.validator.method.MethodValidator
|
||||
*/
|
||||
public class MethodValidationPostProcessor extends ProxyConfig
|
||||
implements BeanPostProcessor, BeanClassLoaderAware, Ordered, InitializingBean {
|
||||
|
||||
private Class<? extends Annotation> validatedAnnotationType = Validated.class;
|
||||
|
||||
private Validator validator;
|
||||
|
||||
private ClassLoader beanClassLoader = ClassUtils.getDefaultClassLoader();
|
||||
|
||||
private Advisor advisor;
|
||||
|
||||
|
||||
/**
|
||||
* Set the 'validated' annotation type.
|
||||
* The default validated annotation type is the {@link Validated} annotation.
|
||||
* <p>This setter property exists so that developers can provide their own
|
||||
* (non-Spring-specific) annotation type to indicate that a class is supposed
|
||||
* to be validated in the sense of applying method validation.
|
||||
* @param validatedAnnotationType the desired annotation type
|
||||
*/
|
||||
public void setValidatedAnnotationType(Class<? extends Annotation> validatedAnnotationType) {
|
||||
Assert.notNull(validatedAnnotationType, "'validatedAnnotationType' must not be null");
|
||||
this.validatedAnnotationType = validatedAnnotationType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the JSR-303 Validator to delegate to for validating methods.
|
||||
* <p>Default is the default ValidatorFactory's default Validator.
|
||||
*/
|
||||
public void setValidator(Validator validator) {
|
||||
this.validator = validator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the JSR-303 ValidatorFactory to delegate to for validating methods,
|
||||
* using its default Validator.
|
||||
* <p>Default is the default ValidatorFactory's default Validator.
|
||||
* @see javax.validation.ValidatorFactory#getValidator()
|
||||
*/
|
||||
public void setValidatorFactory(ValidatorFactory validatorFactory) {
|
||||
this.validator = validatorFactory.getValidator();
|
||||
}
|
||||
|
||||
public void setBeanClassLoader(ClassLoader classLoader) {
|
||||
this.beanClassLoader = classLoader;
|
||||
}
|
||||
|
||||
public int getOrder() {
|
||||
// This should run after all other post-processors, so that it can just add
|
||||
// an advisor to existing proxies rather than double-proxy.
|
||||
return LOWEST_PRECEDENCE;
|
||||
}
|
||||
|
||||
|
||||
public void afterPropertiesSet() {
|
||||
Pointcut pointcut = new AnnotationMatchingPointcut(this.validatedAnnotationType, true);
|
||||
Advice advice = (this.validator != null ? new MethodValidationInterceptor(this.validator) :
|
||||
new MethodValidationInterceptor());
|
||||
this.advisor = new DefaultPointcutAdvisor(pointcut, advice);
|
||||
}
|
||||
|
||||
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||
return bean;
|
||||
}
|
||||
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
||||
if (bean instanceof AopInfrastructureBean) {
|
||||
// Ignore AOP infrastructure such as scoped proxies.
|
||||
return bean;
|
||||
}
|
||||
Class<?> targetClass = AopUtils.getTargetClass(bean);
|
||||
if (AopUtils.canApply(this.advisor, targetClass)) {
|
||||
if (bean instanceof Advised) {
|
||||
((Advised) bean).addAdvisor(this.advisor);
|
||||
return bean;
|
||||
}
|
||||
else {
|
||||
ProxyFactory proxyFactory = new ProxyFactory(bean);
|
||||
// Copy our properties (proxyTargetClass etc) inherited from ProxyConfig.
|
||||
proxyFactory.copyFrom(this);
|
||||
proxyFactory.addAdvisor(this.advisor);
|
||||
return proxyFactory.getProxy(this.beanClassLoader);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// This is not a repository.
|
||||
return bean;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -89,7 +89,7 @@ public class SpringValidatorAdapter implements SmartValidator, javax.validation.
|
|||
processConstraintViolations(this.targetValidator.validate(target), errors);
|
||||
}
|
||||
|
||||
public void validate(Object target, Errors errors, Object[] validationHints) {
|
||||
public void validate(Object target, Errors errors, Object... validationHints) {
|
||||
Set<Class> groups = new LinkedHashSet<Class>();
|
||||
if (validationHints != null) {
|
||||
for (Object hint : validationHints) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
* 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.beanvalidation;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import javax.validation.constraints.Max;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.groups.Default;
|
||||
|
||||
import org.hibernate.validator.method.MethodConstraintViolationException;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.aop.framework.ProxyFactory;
|
||||
import org.springframework.context.support.StaticApplicationContext;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.1
|
||||
*/
|
||||
public class MethodValidationTests {
|
||||
|
||||
@Test
|
||||
public void testMethodValidationInterceptor() {
|
||||
MyValidBean bean = new MyValidBean();
|
||||
ProxyFactory proxyFactory = new ProxyFactory(bean);
|
||||
proxyFactory.addAdvice(new MethodValidationInterceptor());
|
||||
doTestProxyValidation((MyValidInterface) proxyFactory.getProxy());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMethodValidationPostProcessor() {
|
||||
StaticApplicationContext ac = new StaticApplicationContext();
|
||||
ac.registerSingleton("mvpp", MethodValidationPostProcessor.class);
|
||||
ac.registerSingleton("bean", MyValidBean.class);
|
||||
ac.refresh();
|
||||
doTestProxyValidation(ac.getBean("bean", MyValidInterface.class));
|
||||
}
|
||||
|
||||
|
||||
private void doTestProxyValidation(MyValidInterface proxy) {
|
||||
assertNotNull(proxy.myValidMethod("value", 5));
|
||||
try {
|
||||
assertNotNull(proxy.myValidMethod("value", 15));
|
||||
fail("Should have thrown MethodConstraintViolationException");
|
||||
}
|
||||
catch (MethodConstraintViolationException ex) {
|
||||
// expected
|
||||
}
|
||||
try {
|
||||
assertNotNull(proxy.myValidMethod(null, 5));
|
||||
fail("Should have thrown MethodConstraintViolationException");
|
||||
}
|
||||
catch (MethodConstraintViolationException ex) {
|
||||
// expected
|
||||
}
|
||||
try {
|
||||
assertNotNull(proxy.myValidMethod("value", 0));
|
||||
fail("Should have thrown MethodConstraintViolationException");
|
||||
}
|
||||
catch (MethodConstraintViolationException ex) {
|
||||
// expected
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@MyStereotype
|
||||
public static class MyValidBean implements MyValidInterface {
|
||||
|
||||
public Object myValidMethod(String arg1, int arg2) {
|
||||
return (arg2 == 0 ? null : "value");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public interface MyValidInterface {
|
||||
|
||||
@NotNull Object myValidMethod(@NotNull(groups = MyGroup.class) String arg1, @Max(10) int arg2);
|
||||
}
|
||||
|
||||
|
||||
public interface MyGroup {
|
||||
}
|
||||
|
||||
|
||||
@Validated({MyGroup.class, Default.class})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface MyStereotype {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -138,7 +138,7 @@ public class RequestPartMethodArgumentResolver extends AbstractMessageConverterM
|
|||
if (arg != null) {
|
||||
Annotation[] annotations = parameter.getParameterAnnotations();
|
||||
for (Annotation annot : annotations) {
|
||||
if ("Valid".equals(annot.annotationType().getSimpleName())) {
|
||||
if (annot.annotationType().getSimpleName().startsWith("Valid")) {
|
||||
WebDataBinder binder = binderFactory.createBinder(request, arg, partName);
|
||||
Object hints = AnnotationUtils.getValue(annot);
|
||||
binder.validate(hints instanceof Object[] ? (Object[]) hints : new Object[] {hints});
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ public class RequestResponseBodyMethodProcessor extends AbstractMessageConverter
|
|||
Object arg = readWithMessageConverters(webRequest, parameter, parameter.getParameterType());
|
||||
Annotation[] annotations = parameter.getParameterAnnotations();
|
||||
for (Annotation annot : annotations) {
|
||||
if ("Valid".equals(annot.annotationType().getSimpleName())) {
|
||||
if (annot.annotationType().getSimpleName().startsWith("Valid")) {
|
||||
String name = Conventions.getVariableNameForParameter(parameter);
|
||||
WebDataBinder binder = binderFactory.createBinder(webRequest, arg, name);
|
||||
Object hints = AnnotationUtils.getValue(annot);
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ import org.springframework.stereotype.Controller;
|
|||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.validation.Errors;
|
||||
import org.springframework.validation.Validator;
|
||||
import org.springframework.validation.annotation.Valid;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
|
@ -450,7 +450,7 @@ public class MvcNamespaceTests {
|
|||
private boolean recordedValidationError;
|
||||
|
||||
@RequestMapping
|
||||
public void testBind(@RequestParam @DateTimeFormat(iso=ISO.DATE) Date date, @Valid(MyGroup.class) TestBean bean, BindingResult result) {
|
||||
public void testBind(@RequestParam @DateTimeFormat(iso=ISO.DATE) Date date, @Validated(MyGroup.class) TestBean bean, BindingResult result) {
|
||||
this.recordedValidationError = (result.getErrorCount() == 1);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ import org.springframework.util.StringUtils;
|
|||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.validation.Errors;
|
||||
import org.springframework.validation.FieldError;
|
||||
import org.springframework.validation.annotation.Valid;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
|
||||
import org.springframework.web.bind.WebDataBinder;
|
||||
import org.springframework.web.bind.annotation.CookieValue;
|
||||
|
|
@ -2325,7 +2325,7 @@ public class ServletAnnotationControllerTests {
|
|||
|
||||
@Override
|
||||
@RequestMapping("/myPath.do")
|
||||
public String myHandle(@ModelAttribute("myCommand") @Valid(MyGroup.class) TestBean tb, BindingResult errors, ModelMap model) {
|
||||
public String myHandle(@ModelAttribute("myCommand") @Validated(MyGroup.class) TestBean tb, BindingResult errors, ModelMap model) {
|
||||
if (!errors.hasFieldErrors("validCountry")) {
|
||||
throw new IllegalStateException("Declarative validation not applied");
|
||||
}
|
||||
|
|
@ -2383,7 +2383,7 @@ public class ServletAnnotationControllerTests {
|
|||
|
||||
@Override
|
||||
@RequestMapping("/myPath.do")
|
||||
public String myHandle(@ModelAttribute("myCommand") @Valid(MyGroup.class) TestBean tb, BindingResult errors, ModelMap model) {
|
||||
public String myHandle(@ModelAttribute("myCommand") @Validated(MyGroup.class) TestBean tb, BindingResult errors, ModelMap model) {
|
||||
if (!errors.hasFieldErrors("sex")) {
|
||||
throw new IllegalStateException("requiredFields not applied");
|
||||
}
|
||||
|
|
@ -2410,8 +2410,7 @@ public class ServletAnnotationControllerTests {
|
|||
}
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface MyGroup {
|
||||
public interface MyGroup {
|
||||
}
|
||||
|
||||
private static class MyWebBindingInitializer implements WebBindingInitializer {
|
||||
|
|
|
|||
|
|
@ -295,7 +295,7 @@ public class HandlerMethodInvoker {
|
|||
else if (Value.class.isInstance(paramAnn)) {
|
||||
defaultValue = ((Value) paramAnn).value();
|
||||
}
|
||||
else if ("Valid".equals(paramAnn.annotationType().getSimpleName())) {
|
||||
else if (paramAnn.annotationType().getSimpleName().startsWith("Valid")) {
|
||||
validate = true;
|
||||
Object value = AnnotationUtils.getValue(paramAnn);
|
||||
validationHints = (value instanceof Object[] ? (Object[]) value : new Object[] {value});
|
||||
|
|
|
|||
|
|
@ -149,7 +149,7 @@ public class ModelAttributeMethodProcessor implements HandlerMethodArgumentResol
|
|||
protected void validateIfApplicable(WebDataBinder binder, MethodParameter parameter) {
|
||||
Annotation[] annotations = parameter.getParameterAnnotations();
|
||||
for (Annotation annot : annotations) {
|
||||
if ("Valid".equals(annot.annotationType().getSimpleName())) {
|
||||
if (annot.annotationType().getSimpleName().startsWith("Valid")) {
|
||||
Object hints = AnnotationUtils.getValue(annot);
|
||||
binder.validate(hints instanceof Object[] ? (Object[]) hints : new Object[] {hints});
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue