BeanValidationPostProcessor runs in before-initialization phase by default (SPR-6565)
This commit is contained in:
parent
943c46b07d
commit
d6f4f4c7b4
|
|
@ -29,33 +29,77 @@ import org.springframework.beans.factory.InitializingBean;
|
||||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Simple {@link BeanPostProcessor} that checks JSR-303 constraint annotations
|
||||||
|
* in Spring-managed beans, throwing an initialization exception in case of
|
||||||
|
* constraint violations right before calling the bean's init method (if any).
|
||||||
|
*
|
||||||
* @author Juergen Hoeller
|
* @author Juergen Hoeller
|
||||||
* @since 3.0
|
* @since 3.0
|
||||||
*/
|
*/
|
||||||
public class BeanValidationPostProcessor implements BeanPostProcessor, InitializingBean {
|
public class BeanValidationPostProcessor implements BeanPostProcessor, InitializingBean {
|
||||||
|
|
||||||
private javax.validation.Validator validator;
|
private Validator validator;
|
||||||
|
|
||||||
|
private boolean afterInitialization = false;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the JSR-303 Validator to delegate to for validating beans.
|
||||||
|
* <p>Default is the default ValidatorFactory's default Validator.
|
||||||
|
*/
|
||||||
public void setValidator(Validator validator) {
|
public void setValidator(Validator validator) {
|
||||||
this.validator = validator;
|
this.validator = validator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the JSR-303 ValidatorFactory to delegate to for validating beans,
|
||||||
|
* using its default Validator.
|
||||||
|
* <p>Default is the default ValidatorFactory's default Validator.
|
||||||
|
* @see javax.validation.ValidatorFactory#getValidator()
|
||||||
|
*/
|
||||||
public void setValidatorFactory(ValidatorFactory validatorFactory) {
|
public void setValidatorFactory(ValidatorFactory validatorFactory) {
|
||||||
this.validator = validatorFactory.getValidator();
|
this.validator = validatorFactory.getValidator();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Choose whether to perform validation after bean initialization
|
||||||
|
* (i.e. after init methods) instead of before (which is the default).
|
||||||
|
* <p>Default is "false" (before initialization). Switch this to "true"
|
||||||
|
* (after initialization) if you would like to give init methods a chance
|
||||||
|
* to populate constrained fields before they get validated.
|
||||||
|
*/
|
||||||
|
public void setAfterInitialization(boolean afterInitialization) {
|
||||||
|
this.afterInitialization = afterInitialization;
|
||||||
|
}
|
||||||
|
|
||||||
public void afterPropertiesSet() {
|
public void afterPropertiesSet() {
|
||||||
if (this.validator == null) {
|
if (this.validator == null) {
|
||||||
Validation.buildDefaultValidatorFactory().getValidator();
|
this.validator = Validation.buildDefaultValidatorFactory().getValidator();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||||
|
if (!this.afterInitialization) {
|
||||||
|
doValidate(bean);
|
||||||
|
}
|
||||||
return bean;
|
return bean;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
||||||
|
if (this.afterInitialization) {
|
||||||
|
doValidate(bean);
|
||||||
|
}
|
||||||
|
return bean;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform validation of the given bean.
|
||||||
|
* @param bean the bean instance to validate
|
||||||
|
* @see javax.validation.Validator#validate
|
||||||
|
*/
|
||||||
|
protected void doValidate(Object bean) {
|
||||||
Set<ConstraintViolation<Object>> result = this.validator.validate(bean);
|
Set<ConstraintViolation<Object>> result = this.validator.validate(bean);
|
||||||
if (!result.isEmpty()) {
|
if (!result.isEmpty()) {
|
||||||
StringBuilder sb = new StringBuilder("Bean state is invalid: ");
|
StringBuilder sb = new StringBuilder("Bean state is invalid: ");
|
||||||
|
|
@ -68,7 +112,6 @@ public class BeanValidationPostProcessor implements BeanPostProcessor, Initializ
|
||||||
}
|
}
|
||||||
throw new BeanInitializationException(sb.toString());
|
throw new BeanInitializationException(sb.toString());
|
||||||
}
|
}
|
||||||
return bean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,156 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2002-2009 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 javax.annotation.PostConstruct;
|
||||||
|
import javax.validation.constraints.NotNull;
|
||||||
|
import javax.validation.constraints.Size;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import org.springframework.beans.TestBean;
|
||||||
|
import org.springframework.beans.factory.BeanCreationException;
|
||||||
|
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||||
|
import org.springframework.context.annotation.CommonAnnotationBeanPostProcessor;
|
||||||
|
import org.springframework.context.support.GenericApplicationContext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Juergen Hoeller
|
||||||
|
* @since 3.0
|
||||||
|
*/
|
||||||
|
public class BeanValidationPostProcessorTests {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNotNullConstraint() {
|
||||||
|
GenericApplicationContext ac = new GenericApplicationContext();
|
||||||
|
ac.registerBeanDefinition("bvpp", new RootBeanDefinition(BeanValidationPostProcessor.class));
|
||||||
|
ac.registerBeanDefinition("capp", new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class));
|
||||||
|
ac.registerBeanDefinition("bean", new RootBeanDefinition(NotNullConstrainedBean.class));
|
||||||
|
try {
|
||||||
|
ac.refresh();
|
||||||
|
fail("Should have thrown BeanCreationException");
|
||||||
|
}
|
||||||
|
catch (BeanCreationException ex) {
|
||||||
|
assertTrue(ex.getRootCause().getMessage().contains("testBean"));
|
||||||
|
assertTrue(ex.getRootCause().getMessage().contains("invalid"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNotNullConstraintSatisfied() {
|
||||||
|
GenericApplicationContext ac = new GenericApplicationContext();
|
||||||
|
ac.registerBeanDefinition("bvpp", new RootBeanDefinition(BeanValidationPostProcessor.class));
|
||||||
|
ac.registerBeanDefinition("capp", new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class));
|
||||||
|
RootBeanDefinition bd = new RootBeanDefinition(NotNullConstrainedBean.class);
|
||||||
|
bd.getPropertyValues().add("testBean", new TestBean());
|
||||||
|
ac.registerBeanDefinition("bean", bd);
|
||||||
|
ac.refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNotNullConstraintAfterInitialization() {
|
||||||
|
GenericApplicationContext ac = new GenericApplicationContext();
|
||||||
|
RootBeanDefinition bvpp = new RootBeanDefinition(BeanValidationPostProcessor.class);
|
||||||
|
bvpp.getPropertyValues().add("afterInitialization", true);
|
||||||
|
ac.registerBeanDefinition("bvpp", bvpp);
|
||||||
|
ac.registerBeanDefinition("capp", new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class));
|
||||||
|
ac.registerBeanDefinition("bean", new RootBeanDefinition(AfterInitConstraintBean.class));
|
||||||
|
ac.refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSizeConstraint() {
|
||||||
|
GenericApplicationContext ac = new GenericApplicationContext();
|
||||||
|
ac.registerBeanDefinition("bvpp", new RootBeanDefinition(BeanValidationPostProcessor.class));
|
||||||
|
RootBeanDefinition bd = new RootBeanDefinition(NotNullConstrainedBean.class);
|
||||||
|
bd.getPropertyValues().add("testBean", new TestBean());
|
||||||
|
bd.getPropertyValues().add("stringValue", "s");
|
||||||
|
ac.registerBeanDefinition("bean", bd);
|
||||||
|
try {
|
||||||
|
ac.refresh();
|
||||||
|
fail("Should have thrown BeanCreationException");
|
||||||
|
}
|
||||||
|
catch (BeanCreationException ex) {
|
||||||
|
assertTrue(ex.getRootCause().getMessage().contains("stringValue"));
|
||||||
|
assertTrue(ex.getRootCause().getMessage().contains("invalid"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSizeConstraintSatisfied() {
|
||||||
|
GenericApplicationContext ac = new GenericApplicationContext();
|
||||||
|
ac.registerBeanDefinition("bvpp", new RootBeanDefinition(BeanValidationPostProcessor.class));
|
||||||
|
RootBeanDefinition bd = new RootBeanDefinition(NotNullConstrainedBean.class);
|
||||||
|
bd.getPropertyValues().add("testBean", new TestBean());
|
||||||
|
bd.getPropertyValues().add("stringValue", "ss");
|
||||||
|
ac.registerBeanDefinition("bean", bd);
|
||||||
|
ac.refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static class NotNullConstrainedBean {
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private TestBean testBean;
|
||||||
|
|
||||||
|
@Size(min = 2)
|
||||||
|
private String stringValue;
|
||||||
|
|
||||||
|
public TestBean getTestBean() {
|
||||||
|
return testBean;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTestBean(TestBean testBean) {
|
||||||
|
this.testBean = testBean;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getStringValue() {
|
||||||
|
return stringValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setStringValue(String stringValue) {
|
||||||
|
this.stringValue = stringValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
public void init() {
|
||||||
|
assertNotNull("Shouldn't be here after constraint checking", this.testBean);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static class AfterInitConstraintBean {
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private TestBean testBean;
|
||||||
|
|
||||||
|
public TestBean getTestBean() {
|
||||||
|
return testBean;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTestBean(TestBean testBean) {
|
||||||
|
this.testBean = testBean;
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
public void init() {
|
||||||
|
this.testBean = new TestBean();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue