@Required does not get processed on beans returned by @Bean factory methods (SPR-5744)
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
* 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.
|
||||
@@ -27,8 +27,12 @@ import java.util.Set;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.PropertyValues;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.BeanInitializationException;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;
|
||||
import org.springframework.core.Conventions;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.PriorityOrdered;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
@@ -66,12 +70,23 @@ import org.springframework.util.Assert;
|
||||
* @see Required
|
||||
*/
|
||||
public class RequiredAnnotationBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter
|
||||
implements PriorityOrdered {
|
||||
implements PriorityOrdered, BeanFactoryAware {
|
||||
|
||||
/**
|
||||
* Bean definition attribute that may indicate whether a given bean is supposed
|
||||
* to be skipped when performing this post-processor's required property check.
|
||||
* @see #shouldSkip
|
||||
*/
|
||||
public static final String SKIP_REQUIRED_CHECK_ATTRIBUTE =
|
||||
Conventions.getQualifiedAttributeName(RequiredAnnotationBeanPostProcessor.class, "skipRequiredCheck");
|
||||
|
||||
|
||||
private Class<? extends Annotation> requiredAnnotationType = Required.class;
|
||||
|
||||
private int order = Ordered.LOWEST_PRECEDENCE - 1;
|
||||
|
||||
private ConfigurableListableBeanFactory beanFactory;
|
||||
|
||||
/** Cache for validated bean names, skipping re-validation for the same bean */
|
||||
private final Set<String> validatedBeanNames = Collections.synchronizedSet(new HashSet<String>());
|
||||
|
||||
@@ -97,6 +112,12 @@ public class RequiredAnnotationBeanPostProcessor extends InstantiationAwareBeanP
|
||||
return this.requiredAnnotationType;
|
||||
}
|
||||
|
||||
public void setBeanFactory(BeanFactory beanFactory) {
|
||||
if (beanFactory instanceof ConfigurableListableBeanFactory) {
|
||||
this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
|
||||
}
|
||||
}
|
||||
|
||||
public void setOrder(int order) {
|
||||
this.order = order;
|
||||
}
|
||||
@@ -112,20 +133,36 @@ public class RequiredAnnotationBeanPostProcessor extends InstantiationAwareBeanP
|
||||
throws BeansException {
|
||||
|
||||
if (!this.validatedBeanNames.contains(beanName)) {
|
||||
List<String> invalidProperties = new ArrayList<String>();
|
||||
for (PropertyDescriptor pd : pds) {
|
||||
if (isRequiredProperty(pd) && !pvs.contains(pd.getName())) {
|
||||
invalidProperties.add(pd.getName());
|
||||
if (!shouldSkip(this.beanFactory, beanName)) {
|
||||
List<String> invalidProperties = new ArrayList<String>();
|
||||
for (PropertyDescriptor pd : pds) {
|
||||
if (isRequiredProperty(pd) && !pvs.contains(pd.getName())) {
|
||||
invalidProperties.add(pd.getName());
|
||||
}
|
||||
}
|
||||
if (!invalidProperties.isEmpty()) {
|
||||
throw new BeanInitializationException(buildExceptionMessage(invalidProperties, beanName));
|
||||
}
|
||||
}
|
||||
if (!invalidProperties.isEmpty()) {
|
||||
throw new BeanInitializationException(buildExceptionMessage(invalidProperties, beanName));
|
||||
}
|
||||
this.validatedBeanNames.add(beanName);
|
||||
}
|
||||
return pvs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the given bean definition is not subject to the annotation-based
|
||||
* required property check as performed by this post-processor.
|
||||
* <p>The default implementations check for the presence of the
|
||||
* {@link #SKIP_REQUIRED_CHECK_ATTRIBUTE} attribute in the bean definition, if any.
|
||||
* @param beanFactory the BeanFactory to check against
|
||||
* @param beanName the name of the bean to check against
|
||||
* @return <code>true</code> to skip the bean; <code>false</code> to process it
|
||||
*/
|
||||
protected boolean shouldSkip(ConfigurableListableBeanFactory beanFactory, String beanName) {
|
||||
return (beanFactory != null && beanFactory.containsBeanDefinition(beanName) &&
|
||||
Boolean.TRUE.equals(beanFactory.getBeanDefinition(beanName).getAttribute(SKIP_REQUIRED_CHECK_ATTRIBUTE)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the supplied property required to have a value (that is, to be dependency-injected)?
|
||||
* <p>This implementation looks for the existence of a
|
||||
|
||||
Reference in New Issue
Block a user