001/* 002 * Copyright 2002-2017 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.validation.beanvalidation; 018 019import java.lang.annotation.Annotation; 020import javax.validation.Validator; 021import javax.validation.ValidatorFactory; 022 023import org.aopalliance.aop.Advice; 024 025import org.springframework.aop.Pointcut; 026import org.springframework.aop.framework.autoproxy.AbstractBeanFactoryAwareAdvisingPostProcessor; 027import org.springframework.aop.support.DefaultPointcutAdvisor; 028import org.springframework.aop.support.annotation.AnnotationMatchingPointcut; 029import org.springframework.beans.factory.InitializingBean; 030import org.springframework.beans.factory.config.BeanPostProcessor; 031import org.springframework.util.Assert; 032import org.springframework.validation.annotation.Validated; 033 034/** 035 * A convenient {@link BeanPostProcessor} implementation that delegates to a 036 * JSR-303 provider for performing method-level validation on annotated methods. 037 * 038 * <p>Applicable methods have JSR-303 constraint annotations on their parameters 039 * and/or on their return value (in the latter case specified at the method level, 040 * typically as inline annotation), e.g.: 041 * 042 * <pre class="code"> 043 * public @NotNull Object myValidMethod(@NotNull String arg1, @Max(10) int arg2) 044 * </pre> 045 * 046 * <p>Target classes with such annotated methods need to be annotated with Spring's 047 * {@link Validated} annotation at the type level, for their methods to be searched for 048 * inline constraint annotations. Validation groups can be specified through {@code @Validated} 049 * as well. By default, JSR-303 will validate against its default group only. 050 * 051 * <p>As of Spring 4.0, this functionality requires either a Bean Validation 1.1 provider 052 * (such as Hibernate Validator 5.x) or the Bean Validation 1.0 API with Hibernate Validator 053 * 4.3. The actual provider will be autodetected and automatically adapted. 054 * 055 * @author Juergen Hoeller 056 * @since 3.1 057 * @see MethodValidationInterceptor 058 * @see javax.validation.executable.ExecutableValidator 059 * @see org.hibernate.validator.method.MethodValidator 060 */ 061@SuppressWarnings("serial") 062public class MethodValidationPostProcessor extends AbstractBeanFactoryAwareAdvisingPostProcessor 063 implements InitializingBean { 064 065 private Class<? extends Annotation> validatedAnnotationType = Validated.class; 066 067 private Validator validator; 068 069 070 /** 071 * Set the 'validated' annotation type. 072 * The default validated annotation type is the {@link Validated} annotation. 073 * <p>This setter property exists so that developers can provide their own 074 * (non-Spring-specific) annotation type to indicate that a class is supposed 075 * to be validated in the sense of applying method validation. 076 * @param validatedAnnotationType the desired annotation type 077 */ 078 public void setValidatedAnnotationType(Class<? extends Annotation> validatedAnnotationType) { 079 Assert.notNull(validatedAnnotationType, "'validatedAnnotationType' must not be null"); 080 this.validatedAnnotationType = validatedAnnotationType; 081 } 082 083 /** 084 * Set the JSR-303 Validator to delegate to for validating methods. 085 * <p>Default is the default ValidatorFactory's default Validator. 086 */ 087 public void setValidator(Validator validator) { 088 // Unwrap to the native Validator with forExecutables support 089 if (validator instanceof LocalValidatorFactoryBean) { 090 this.validator = ((LocalValidatorFactoryBean) validator).getValidator(); 091 } 092 else if (validator instanceof SpringValidatorAdapter) { 093 this.validator = validator.unwrap(Validator.class); 094 } 095 else { 096 this.validator = validator; 097 } 098 } 099 100 /** 101 * Set the JSR-303 ValidatorFactory to delegate to for validating methods, 102 * using its default Validator. 103 * <p>Default is the default ValidatorFactory's default Validator. 104 * @see javax.validation.ValidatorFactory#getValidator() 105 */ 106 public void setValidatorFactory(ValidatorFactory validatorFactory) { 107 this.validator = validatorFactory.getValidator(); 108 } 109 110 111 @Override 112 public void afterPropertiesSet() { 113 Pointcut pointcut = new AnnotationMatchingPointcut(this.validatedAnnotationType, true); 114 this.advisor = new DefaultPointcutAdvisor(pointcut, createMethodValidationAdvice(this.validator)); 115 } 116 117 /** 118 * Create AOP advice for method validation purposes, to be applied 119 * with a pointcut for the specified 'validated' annotation. 120 * @param validator the JSR-303 Validator to delegate to 121 * @return the interceptor to use (typically, but not necessarily, 122 * a {@link MethodValidationInterceptor} or subclass thereof) 123 * @since 4.2 124 */ 125 protected Advice createMethodValidationAdvice(Validator validator) { 126 return (validator != null ? new MethodValidationInterceptor(validator) : new MethodValidationInterceptor()); 127 } 128 129}