Skip to content

Commit 00b56c0

Browse files
committed
Consistent handling of NullBean instances in resolveNamedBean
Closes gh-26271
1 parent fbd2ffd commit 00b56c0

File tree

3 files changed

+35
-11
lines changed

3 files changed

+35
-11
lines changed

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

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,7 @@ protected <T> T doGetBean(
250250
throws BeansException {
251251

252252
String beanName = transformedBeanName(name);
253-
Object bean;
253+
Object beanInstance;
254254

255255
// Eagerly check singleton cache for manually registered singletons.
256256
Object sharedInstance = getSingleton(beanName);
@@ -264,7 +264,7 @@ protected <T> T doGetBean(
264264
logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
265265
}
266266
}
267-
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
267+
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
268268
}
269269

270270
else {
@@ -342,7 +342,7 @@ else if (requiredType != null) {
342342
throw ex;
343343
}
344344
});
345-
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
345+
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
346346
}
347347

348348
else if (mbd.isPrototype()) {
@@ -355,7 +355,7 @@ else if (mbd.isPrototype()) {
355355
finally {
356356
afterPrototypeCreation(beanName);
357357
}
358-
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
358+
beanInstance = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
359359
}
360360

361361
else {
@@ -377,7 +377,7 @@ else if (mbd.isPrototype()) {
377377
afterPrototypeCreation(beanName);
378378
}
379379
});
380-
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
380+
beanInstance = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
381381
}
382382
catch (IllegalStateException ex) {
383383
throw new ScopeNotActiveException(beanName, scopeName, ex);
@@ -395,14 +395,19 @@ else if (mbd.isPrototype()) {
395395
}
396396
}
397397

398+
return adaptBeanInstance(name, beanInstance, requiredType);
399+
}
400+
401+
@SuppressWarnings("unchecked")
402+
<T> T adaptBeanInstance(String name, Object bean, @Nullable Class<?> requiredType) {
398403
// Check if required type matches the type of the actual bean instance.
399404
if (requiredType != null && !requiredType.isInstance(bean)) {
400405
try {
401-
T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
406+
Object convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
402407
if (convertedBean == null) {
403408
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
404409
}
405-
return convertedBean;
410+
return (T) convertedBean;
406411
}
407412
catch (TypeMismatchException ex) {
408413
if (logger.isTraceEnabled()) {

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

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1231,8 +1231,7 @@ private <T> NamedBeanHolder<T> resolveNamedBean(
12311231
}
12321232

12331233
if (candidateNames.length == 1) {
1234-
String beanName = candidateNames[0];
1235-
return new NamedBeanHolder<>(beanName, (T) getBean(beanName, requiredType.toClass(), args));
1234+
return resolveNamedBean(candidateNames[0], requiredType, args);
12361235
}
12371236
else if (candidateNames.length > 1) {
12381237
Map<String, Object> candidates = CollectionUtils.newLinkedHashMap(candidateNames.length);
@@ -1251,8 +1250,11 @@ else if (candidateNames.length > 1) {
12511250
}
12521251
if (candidateName != null) {
12531252
Object beanInstance = candidates.get(candidateName);
1254-
if (beanInstance == null || beanInstance instanceof Class) {
1255-
beanInstance = getBean(candidateName, requiredType.toClass(), args);
1253+
if (beanInstance == null) {
1254+
return null;
1255+
}
1256+
if (beanInstance instanceof Class) {
1257+
return resolveNamedBean(candidateName, requiredType, args);
12561258
}
12571259
return new NamedBeanHolder<>(candidateName, (T) beanInstance);
12581260
}
@@ -1264,6 +1266,17 @@ else if (candidateNames.length > 1) {
12641266
return null;
12651267
}
12661268

1269+
@Nullable
1270+
private <T> NamedBeanHolder<T> resolveNamedBean(
1271+
String beanName, ResolvableType requiredType, @Nullable Object[] args) throws BeansException {
1272+
1273+
Object bean = getBean(beanName, null, args);
1274+
if (bean instanceof NullBean) {
1275+
return null;
1276+
}
1277+
return new NamedBeanHolder<T>(beanName, adaptBeanInstance(beanName, bean, requiredType.toClass()));
1278+
}
1279+
12671280
@Override
12681281
@Nullable
12691282
public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,

spring-context/src/test/java/org/springframework/context/annotation/AnnotationConfigApplicationContextTests.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,9 +271,15 @@ void individualBeanWithNullReturningSupplier() {
271271
assertThat(ObjectUtils.containsElement(context.getBeanNamesForType(BeanA.class), "a")).isTrue();
272272
assertThat(ObjectUtils.containsElement(context.getBeanNamesForType(BeanB.class), "b")).isTrue();
273273
assertThat(ObjectUtils.containsElement(context.getBeanNamesForType(BeanC.class), "c")).isTrue();
274+
274275
assertThat(context.getBeansOfType(BeanA.class)).isEmpty();
275276
assertThat(context.getBeansOfType(BeanB.class).values().iterator().next()).isSameAs(context.getBean(BeanB.class));
276277
assertThat(context.getBeansOfType(BeanC.class).values().iterator().next()).isSameAs(context.getBean(BeanC.class));
278+
279+
assertThatExceptionOfType(NoSuchBeanDefinitionException.class).isThrownBy(() ->
280+
context.getBeanFactory().resolveNamedBean(BeanA.class));
281+
assertThat(context.getBeanFactory().resolveNamedBean(BeanB.class).getBeanInstance()).isSameAs(context.getBean(BeanB.class));
282+
assertThat(context.getBeanFactory().resolveNamedBean(BeanC.class).getBeanInstance()).isSameAs(context.getBean(BeanC.class));
277283
}
278284

279285
@Test

0 commit comments

Comments
 (0)