Skip to content

Commit f805427

Browse files
committed
Detect generic type match behind interface-based proxy as well
Issue: SPR-14097
1 parent 0208198 commit f805427

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
@@ -528,6 +528,7 @@ protected Object doCreateBean(final String beanName, final RootBeanDefinition mb
528528
}
529529
final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
530530
Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
531+
mbd.resolvedTargetType = beanType;
531532

532533
// Allow post-processors to modify the merged bean definition.
533534
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
@@ -405,33 +405,31 @@ else if (containsSingleton(beanName)) {
405405
return true;
406406
}
407407

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

416-
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
415+
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
417416

418-
// In case of FactoryBean, return singleton status of created object if not a dereference.
419-
if (mbd.isSingleton()) {
420-
if (isFactoryBean(beanName, mbd)) {
421-
if (BeanFactoryUtils.isFactoryDereference(name)) {
422-
return true;
423-
}
424-
FactoryBean<?> factoryBean = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
425-
return factoryBean.isSingleton();
426-
}
427-
else {
428-
return !BeanFactoryUtils.isFactoryDereference(name);
417+
// In case of FactoryBean, return singleton status of created object if not a dereference.
418+
if (mbd.isSingleton()) {
419+
if (isFactoryBean(beanName, mbd)) {
420+
if (BeanFactoryUtils.isFactoryDereference(name)) {
421+
return true;
429422
}
423+
FactoryBean<?> factoryBean = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
424+
return factoryBean.isSingleton();
430425
}
431426
else {
432-
return false;
427+
return !BeanFactoryUtils.isFactoryDereference(name);
433428
}
434429
}
430+
else {
431+
return false;
432+
}
435433
}
436434

437435
@Override
@@ -449,32 +447,31 @@ public boolean isPrototype(String name) throws NoSuchBeanDefinitionException {
449447
// In case of FactoryBean, return singleton status of created object if not a dereference.
450448
return (!BeanFactoryUtils.isFactoryDereference(name) || isFactoryBean(beanName, mbd));
451449
}
452-
else {
453-
// Singleton or scoped - not a prototype.
454-
// However, FactoryBean may still produce a prototype object...
455-
if (BeanFactoryUtils.isFactoryDereference(name)) {
456-
return false;
457-
}
458-
if (isFactoryBean(beanName, mbd)) {
459-
final FactoryBean<?> fb = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
460-
if (System.getSecurityManager() != null) {
461-
return AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
462-
@Override
463-
public Boolean run() {
464-
return ((fb instanceof SmartFactoryBean && ((SmartFactoryBean<?>) fb).isPrototype()) ||
465-
!fb.isSingleton());
466-
}
467-
}, getAccessControlContext());
468-
}
469-
else {
470-
return ((fb instanceof SmartFactoryBean && ((SmartFactoryBean<?>) fb).isPrototype()) ||
471-
!fb.isSingleton());
472-
}
450+
451+
// Singleton or scoped - not a prototype.
452+
// However, FactoryBean may still produce a prototype object...
453+
if (BeanFactoryUtils.isFactoryDereference(name)) {
454+
return false;
455+
}
456+
if (isFactoryBean(beanName, mbd)) {
457+
final FactoryBean<?> fb = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
458+
if (System.getSecurityManager() != null) {
459+
return AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
460+
@Override
461+
public Boolean run() {
462+
return ((fb instanceof SmartFactoryBean && ((SmartFactoryBean<?>) fb).isPrototype()) ||
463+
!fb.isSingleton());
464+
}
465+
}, getAccessControlContext());
473466
}
474467
else {
475-
return false;
468+
return ((fb instanceof SmartFactoryBean && ((SmartFactoryBean<?>) fb).isPrototype()) ||
469+
!fb.isSingleton());
476470
}
477471
}
472+
else {
473+
return false;
474+
}
478475
}
479476

480477
@Override
@@ -493,78 +490,91 @@ public boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuc
493490
return typeToMatch.isInstance(beanInstance);
494491
}
495492
}
496-
else {
497-
return (!BeanFactoryUtils.isFactoryDereference(name) && typeToMatch.isInstance(beanInstance));
493+
else if (!BeanFactoryUtils.isFactoryDereference(name)) {
494+
if (typeToMatch.isInstance(beanInstance)) {
495+
// Direct match for exposed instance?
496+
return true;
497+
}
498+
else if (typeToMatch.hasGenerics() && containsBeanDefinition(beanName)) {
499+
// Generics potentially only match on the target class, not on the proxy...
500+
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
501+
Class<?> targetType = mbd.getTargetType();
502+
if (targetType != null && targetType != ClassUtils.getUserClass(beanInstance) &&
503+
typeToMatch.isAssignableFrom(targetType)) {
504+
// Check raw class match as well, making sure it's exposed on the proxy.
505+
Class<?> classToMatch = typeToMatch.resolve();
506+
return (classToMatch == null || classToMatch.isInstance(beanInstance));
507+
}
508+
}
498509
}
510+
return false;
499511
}
500512
else if (containsSingleton(beanName) && !containsBeanDefinition(beanName)) {
501513
// null instance registered
502514
return false;
503515
}
504516

505-
else {
506-
// No singleton instance found -> check bean definition.
507-
BeanFactory parentBeanFactory = getParentBeanFactory();
508-
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
509-
// No bean definition found in this factory -> delegate to parent.
510-
return parentBeanFactory.isTypeMatch(originalBeanName(name), typeToMatch);
511-
}
517+
// No singleton instance found -> check bean definition.
518+
BeanFactory parentBeanFactory = getParentBeanFactory();
519+
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
520+
// No bean definition found in this factory -> delegate to parent.
521+
return parentBeanFactory.isTypeMatch(originalBeanName(name), typeToMatch);
522+
}
512523

513-
// Retrieve corresponding bean definition.
514-
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
524+
// Retrieve corresponding bean definition.
525+
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
515526

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

534-
Class<?> beanType = predictBeanType(beanName, mbd, typesToMatch);
535-
if (beanType == null) {
536-
return false;
537-
}
545+
Class<?> beanType = predictBeanType(beanName, mbd, typesToMatch);
546+
if (beanType == null) {
547+
return false;
548+
}
538549

539-
// Check bean class whether we're dealing with a FactoryBean.
540-
if (FactoryBean.class.isAssignableFrom(beanType)) {
541-
if (!BeanFactoryUtils.isFactoryDereference(name)) {
542-
// If it's a FactoryBean, we want to look at what it creates, not the factory class.
543-
beanType = getTypeForFactoryBean(beanName, mbd);
544-
if (beanType == null) {
545-
return false;
546-
}
547-
}
548-
}
549-
else if (BeanFactoryUtils.isFactoryDereference(name)) {
550-
// Special case: A SmartInstantiationAwareBeanPostProcessor returned a non-FactoryBean
551-
// type but we nevertheless are being asked to dereference a FactoryBean...
552-
// Let's check the original bean class and proceed with it if it is a FactoryBean.
553-
beanType = predictBeanType(beanName, mbd, FactoryBean.class);
554-
if (beanType == null || !FactoryBean.class.isAssignableFrom(beanType)) {
550+
// Check bean class whether we're dealing with a FactoryBean.
551+
if (FactoryBean.class.isAssignableFrom(beanType)) {
552+
if (!BeanFactoryUtils.isFactoryDereference(name)) {
553+
// If it's a FactoryBean, we want to look at what it creates, not the factory class.
554+
beanType = getTypeForFactoryBean(beanName, mbd);
555+
if (beanType == null) {
555556
return false;
556557
}
557558
}
558-
559-
ResolvableType resolvableType = mbd.targetType;
560-
if (resolvableType == null) {
561-
resolvableType = mbd.factoryMethodReturnType;
562-
}
563-
if (resolvableType != null && resolvableType.resolve() == beanType) {
564-
return typeToMatch.isAssignableFrom(resolvableType);
559+
}
560+
else if (BeanFactoryUtils.isFactoryDereference(name)) {
561+
// Special case: A SmartInstantiationAwareBeanPostProcessor returned a non-FactoryBean
562+
// type but we nevertheless are being asked to dereference a FactoryBean...
563+
// Let's check the original bean class and proceed with it if it is a FactoryBean.
564+
beanType = predictBeanType(beanName, mbd, FactoryBean.class);
565+
if (beanType == null || !FactoryBean.class.isAssignableFrom(beanType)) {
566+
return false;
565567
}
566-
return typeToMatch.isAssignableFrom(beanType);
567568
}
569+
570+
ResolvableType resolvableType = mbd.targetType;
571+
if (resolvableType == null) {
572+
resolvableType = mbd.factoryMethodReturnType;
573+
}
574+
if (resolvableType != null && resolvableType.resolve() == beanType) {
575+
return typeToMatch.isAssignableFrom(resolvableType);
576+
}
577+
return typeToMatch.isAssignableFrom(beanType);
568578
}
569579

570580
@Override
@@ -591,43 +601,41 @@ else if (containsSingleton(beanName) && !containsBeanDefinition(beanName)) {
591601
return null;
592602
}
593603

594-
else {
595-
// No singleton instance found -> check bean definition.
596-
BeanFactory parentBeanFactory = getParentBeanFactory();
597-
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
598-
// No bean definition found in this factory -> delegate to parent.
599-
return parentBeanFactory.getType(originalBeanName(name));
600-
}
604+
// No singleton instance found -> check bean definition.
605+
BeanFactory parentBeanFactory = getParentBeanFactory();
606+
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
607+
// No bean definition found in this factory -> delegate to parent.
608+
return parentBeanFactory.getType(originalBeanName(name));
609+
}
601610

602-
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
611+
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
603612

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

615-
Class<?> beanClass = predictBeanType(beanName, mbd);
624+
Class<?> beanClass = predictBeanType(beanName, mbd);
616625

617-
// Check bean class whether we're dealing with a FactoryBean.
618-
if (beanClass != null && FactoryBean.class.isAssignableFrom(beanClass)) {
619-
if (!BeanFactoryUtils.isFactoryDereference(name)) {
620-
// If it's a FactoryBean, we want to look at what it creates, not at the factory class.
621-
return getTypeForFactoryBean(beanName, mbd);
622-
}
623-
else {
624-
return beanClass;
625-
}
626+
// Check bean class whether we're dealing with a FactoryBean.
627+
if (beanClass != null && FactoryBean.class.isAssignableFrom(beanClass)) {
628+
if (!BeanFactoryUtils.isFactoryDereference(name)) {
629+
// If it's a FactoryBean, we want to look at what it creates, not at the factory class.
630+
return getTypeForFactoryBean(beanName, mbd);
626631
}
627632
else {
628-
return (!BeanFactoryUtils.isFactoryDereference(name) ? beanClass : null);
633+
return beanClass;
629634
}
630635
}
636+
else {
637+
return (!BeanFactoryUtils.isFactoryDereference(name) ? beanClass : null);
638+
}
631639
}
632640

633641
@Override

0 commit comments

Comments
 (0)