Consistent handling of NullBean instances in resolveNamedBean

Closes gh-26271
This commit is contained in:
Juergen Hoeller 2020-12-16 22:27:41 +01:00
parent fbd2ffdd23
commit 00b56c026a
3 changed files with 35 additions and 11 deletions

View File

@ -250,7 +250,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
throws BeansException { throws BeansException {
String beanName = transformedBeanName(name); String beanName = transformedBeanName(name);
Object bean; Object beanInstance;
// Eagerly check singleton cache for manually registered singletons. // Eagerly check singleton cache for manually registered singletons.
Object sharedInstance = getSingleton(beanName); Object sharedInstance = getSingleton(beanName);
@ -264,7 +264,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
logger.trace("Returning cached instance of singleton bean '" + beanName + "'"); logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
} }
} }
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null); beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
} }
else { else {
@ -342,7 +342,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
throw ex; throw ex;
} }
}); });
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
} }
else if (mbd.isPrototype()) { else if (mbd.isPrototype()) {
@ -355,7 +355,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
finally { finally {
afterPrototypeCreation(beanName); afterPrototypeCreation(beanName);
} }
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd); beanInstance = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
} }
else { else {
@ -377,7 +377,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
afterPrototypeCreation(beanName); afterPrototypeCreation(beanName);
} }
}); });
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd); beanInstance = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
} }
catch (IllegalStateException ex) { catch (IllegalStateException ex) {
throw new ScopeNotActiveException(beanName, scopeName, ex); throw new ScopeNotActiveException(beanName, scopeName, ex);
@ -395,14 +395,19 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
} }
} }
return adaptBeanInstance(name, beanInstance, requiredType);
}
@SuppressWarnings("unchecked")
<T> T adaptBeanInstance(String name, Object bean, @Nullable Class<?> requiredType) {
// Check if required type matches the type of the actual bean instance. // Check if required type matches the type of the actual bean instance.
if (requiredType != null && !requiredType.isInstance(bean)) { if (requiredType != null && !requiredType.isInstance(bean)) {
try { try {
T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType); Object convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
if (convertedBean == null) { if (convertedBean == null) {
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass()); throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
} }
return convertedBean; return (T) convertedBean;
} }
catch (TypeMismatchException ex) { catch (TypeMismatchException ex) {
if (logger.isTraceEnabled()) { if (logger.isTraceEnabled()) {

View File

@ -1231,8 +1231,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
} }
if (candidateNames.length == 1) { if (candidateNames.length == 1) {
String beanName = candidateNames[0]; return resolveNamedBean(candidateNames[0], requiredType, args);
return new NamedBeanHolder<>(beanName, (T) getBean(beanName, requiredType.toClass(), args));
} }
else if (candidateNames.length > 1) { else if (candidateNames.length > 1) {
Map<String, Object> candidates = CollectionUtils.newLinkedHashMap(candidateNames.length); Map<String, Object> candidates = CollectionUtils.newLinkedHashMap(candidateNames.length);
@ -1251,8 +1250,11 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
} }
if (candidateName != null) { if (candidateName != null) {
Object beanInstance = candidates.get(candidateName); Object beanInstance = candidates.get(candidateName);
if (beanInstance == null || beanInstance instanceof Class) { if (beanInstance == null) {
beanInstance = getBean(candidateName, requiredType.toClass(), args); return null;
}
if (beanInstance instanceof Class) {
return resolveNamedBean(candidateName, requiredType, args);
} }
return new NamedBeanHolder<>(candidateName, (T) beanInstance); return new NamedBeanHolder<>(candidateName, (T) beanInstance);
} }
@ -1264,6 +1266,17 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
return null; return null;
} }
@Nullable
private <T> NamedBeanHolder<T> resolveNamedBean(
String beanName, ResolvableType requiredType, @Nullable Object[] args) throws BeansException {
Object bean = getBean(beanName, null, args);
if (bean instanceof NullBean) {
return null;
}
return new NamedBeanHolder<T>(beanName, adaptBeanInstance(beanName, bean, requiredType.toClass()));
}
@Override @Override
@Nullable @Nullable
public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName, public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,

View File

@ -271,9 +271,15 @@ class AnnotationConfigApplicationContextTests {
assertThat(ObjectUtils.containsElement(context.getBeanNamesForType(BeanA.class), "a")).isTrue(); assertThat(ObjectUtils.containsElement(context.getBeanNamesForType(BeanA.class), "a")).isTrue();
assertThat(ObjectUtils.containsElement(context.getBeanNamesForType(BeanB.class), "b")).isTrue(); assertThat(ObjectUtils.containsElement(context.getBeanNamesForType(BeanB.class), "b")).isTrue();
assertThat(ObjectUtils.containsElement(context.getBeanNamesForType(BeanC.class), "c")).isTrue(); assertThat(ObjectUtils.containsElement(context.getBeanNamesForType(BeanC.class), "c")).isTrue();
assertThat(context.getBeansOfType(BeanA.class)).isEmpty(); assertThat(context.getBeansOfType(BeanA.class)).isEmpty();
assertThat(context.getBeansOfType(BeanB.class).values().iterator().next()).isSameAs(context.getBean(BeanB.class)); assertThat(context.getBeansOfType(BeanB.class).values().iterator().next()).isSameAs(context.getBean(BeanB.class));
assertThat(context.getBeansOfType(BeanC.class).values().iterator().next()).isSameAs(context.getBean(BeanC.class)); assertThat(context.getBeansOfType(BeanC.class).values().iterator().next()).isSameAs(context.getBean(BeanC.class));
assertThatExceptionOfType(NoSuchBeanDefinitionException.class).isThrownBy(() ->
context.getBeanFactory().resolveNamedBean(BeanA.class));
assertThat(context.getBeanFactory().resolveNamedBean(BeanB.class).getBeanInstance()).isSameAs(context.getBean(BeanB.class));
assertThat(context.getBeanFactory().resolveNamedBean(BeanC.class).getBeanInstance()).isSameAs(context.getBean(BeanC.class));
} }
@Test @Test