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;
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @since 3.0
|
||||
*/
|
||||
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) {
|
||||
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) {
|
||||
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() {
|
||||
if (this.validator == null) {
|
||||
Validation.buildDefaultValidatorFactory().getValidator();
|
||||
this.validator = Validation.buildDefaultValidatorFactory().getValidator();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||
if (!this.afterInitialization) {
|
||||
doValidate(bean);
|
||||
}
|
||||
return bean;
|
||||
}
|
||||
|
||||
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);
|
||||
if (!result.isEmpty()) {
|
||||
StringBuilder sb = new StringBuilder("Bean state is invalid: ");
|
||||
|
|
@ -68,7 +112,6 @@ public class BeanValidationPostProcessor implements BeanPostProcessor, Initializ
|
|||
}
|
||||
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