Skip to content

Commit 9a39a25

Browse files
committed
Detect generic type match behind interface-based proxy as well
Issue: SPR-14097 (cherry picked from commit f805427)
1 parent 4b01840 commit 9a39a25

File tree

4 files changed

+295
-138
lines changed

4 files changed

+295
-138
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -514,6 +514,7 @@ protected Object doCreateBean(final String beanName, final RootBeanDefinition mb
514514
}
515515
final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
516516
Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
517+
mbd.resolvedTargetType = beanType;
517518

518519
// Allow post-processors to modify the merged bean definition.
519520
synchronized (mbd.postProcessingLock) {

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

Lines changed: 133 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -409,33 +409,31 @@ else if (containsSingleton(beanName)) {
409409
return true;
410410
}
411411

412-
else {
413-
// No singleton instance found -> check bean definition.
414-
BeanFactory parentBeanFactory = getParentBeanFactory();
415-
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
416-
// No bean definition found in this factory -> delegate to parent.
417-
return parentBeanFactory.isSingleton(originalBeanName(name));
418-
}
412+
// No singleton instance found -> check bean definition.
413+
BeanFactory parentBeanFactory = getParentBeanFactory();
414+
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
415+
// No bean definition found in this factory -> delegate to parent.
416+
return parentBeanFactory.isSingleton(originalBeanName(name));
417+
}
419418

420-
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
419+
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
421420

422-
// In case of FactoryBean, return singleton status of created object if not a dereference.
423-
if (mbd.isSingleton()) {
424-
if (isFactoryBean(beanName, mbd)) {
425-
if (BeanFactoryUtils.isFactoryDereference(name)) {
426-
return true;
427-
}
428-
FactoryBean<?> factoryBean = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
429-
return factoryBean.isSingleton();
430-
}
431-
else {
432-
return !BeanFactoryUtils.isFactoryDereference(name);
421+
// In case of FactoryBean, return singleton status of created object if not a dereference.
422+
if (mbd.isSingleton()) {
423+
if (isFactoryBean(beanName, mbd)) {
424+
if (BeanFactoryUtils.isFactoryDereference(name)) {
425+
return true;
433426
}
427+
FactoryBean<?> factoryBean = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
428+
return factoryBean.isSingleton();
434429
}
435430
else {
436-
return false;
431+
return !BeanFactoryUtils.isFactoryDereference(name);
437432
}
438433
}
434+
else {
435+
return false;
436+
}
439437
}
440438

441439
@Override
@@ -453,32 +451,31 @@ public boolean isPrototype(String name) throws NoSuchBeanDefinitionException {
453451
// In case of FactoryBean, return singleton status of created object if not a dereference.
454452
return (!BeanFactoryUtils.isFactoryDereference(name) || isFactoryBean(beanName, mbd));
455453
}
456-
else {
457-
// Singleton or scoped - not a prototype.
458-
// However, FactoryBean may still produce a prototype object...
459-
if (BeanFactoryUtils.isFactoryDereference(name)) {
460-
return false;
461-
}
462-
if (isFactoryBean(beanName, mbd)) {
463-
final FactoryBean<?> fb = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
464-
if (System.getSecurityManager() != null) {
465-
return AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
466-
@Override
467-
public Boolean run() {
468-
return ((fb instanceof SmartFactoryBean && ((SmartFactoryBean<?>) fb).isPrototype()) ||
469-
!fb.isSingleton());
470-
}
471-
}, getAccessControlContext());
472-
}
473-
else {
474-
return ((fb instanceof SmartFactoryBean && ((SmartFactoryBean<?>) fb).isPrototype()) ||
475-
!fb.isSingleton());
476-
}
454+
455+
// Singleton or scoped - not a prototype.
456+
// However, FactoryBean may still produce a prototype object...
457+
if (BeanFactoryUtils.isFactoryDereference(name)) {
458+
return false;
459+
}
460+
if (isFactoryBean(beanName, mbd)) {
461+
final FactoryBean<?> fb = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
462+
if (System.getSecurityManager() != null) {
463+
return AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
464+
@Override
465+
public Boolean run() {
466+
return ((fb instanceof SmartFactoryBean && ((SmartFactoryBean<?>) fb).isPrototype()) ||
467+
!fb.isSingleton());
468+
}
469+
}, getAccessControlContext());
477470
}
478471
else {
479-
return false;
472+
return ((fb instanceof SmartFactoryBean && ((SmartFactoryBean<?>) fb).isPrototype()) ||
473+
!fb.isSingleton());
480474
}
481475
}
476+
else {
477+
return false;
478+
}
482479
}
483480

484481
@Override
@@ -497,78 +494,91 @@ public boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuc
497494
return typeToMatch.isInstance(beanInstance);
498495
}
499496
}
500-
else {
501-
return (!BeanFactoryUtils.isFactoryDereference(name) && typeToMatch.isInstance(beanInstance));
497+
else if (!BeanFactoryUtils.isFactoryDereference(name)) {
498+
if (typeToMatch.isInstance(beanInstance)) {
499+
// Direct match for exposed instance?
500+
return true;
501+
}
502+
else if (typeToMatch.hasGenerics() && containsBeanDefinition(beanName)) {
503+
// Generics potentially only match on the target class, not on the proxy...
504+
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
505+
Class<?> targetType = mbd.getTargetType();
506+
if (targetType != null && targetType != ClassUtils.getUserClass(beanInstance) &&
507+
typeToMatch.isAssignableFrom(targetType)) {
508+
// Check raw class match as well, making sure it's exposed on the proxy.
509+
Class<?> classToMatch = typeToMatch.resolve();
510+
return (classToMatch == null || classToMatch.isInstance(beanInstance));
511+
}
512+
}
502513
}
514+
return false;
503515
}
504516
else if (containsSingleton(beanName) && !containsBeanDefinition(beanName)) {
505517
// null instance registered
506518
return false;
507519
}
508520

509-
else {
510-
// No singleton instance found -> check bean definition.
511-
BeanFactory parentBeanFactory = getParentBeanFactory();
512-
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
513-
// No bean definition found in this factory -> delegate to parent.
514-
return parentBeanFactory.isTypeMatch(originalBeanName(name), typeToMatch);
515-
}
521+
// No singleton instance found -> check bean definition.
522+
BeanFactory parentBeanFactory = getParentBeanFactory();
523+
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
524+
// No bean definition found in this factory -> delegate to parent.
525+
return parentBeanFactory.isTypeMatch(originalBeanName(name), typeToMatch);
526+
}
516527

517-
// Retrieve corresponding bean definition.
518-
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
528+
// Retrieve corresponding bean definition.
529+
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
519530

520-
Class<?> classToMatch = typeToMatch.resolve();
521-
if (classToMatch == null) {
522-
classToMatch = FactoryBean.class;
523-
}
524-
Class<?>[] typesToMatch = (FactoryBean.class == classToMatch ?
525-
new Class<?>[] {classToMatch} : new Class<?>[] {FactoryBean.class, classToMatch});
526-
527-
// Check decorated bean definition, if any: We assume it'll be easier
528-
// to determine the decorated bean's type than the proxy's type.
529-
BeanDefinitionHolder dbd = mbd.getDecoratedDefinition();
530-
if (dbd != null && !BeanFactoryUtils.isFactoryDereference(name)) {
531-
RootBeanDefinition tbd = getMergedBeanDefinition(dbd.getBeanName(), dbd.getBeanDefinition(), mbd);
532-
Class<?> targetClass = predictBeanType(dbd.getBeanName(), tbd, typesToMatch);
533-
if (targetClass != null && !FactoryBean.class.isAssignableFrom(targetClass)) {
534-
return typeToMatch.isAssignableFrom(targetClass);
535-
}
531+
Class<?> classToMatch = typeToMatch.resolve();
532+
if (classToMatch == null) {
533+
classToMatch = FactoryBean.class;
534+
}
535+
Class<?>[] typesToMatch = (FactoryBean.class == classToMatch ?
536+
new Class<?>[] {classToMatch} : new Class<?>[] {FactoryBean.class, classToMatch});
537+
538+
// Check decorated bean definition, if any: We assume it'll be easier
539+
// to determine the decorated bean's type than the proxy's type.
540+
BeanDefinitionHolder dbd = mbd.getDecoratedDefinition();
541+
if (dbd != null && !BeanFactoryUtils.isFactoryDereference(name)) {
542+
RootBeanDefinition tbd = getMergedBeanDefinition(dbd.getBeanName(), dbd.getBeanDefinition(), mbd);
543+
Class<?> targetClass = predictBeanType(dbd.getBeanName(), tbd, typesToMatch);
544+
if (targetClass != null && !FactoryBean.class.isAssignableFrom(targetClass)) {
545+
return typeToMatch.isAssignableFrom(targetClass);
536546
}
547+
}
537548

538-
Class<?> beanType = predictBeanType(beanName, mbd, typesToMatch);
539-
if (beanType == null) {
540-
return false;
541-
}
549+
Class<?> beanType = predictBeanType(beanName, mbd, typesToMatch);
550+
if (beanType == null) {
551+
return false;
552+
}
542553

543-
// Check bean class whether we're dealing with a FactoryBean.
544-
if (FactoryBean.class.isAssignableFrom(beanType)) {
545-
if (!BeanFactoryUtils.isFactoryDereference(name)) {
546-
// If it's a FactoryBean, we want to look at what it creates, not the factory class.
547-
beanType = getTypeForFactoryBean(beanName, mbd);
548-
if (beanType == null) {
549-
return false;
550-
}
551-
}
552-
}
553-
else if (BeanFactoryUtils.isFactoryDereference(name)) {
554-
// Special case: A SmartInstantiationAwareBeanPostProcessor returned a non-FactoryBean
555-
// type but we nevertheless are being asked to dereference a FactoryBean...
556-
// Let's check the original bean class and proceed with it if it is a FactoryBean.
557-
beanType = predictBeanType(beanName, mbd, FactoryBean.class);
558-
if (beanType == null || !FactoryBean.class.isAssignableFrom(beanType)) {
554+
// Check bean class whether we're dealing with a FactoryBean.
555+
if (FactoryBean.class.isAssignableFrom(beanType)) {
556+
if (!BeanFactoryUtils.isFactoryDereference(name)) {
557+
// If it's a FactoryBean, we want to look at what it creates, not the factory class.
558+
beanType = getTypeForFactoryBean(beanName, mbd);
559+
if (beanType == null) {
559560
return false;
560561
}
561562
}
562-
563-
ResolvableType resolvableType = mbd.targetType;
564-
if (resolvableType == null) {
565-
resolvableType = mbd.factoryMethodReturnType;
566-
}
567-
if (resolvableType != null && resolvableType.resolve() == beanType) {
568-
return typeToMatch.isAssignableFrom(resolvableType);
563+
}
564+
else if (BeanFactoryUtils.isFactoryDereference(name)) {
565+
// Special case: A SmartInstantiationAwareBeanPostProcessor returned a non-FactoryBean
566+
// type but we nevertheless are being asked to dereference a FactoryBean...
567+
// Let's check the original bean class and proceed with it if it is a FactoryBean.
568+
beanType = predictBeanType(beanName, mbd, FactoryBean.class);
569+
if (beanType == null || !FactoryBean.class.isAssignableFrom(beanType)) {
570+
return false;
569571
}
570-
return typeToMatch.isAssignableFrom(beanType);
571572
}
573+
574+
ResolvableType resolvableType = mbd.targetType;
575+
if (resolvableType == null) {
576+
resolvableType = mbd.factoryMethodReturnType;
577+
}
578+
if (resolvableType != null && resolvableType.resolve() == beanType) {
579+
return typeToMatch.isAssignableFrom(resolvableType);
580+
}
581+
return typeToMatch.isAssignableFrom(beanType);
572582
}
573583

574584
@Override
@@ -595,43 +605,41 @@ else if (containsSingleton(beanName) && !containsBeanDefinition(beanName)) {
595605
return null;
596606
}
597607

598-
else {
599-
// No singleton instance found -> check bean definition.
600-
BeanFactory parentBeanFactory = getParentBeanFactory();
601-
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
602-
// No bean definition found in this factory -> delegate to parent.
603-
return parentBeanFactory.getType(originalBeanName(name));
604-
}
608+
// No singleton instance found -> check bean definition.
609+
BeanFactory parentBeanFactory = getParentBeanFactory();
610+
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
611+
// No bean definition found in this factory -> delegate to parent.
612+
return parentBeanFactory.getType(originalBeanName(name));
613+
}
605614

606-
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
615+
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
607616

608-
// Check decorated bean definition, if any: We assume it'll be easier
609-
// to determine the decorated bean's type than the proxy's type.
610-
BeanDefinitionHolder dbd = mbd.getDecoratedDefinition();
611-
if (dbd != null && !BeanFactoryUtils.isFactoryDereference(name)) {
612-
RootBeanDefinition tbd = getMergedBeanDefinition(dbd.getBeanName(), dbd.getBeanDefinition(), mbd);
613-
Class<?> targetClass = predictBeanType(dbd.getBeanName(), tbd);
614-
if (targetClass != null && !FactoryBean.class.isAssignableFrom(targetClass)) {
615-
return targetClass;
616-
}
617+
// Check decorated bean definition, if any: We assume it'll be easier
618+
// to determine the decorated bean's type than the proxy's type.
619+
BeanDefinitionHolder dbd = mbd.getDecoratedDefinition();
620+
if (dbd != null && !BeanFactoryUtils.isFactoryDereference(name)) {
621+
RootBeanDefinition tbd = getMergedBeanDefinition(dbd.getBeanName(), dbd.getBeanDefinition(), mbd);
622+
Class<?> targetClass = predictBeanType(dbd.getBeanName(), tbd);
623+
if (targetClass != null && !FactoryBean.class.isAssignableFrom(targetClass)) {
624+
return targetClass;
617625
}
626+
}
618627

619-
Class<?> beanClass = predictBeanType(beanName, mbd);
628+
Class<?> beanClass = predictBeanType(beanName, mbd);
620629

621-
// Check bean class whether we're dealing with a FactoryBean.
622-
if (beanClass != null && FactoryBean.class.isAssignableFrom(beanClass)) {
623-
if (!BeanFactoryUtils.isFactoryDereference(name)) {
624-
// If it's a FactoryBean, we want to look at what it creates, not at the factory class.
625-
return getTypeForFactoryBean(beanName, mbd);
626-
}
627-
else {
628-
return beanClass;
629-
}
630+
// Check bean class whether we're dealing with a FactoryBean.
631+
if (beanClass != null && FactoryBean.class.isAssignableFrom(beanClass)) {
632+
if (!BeanFactoryUtils.isFactoryDereference(name)) {
633+
// If it's a FactoryBean, we want to look at what it creates, not at the factory class.
634+
return getTypeForFactoryBean(beanName, mbd);
630635
}
631636
else {
632-
return (!BeanFactoryUtils.isFactoryDereference(name) ? beanClass : null);
637+
return beanClass;
633638
}
634639
}
640+
else {
641+
return (!BeanFactoryUtils.isFactoryDereference(name) ? beanClass : null);
642+
}
635643
}
636644

637645
@Override

0 commit comments

Comments
 (0)