Skip to content

Commit f2889b1

Browse files
committed
Consistent support for generic FactoryBean type matching
Closes gh-32590 See gh-32489
1 parent 802967f commit f2889b1

File tree

5 files changed

+342
-250
lines changed

5 files changed

+342
-250
lines changed

spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java

+57-26
Original file line numberDiff line numberDiff line change
@@ -525,42 +525,73 @@ protected boolean isTypeMatch(String name, ResolvableType typeToMatch, boolean a
525525
// Check manually registered singletons.
526526
Object beanInstance = getSingleton(beanName, false);
527527
if (beanInstance != null && beanInstance.getClass() != NullBean.class) {
528+
529+
// Determine target for FactoryBean match if necessary.
528530
if (beanInstance instanceof FactoryBean<?> factoryBean) {
529531
if (!isFactoryDereference) {
530532
Class<?> type = getTypeForFactoryBean(factoryBean);
531-
return (type != null && typeToMatch.isAssignableFrom(type));
532-
}
533-
else {
534-
return typeToMatch.isInstance(beanInstance);
535-
}
536-
}
537-
else if (!isFactoryDereference) {
538-
if (typeToMatch.isInstance(beanInstance)) {
539-
// Direct match for exposed instance?
540-
return true;
541-
}
542-
else if (typeToMatch.hasGenerics() && containsBeanDefinition(beanName)) {
543-
// Generics potentially only match on the target class, not on the proxy...
544-
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
545-
Class<?> targetType = mbd.getTargetType();
546-
if (targetType != null && targetType != ClassUtils.getUserClass(beanInstance)) {
547-
// Check raw class match as well, making sure it's exposed on the proxy.
548-
Class<?> classToMatch = typeToMatch.resolve();
549-
if (classToMatch != null && !classToMatch.isInstance(beanInstance)) {
533+
if (type == null) {
534+
return false;
535+
}
536+
if (typeToMatch.isAssignableFrom(type)) {
537+
return true;
538+
}
539+
else if (typeToMatch.hasGenerics() && containsBeanDefinition(beanName)) {
540+
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
541+
ResolvableType targetType = mbd.targetType;
542+
if (targetType == null) {
543+
targetType = mbd.factoryMethodReturnType;
544+
}
545+
if (targetType == null) {
550546
return false;
551547
}
552-
if (typeToMatch.isAssignableFrom(targetType)) {
553-
return true;
548+
Class<?> targetClass = targetType.resolve();
549+
if (targetClass != null && FactoryBean.class.isAssignableFrom(targetClass)) {
550+
Class<?> classToMatch = typeToMatch.resolve();
551+
if (classToMatch != null && !FactoryBean.class.isAssignableFrom(classToMatch) &&
552+
!classToMatch.isAssignableFrom(targetType.toClass())) {
553+
return typeToMatch.isAssignableFrom(targetType.getGeneric());
554+
}
555+
}
556+
else {
557+
return typeToMatch.isAssignableFrom(targetType);
554558
}
555559
}
556-
ResolvableType resolvableType = mbd.targetType;
557-
if (resolvableType == null) {
558-
resolvableType = mbd.factoryMethodReturnType;
560+
return false;
561+
}
562+
}
563+
else if (isFactoryDereference) {
564+
return false;
565+
}
566+
567+
// Actual matching against bean instance...
568+
if (typeToMatch.isInstance(beanInstance)) {
569+
// Direct match for exposed instance?
570+
return true;
571+
}
572+
else if (typeToMatch.hasGenerics() && containsBeanDefinition(beanName)) {
573+
// Generics potentially only match on the target class, not on the proxy...
574+
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
575+
Class<?> targetType = mbd.getTargetType();
576+
if (targetType != null && targetType != ClassUtils.getUserClass(beanInstance)) {
577+
// Check raw class match as well, making sure it's exposed on the proxy.
578+
Class<?> classToMatch = typeToMatch.resolve();
579+
if (classToMatch != null && !classToMatch.isInstance(beanInstance)) {
580+
return false;
559581
}
560-
return (resolvableType != null && typeToMatch.isAssignableFrom(resolvableType));
582+
if (typeToMatch.isAssignableFrom(targetType)) {
583+
return true;
584+
}
585+
}
586+
ResolvableType resolvableType = mbd.targetType;
587+
if (resolvableType == null) {
588+
resolvableType = mbd.factoryMethodReturnType;
561589
}
590+
return (resolvableType != null && typeToMatch.isAssignableFrom(resolvableType));
591+
}
592+
else {
593+
return false;
562594
}
563-
return false;
564595
}
565596
else if (containsSingleton(beanName) && !containsBeanDefinition(beanName)) {
566597
// null instance registered

spring-beans/src/main/java/org/springframework/beans/factory/support/GenericTypeAwareAutowireCandidateResolver.java

+17-17
Original file line numberDiff line numberDiff line change
@@ -102,23 +102,6 @@ protected boolean checkGenericTypeMatch(BeanDefinitionHolder bdHolder, Dependenc
102102
}
103103
}
104104
}
105-
else {
106-
// Pre-existing target type: In case of a generic FactoryBean type,
107-
// unwrap nested generic type when matching a non-FactoryBean type.
108-
Class<?> resolvedClass = targetType.resolve();
109-
if (resolvedClass != null && FactoryBean.class.isAssignableFrom(resolvedClass)) {
110-
Class<?> typeToBeMatched = dependencyType.resolve();
111-
if (typeToBeMatched != null && !FactoryBean.class.isAssignableFrom(typeToBeMatched) &&
112-
!typeToBeMatched.isAssignableFrom(resolvedClass)) {
113-
targetType = targetType.getGeneric();
114-
if (descriptor.fallbackMatchAllowed()) {
115-
// Matching the Class-based type determination for FactoryBean
116-
// objects in the lazy-determination getType code path below.
117-
targetType = ResolvableType.forClass(targetType.resolve());
118-
}
119-
}
120-
}
121-
}
122105
}
123106

124107
if (targetType == null) {
@@ -145,6 +128,23 @@ protected boolean checkGenericTypeMatch(BeanDefinitionHolder bdHolder, Dependenc
145128
if (cacheType) {
146129
rbd.targetType = targetType;
147130
}
131+
132+
// Pre-declared target type: In case of a generic FactoryBean type,
133+
// unwrap nested generic type when matching a non-FactoryBean type.
134+
Class<?> targetClass = targetType.resolve();
135+
if (targetClass != null && FactoryBean.class.isAssignableFrom(targetClass)) {
136+
Class<?> classToMatch = dependencyType.resolve();
137+
if (classToMatch != null && !FactoryBean.class.isAssignableFrom(classToMatch) &&
138+
!classToMatch.isAssignableFrom(targetClass)) {
139+
targetType = targetType.getGeneric();
140+
if (descriptor.fallbackMatchAllowed()) {
141+
// Matching the Class-based type determination for FactoryBean
142+
// objects in the lazy-determination getType code path above.
143+
targetType = ResolvableType.forClass(targetType.resolve());
144+
}
145+
}
146+
}
147+
148148
if (descriptor.fallbackMatchAllowed() &&
149149
(targetType.hasUnresolvableGenerics() || targetType.resolve() == Properties.class)) {
150150
// Fallback matches allow unresolvable generics, e.g. plain HashMap to Map<String,String>;

0 commit comments

Comments
 (0)