diff --git a/org.springframework.context/src/main/java/org/springframework/validation/annotation/Valid.java b/org.springframework.context/src/main/java/org/springframework/validation/annotation/Validated.java similarity index 72% rename from org.springframework.context/src/main/java/org/springframework/validation/annotation/Valid.java rename to org.springframework.context/src/main/java/org/springframework/validation/annotation/Validated.java index b7807ab912b..70da20211f5 100644 --- a/org.springframework.context/src/main/java/org/springframework/validation/annotation/Valid.java +++ b/org.springframework.context/src/main/java/org/springframework/validation/annotation/Validated.java @@ -1,56 +1,63 @@ -/* - * 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. - * - *
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. - *
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}. - *
Other {@link org.springframework.validation.SmartValidator} implementations may - * support class arguments in other ways as well. - */ - Class[] value() default {}; - -} +/* + * 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; + +/** + * 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. + * + *
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. + * + *
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.TYPE, ElementType.PARAMETER}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface Validated { + + /** + * Specify one or more validation groups to apply to the validation step + * kicked off by this annotation. + *
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}. + *
Other {@link org.springframework.validation.SmartValidator} implementations may + * support class arguments in other ways as well. + */ + Class[] value() default {}; + +} diff --git a/org.springframework.context/src/main/java/org/springframework/validation/beanvalidation/MethodValidationInterceptor.java b/org.springframework.context/src/main/java/org/springframework/validation/beanvalidation/MethodValidationInterceptor.java new file mode 100644 index 00000000000..b3e087c83b6 --- /dev/null +++ b/org.springframework.context/src/main/java/org/springframework/validation/beanvalidation/MethodValidationInterceptor.java @@ -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. + * + *
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). + * + *
E.g.: public @NotNull Object myValidMethod(@NotNull String arg1, @Max(10) int arg2)
+ *
+ *
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. + * + *
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 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]);
+ }
+
+}
diff --git a/org.springframework.context/src/main/java/org/springframework/validation/beanvalidation/MethodValidationPostProcessor.java b/org.springframework.context/src/main/java/org/springframework/validation/beanvalidation/MethodValidationPostProcessor.java
new file mode 100644
index 00000000000..3ccf295ad48
--- /dev/null
+++ b/org.springframework.context/src/main/java/org/springframework/validation/beanvalidation/MethodValidationPostProcessor.java
@@ -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.
+ *
+ * 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).
+ *
+ * E.g.: 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.
+ *
+ * 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.
+ * 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.
+ * 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.
+ * 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;
+ }
+ }
+
+}
diff --git a/org.springframework.context/src/main/java/org/springframework/validation/beanvalidation/SpringValidatorAdapter.java b/org.springframework.context/src/main/java/org/springframework/validation/beanvalidation/SpringValidatorAdapter.java
index 7901a0d1db3..08ef9b89bde 100644
--- a/org.springframework.context/src/main/java/org/springframework/validation/beanvalidation/SpringValidatorAdapter.java
+++ b/org.springframework.context/src/main/java/org/springframework/validation/beanvalidation/SpringValidatorAdapter.java
@@ -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) {
Setpublic @NotNull Object myValidMethod(@NotNull String arg1, @Max(10) int arg2)
+ *
+ *