Fixed detection of generic types and qualifier annotations on scoped-proxy factory methods
Issue: SPR-11116
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user