001/* 002 * Copyright 2002-2012 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.util.Iterator; 020import java.util.Set; 021import javax.validation.ConstraintViolation; 022import javax.validation.Validation; 023import javax.validation.Validator; 024import javax.validation.ValidatorFactory; 025 026import org.springframework.beans.BeansException; 027import org.springframework.beans.factory.BeanInitializationException; 028import org.springframework.beans.factory.InitializingBean; 029import org.springframework.beans.factory.config.BeanPostProcessor; 030 031/** 032 * Simple {@link BeanPostProcessor} that checks JSR-303 constraint annotations 033 * in Spring-managed beans, throwing an initialization exception in case of 034 * constraint violations right before calling the bean's init method (if any). 035 * 036 * @author Juergen Hoeller 037 * @since 3.0 038 */ 039public class BeanValidationPostProcessor implements BeanPostProcessor, InitializingBean { 040 041 private Validator validator; 042 043 private boolean afterInitialization = false; 044 045 046 /** 047 * Set the JSR-303 Validator to delegate to for validating beans. 048 * <p>Default is the default ValidatorFactory's default Validator. 049 */ 050 public void setValidator(Validator validator) { 051 this.validator = validator; 052 } 053 054 /** 055 * Set the JSR-303 ValidatorFactory to delegate to for validating beans, 056 * using its default Validator. 057 * <p>Default is the default ValidatorFactory's default Validator. 058 * @see javax.validation.ValidatorFactory#getValidator() 059 */ 060 public void setValidatorFactory(ValidatorFactory validatorFactory) { 061 this.validator = validatorFactory.getValidator(); 062 } 063 064 /** 065 * Choose whether to perform validation after bean initialization 066 * (i.e. after init methods) instead of before (which is the default). 067 * <p>Default is "false" (before initialization). Switch this to "true" 068 * (after initialization) if you would like to give init methods a chance 069 * to populate constrained fields before they get validated. 070 */ 071 public void setAfterInitialization(boolean afterInitialization) { 072 this.afterInitialization = afterInitialization; 073 } 074 075 @Override 076 public void afterPropertiesSet() { 077 if (this.validator == null) { 078 this.validator = Validation.buildDefaultValidatorFactory().getValidator(); 079 } 080 } 081 082 083 @Override 084 public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { 085 if (!this.afterInitialization) { 086 doValidate(bean); 087 } 088 return bean; 089 } 090 091 @Override 092 public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { 093 if (this.afterInitialization) { 094 doValidate(bean); 095 } 096 return bean; 097 } 098 099 100 /** 101 * Perform validation of the given bean. 102 * @param bean the bean instance to validate 103 * @see javax.validation.Validator#validate 104 */ 105 protected void doValidate(Object bean) { 106 Set<ConstraintViolation<Object>> result = this.validator.validate(bean); 107 if (!result.isEmpty()) { 108 StringBuilder sb = new StringBuilder("Bean state is invalid: "); 109 for (Iterator<ConstraintViolation<Object>> it = result.iterator(); it.hasNext();) { 110 ConstraintViolation<Object> violation = it.next(); 111 sb.append(violation.getPropertyPath()).append(" - ").append(violation.getMessage()); 112 if (it.hasNext()) { 113 sb.append("; "); 114 } 115 } 116 throw new BeanInitializationException(sb.toString()); 117 } 118 } 119 120}