Fixed detection of generic types and qualifier annotations on scoped-proxy factory methods

Issue: SPR-11116
This commit is contained in:
Juergen Hoeller
2013-12-08 23:24:16 +01:00
parent 1f9b833c4d
commit 8580d2d19e
5 changed files with 216 additions and 36 deletions

View File

@@ -216,18 +216,22 @@ public class QualifierAnnotationAutowireCandidateResolver extends GenericTypeAwa
Class<? extends Annotation> type = annotation.annotationType();
RootBeanDefinition bd = (RootBeanDefinition) bdHolder.getBeanDefinition();
AutowireCandidateQualifier qualifier = bd.getQualifier(type.getName());
if (qualifier == null) {
qualifier = bd.getQualifier(ClassUtils.getShortName(type));
}
if (qualifier == null) {
Annotation targetAnnotation = null;
Method resolvedFactoryMethod = bd.getResolvedFactoryMethod();
if (resolvedFactoryMethod != null) {
targetAnnotation = AnnotationUtils.getAnnotation(resolvedFactoryMethod, type);
// First, check annotation on factory method, if applicable
Annotation targetAnnotation = getFactoryMethodAnnotation(bd, type);
if (targetAnnotation == null) {
RootBeanDefinition dbd = getResolvedDecoratedDefinition(bd);
if (dbd != null) {
targetAnnotation = getFactoryMethodAnnotation(dbd, type);
}
}
if (targetAnnotation == null) {
// look for matching annotation on the target class
// Look for matching annotation on the target class
if (getBeanFactory() != null) {
Class<?> beanType = getBeanFactory().getType(bdHolder.getBeanName());
if (beanType != null) {
@@ -242,30 +246,31 @@ public class QualifierAnnotationAutowireCandidateResolver extends GenericTypeAwa
return true;
}
}
Map<String, Object> attributes = AnnotationUtils.getAnnotationAttributes(annotation);
if (attributes.isEmpty() && qualifier == null) {
// if no attributes, the qualifier must be present
// If no attributes, the qualifier must be present
return false;
}
for (Map.Entry<String, Object> entry : attributes.entrySet()) {
String attributeName = entry.getKey();
Object expectedValue = entry.getValue();
Object actualValue = null;
// check qualifier first
// Check qualifier first
if (qualifier != null) {
actualValue = qualifier.getAttribute(attributeName);
}
if (actualValue == null) {
// fall back on bean definition attribute
// Fall back on bean definition attribute
actualValue = bd.getAttribute(attributeName);
}
if (actualValue == null && attributeName.equals(AutowireCandidateQualifier.VALUE_KEY) &&
expectedValue instanceof String && bdHolder.matchesName((String) expectedValue)) {
// fall back on bean name (or alias) match
// Fall back on bean name (or alias) match
continue;
}
if (actualValue == null && qualifier != null) {
// fall back on default, but only if the qualifier is present
// Fall back on default, but only if the qualifier is present
actualValue = AnnotationUtils.getDefaultValue(annotation, attributeName);
}
if (actualValue != null) {
@@ -278,6 +283,11 @@ public class QualifierAnnotationAutowireCandidateResolver extends GenericTypeAwa
return true;
}
protected Annotation getFactoryMethodAnnotation(RootBeanDefinition bd, Class<? extends Annotation> type) {
Method resolvedFactoryMethod = bd.getResolvedFactoryMethod();
return (resolvedFactoryMethod != null ? AnnotationUtils.getAnnotation(resolvedFactoryMethod, type) : null);
}
/**
* Determine whether the given dependency carries a value annotation.

View File

@@ -21,7 +21,9 @@ import java.lang.reflect.Method;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.DependencyDescriptor;
import org.springframework.core.ResolvableType;
import org.springframework.util.ClassUtils;
@@ -77,22 +79,13 @@ public class GenericTypeAwareAutowireCandidateResolver implements AutowireCandid
if (bdHolder.getBeanDefinition() instanceof RootBeanDefinition) {
rbd = (RootBeanDefinition) bdHolder.getBeanDefinition();
}
if (rbd != null && rbd.getFactoryMethodName() != null) {
// Should typically be set for any kind of factory method, since the BeanFactory
// pre-resolves them before reaching out to the AutowireCandidateResolver...
Class<?> preResolved = rbd.resolvedFactoryMethodReturnType;
if (preResolved != null) {
targetType = ResolvableType.forClass(preResolved);
}
else {
Method resolvedFactoryMethod = rbd.getResolvedFactoryMethod();
if (resolvedFactoryMethod != null) {
if (descriptor.getDependencyType().isAssignableFrom(resolvedFactoryMethod.getReturnType())) {
// Only use factory method metadata if the return type is actually expressive enough
// for our dependency. Otherwise, the returned instance type may have matched instead
// in case of a singleton instance having been registered with the container already.
targetType = ResolvableType.forMethodReturnType(resolvedFactoryMethod);
}
if (rbd != null) {
// First, check factory method return type, if applicable
targetType = getReturnTypeForFactoryMethod(rbd, descriptor);
if (targetType == null) {
RootBeanDefinition dbd = getResolvedDecoratedDefinition(rbd);
if (dbd != null) {
targetType = getReturnTypeForFactoryMethod(dbd, descriptor);
}
}
}
@@ -122,6 +115,41 @@ public class GenericTypeAwareAutowireCandidateResolver implements AutowireCandid
return dependencyType.isAssignableFrom(targetType);
}
protected RootBeanDefinition getResolvedDecoratedDefinition(RootBeanDefinition rbd) {
BeanDefinitionHolder decDef = rbd.getDecoratedDefinition();
if (decDef != null && this.beanFactory instanceof ConfigurableListableBeanFactory) {
ConfigurableListableBeanFactory clbf = (ConfigurableListableBeanFactory) this.beanFactory;
if (clbf.containsBeanDefinition(decDef.getBeanName())) {
BeanDefinition dbd = clbf.getMergedBeanDefinition(decDef.getBeanName());
if (dbd instanceof RootBeanDefinition) {
return (RootBeanDefinition) dbd;
}
}
}
return null;
}
protected ResolvableType getReturnTypeForFactoryMethod(RootBeanDefinition rbd, DependencyDescriptor descriptor) {
// Should typically be set for any kind of factory method, since the BeanFactory
// pre-resolves them before reaching out to the AutowireCandidateResolver...
Class<?> preResolved = rbd.resolvedFactoryMethodReturnType;
if (preResolved != null) {
return ResolvableType.forClass(preResolved);
}
else {
Method resolvedFactoryMethod = rbd.getResolvedFactoryMethod();
if (resolvedFactoryMethod != null) {
if (descriptor.getDependencyType().isAssignableFrom(resolvedFactoryMethod.getReturnType())) {
// Only use factory method metadata if the return type is actually expressive enough
// for our dependency. Otherwise, the returned instance type may have matched instead
// in case of a singleton instance having been registered with the container already.
return ResolvableType.forMethodReturnType(resolvedFactoryMethod);
}
}
return null;
}
}
/**
* This implementation always returns {@code null}, leaving suggested value support up