Skip to content

Commit b94302b

Browse files
committed
Enforce non-null value from getBean and at injection points
Bean-derived null values may still get passed into bean properties and injection points but only if those are declared as non-required. Note that getBean will never return null; a manual bean.equals(null) / "null".equals(bean.toString()) check identifies expected null values now. This will only ever happen with custom FactoryBeans or factory methods returning null - and since all common cases are handled by autowiring or bean property values in bean definitions, there should be no need to ever manually check for such a null value received from getBean. Issue: SPR-15829
1 parent 10dcaa9 commit b94302b

File tree

30 files changed

+344
-204
lines changed

30 files changed

+344
-204
lines changed

spring-beans/src/main/java/org/springframework/beans/factory/ObjectFactory.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@ public interface ObjectFactory<T> {
4545
* @return the resulting instance
4646
* @throws BeansException in case of creation errors
4747
*/
48-
@Nullable
4948
T getObject() throws BeansException;
5049

5150
}

spring-beans/src/main/java/org/springframework/beans/factory/ObjectProvider.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ public interface ObjectProvider<T> extends ObjectFactory<T> {
4040
* @throws BeansException in case of creation errors
4141
* @see #getObject()
4242
*/
43-
@Nullable
4443
T getObject(Object... args) throws BeansException;
4544

4645
/**

spring-beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -725,7 +725,7 @@ public ShortcutDependencyDescriptor(DependencyDescriptor original, String shortc
725725

726726
@Override
727727
public Object resolveShortcut(BeanFactory beanFactory) {
728-
return resolveCandidate(this.shortcut, this.requiredType, beanFactory);
728+
return beanFactory.getBean(this.shortcut, this.requiredType);
729729
}
730730
}
731731

spring-beans/src/main/java/org/springframework/beans/factory/config/AutowireCapableBeanFactory.java

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,6 @@ void autowireBeanProperties(Object existingBean, int autowireMode, boolean depen
268268
* @return the bean instance to use, either the original or a wrapped one
269269
* @throws BeansException if the initialization failed
270270
*/
271-
@Nullable
272271
Object initializeBean(Object existingBean, String beanName) throws BeansException;
273272

274273
/**
@@ -281,7 +280,6 @@ void autowireBeanProperties(Object existingBean, int autowireMode, boolean depen
281280
* @throws BeansException if any post-processing failed
282281
* @see BeanPostProcessor#postProcessBeforeInitialization
283282
*/
284-
@Nullable
285283
Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
286284
throws BeansException;
287285

@@ -295,7 +293,6 @@ Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String b
295293
* @throws BeansException if any post-processing failed
296294
* @see BeanPostProcessor#postProcessAfterInitialization
297295
*/
298-
@Nullable
299296
Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
300297
throws BeansException;
301298

spring-beans/src/main/java/org/springframework/beans/factory/config/DependencyDescriptor.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ public Object resolveShortcut(BeanFactory beanFactory) throws BeansException {
252252
public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFactory beanFactory)
253253
throws BeansException {
254254

255-
return beanFactory.getBean(beanName, requiredType);
255+
return beanFactory.getBean(beanName);
256256
}
257257

258258

spring-beans/src/main/java/org/springframework/beans/factory/config/SmartInstantiationAwareBeanPostProcessor.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,6 @@ default Constructor<?>[] determineCandidateConstructors(Class<?> beanClass, Stri
8787
* (typically with the passed-in bean instance as default)
8888
* @throws org.springframework.beans.BeansException in case of errors
8989
*/
90-
@Nullable
9190
default Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
9291
return bean;
9392
}

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

Lines changed: 44 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -410,37 +410,36 @@ public void applyBeanPropertyValues(Object existingBean, String beanName) throws
410410
}
411411

412412
@Override
413-
@Nullable
414413
public Object initializeBean(Object existingBean, String beanName) {
415414
return initializeBean(beanName, existingBean, null);
416415
}
417416

418417
@Override
419-
@Nullable
420418
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
421419
throws BeansException {
422420

423421
Object result = existingBean;
424422
for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
425-
result = beanProcessor.postProcessBeforeInitialization(result, beanName);
426-
if (result == null) {
427-
return null;
423+
Object current = beanProcessor.postProcessBeforeInitialization(result, beanName);
424+
if (current == null) {
425+
return result;
428426
}
427+
result = current;
429428
}
430429
return result;
431430
}
432431

433432
@Override
434-
@Nullable
435433
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
436434
throws BeansException {
437435

438436
Object result = existingBean;
439437
for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
440-
result = beanProcessor.postProcessAfterInitialization(result, beanName);
441-
if (result == null) {
442-
return null;
438+
Object current = beanProcessor.postProcessAfterInitialization(result, beanName);
439+
if (current == null) {
440+
return result;
443441
}
442+
result = current;
444443
}
445444
return result;
446445
}
@@ -461,7 +460,6 @@ public void destroyBean(Object existingBean) {
461460
* @see #doCreateBean
462461
*/
463462
@Override
464-
@Nullable
465463
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
466464
throws BeanCreationException {
467465

@@ -535,7 +533,6 @@ protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable O
535533
* @see #instantiateUsingFactoryMethod
536534
* @see #autowireConstructor
537535
*/
538-
@Nullable
539536
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
540537
throws BeanCreationException {
541538

@@ -547,23 +544,23 @@ protected Object doCreateBean(final String beanName, final RootBeanDefinition mb
547544
if (instanceWrapper == null) {
548545
instanceWrapper = createBeanInstance(beanName, mbd, args);
549546
}
550-
final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
551-
Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
552-
mbd.resolvedTargetType = beanType;
547+
final Object bean = instanceWrapper.getWrappedInstance();
548+
Class<?> beanType = instanceWrapper.getWrappedClass();
549+
if (beanType != NullBean.class) {
550+
mbd.resolvedTargetType = beanType;
551+
}
553552

554-
if (beanType != null) {
555-
// Allow post-processors to modify the merged bean definition.
556-
synchronized (mbd.postProcessingLock) {
557-
if (!mbd.postProcessed) {
558-
try {
559-
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
560-
}
561-
catch (Throwable ex) {
562-
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
563-
"Post-processing of merged bean definition failed", ex);
564-
}
565-
mbd.postProcessed = true;
553+
// Allow post-processors to modify the merged bean definition.
554+
synchronized (mbd.postProcessingLock) {
555+
if (!mbd.postProcessed) {
556+
try {
557+
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
566558
}
559+
catch (Throwable ex) {
560+
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
561+
"Post-processing of merged bean definition failed", ex);
562+
}
563+
mbd.postProcessed = true;
567564
}
568565
}
569566

@@ -583,9 +580,7 @@ protected Object doCreateBean(final String beanName, final RootBeanDefinition mb
583580
Object exposedObject = bean;
584581
try {
585582
populateBean(beanName, mbd, instanceWrapper);
586-
if (exposedObject != null) {
587-
exposedObject = initializeBean(beanName, exposedObject, mbd);
588-
}
583+
exposedObject = initializeBean(beanName, exposedObject, mbd);
589584
}
590585
catch (Throwable ex) {
591586
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
@@ -624,15 +619,13 @@ else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
624619
}
625620
}
626621

627-
if (bean != null) {
628-
// Register bean as disposable.
629-
try {
630-
registerDisposableBeanIfNecessary(beanName, bean, mbd);
631-
}
632-
catch (BeanDefinitionValidationException ex) {
633-
throw new BeanCreationException(
634-
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
635-
}
622+
// Register bean as disposable.
623+
try {
624+
registerDisposableBeanIfNecessary(beanName, bean, mbd);
625+
}
626+
catch (BeanDefinitionValidationException ex) {
627+
throw new BeanCreationException(
628+
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
636629
}
637630

638631
return exposedObject;
@@ -904,17 +897,13 @@ class Holder { @Nullable Class<?> value = null; }
904897
* @param bean the raw bean instance
905898
* @return the object to expose as bean reference
906899
*/
907-
@Nullable
908-
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, @Nullable Object bean) {
900+
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
909901
Object exposedObject = bean;
910-
if (bean != null && !mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
902+
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
911903
for (BeanPostProcessor bp : getBeanPostProcessors()) {
912904
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
913905
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
914906
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
915-
if (exposedObject == null) {
916-
return null;
917-
}
918907
}
919908
}
920909
}
@@ -954,9 +943,6 @@ private FactoryBean<?> getSingletonFactoryBeanForTypeCheck(String beanName, Root
954943
instance = resolveBeforeInstantiation(beanName, mbd);
955944
if (instance == null) {
956945
bw = createBeanInstance(beanName, mbd, null);
957-
if (bw == null) {
958-
return null;
959-
}
960946
instance = bw.getWrappedInstance();
961947
}
962948
}
@@ -995,9 +981,6 @@ private FactoryBean<?> getNonSingletonFactoryBeanForTypeCheck(String beanName, R
995981
instance = resolveBeforeInstantiation(beanName, mbd);
996982
if (instance == null) {
997983
BeanWrapper bw = createBeanInstance(beanName, mbd, null);
998-
if (bw == null) {
999-
return null;
1000-
}
1001984
instance = bw.getWrappedInstance();
1002985
}
1003986
}
@@ -1097,7 +1080,6 @@ protected Object applyBeanPostProcessorsBeforeInstantiation(Class<?> beanClass,
10971080
* @see #autowireConstructor
10981081
* @see #instantiateBean
10991082
*/
1100-
@Nullable
11011083
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
11021084
// Make sure bean class is actually resolved at this point.
11031085
Class<?> beanClass = resolveBeanClass(mbd, beanName);
@@ -1184,9 +1166,8 @@ protected BeanWrapper obtainFromSupplier(Supplier<?> instanceSupplier, String be
11841166
* @see #obtainFromSupplier
11851167
*/
11861168
@Override
1187-
@Nullable
11881169
protected Object getObjectForBeanInstance(
1189-
@Nullable Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
1170+
Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
11901171

11911172
String currentlyCreatedBean = this.currentlyCreatedBean.get();
11921173
if (currentlyCreatedBean != null) {
@@ -1262,7 +1243,6 @@ protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefin
12621243
* @return a BeanWrapper for the new instance
12631244
* @see #getBean(String, Object[])
12641245
*/
1265-
@Nullable
12661246
protected BeanWrapper instantiateUsingFactoryMethod(
12671247
String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) {
12681248

@@ -1698,7 +1678,6 @@ private Object convertForProperty(Object value, String propertyName, BeanWrapper
16981678
* @see #invokeInitMethods
16991679
* @see #applyBeanPostProcessorsAfterInitialization
17001680
*/
1701-
@Nullable
17021681
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
17031682
if (System.getSecurityManager() != null) {
17041683
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
@@ -1715,18 +1694,16 @@ protected Object initializeBean(final String beanName, final Object bean, @Nulla
17151694
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
17161695
}
17171696

1718-
if (wrappedBean != null) {
1719-
try {
1720-
invokeInitMethods(beanName, wrappedBean, mbd);
1721-
}
1722-
catch (Throwable ex) {
1723-
throw new BeanCreationException(
1724-
(mbd != null ? mbd.getResourceDescription() : null),
1725-
beanName, "Invocation of init method failed", ex);
1726-
}
1727-
if (mbd == null || !mbd.isSynthetic()) {
1728-
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
1729-
}
1697+
try {
1698+
invokeInitMethods(beanName, wrappedBean, mbd);
1699+
}
1700+
catch (Throwable ex) {
1701+
throw new BeanCreationException(
1702+
(mbd != null ? mbd.getResourceDescription() : null),
1703+
beanName, "Invocation of init method failed", ex);
1704+
}
1705+
if (mbd == null || !mbd.isSynthetic()) {
1706+
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
17301707
}
17311708

17321709
return wrappedBean;

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

Lines changed: 9 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -380,9 +380,13 @@ else if (mbd.isPrototype()) {
380380
// corner cases, in particular in functional configuration and Kotlin scenarios.
381381
// A future Spring generation might eventually forbid null values completely
382382
// and throw IllegalStateExceptions instead of leniently passing them through.
383-
if (requiredType != null && bean != null && !requiredType.isInstance(bean)) {
383+
if (requiredType != null && !requiredType.isInstance(bean)) {
384384
try {
385-
return getTypeConverter().convertIfNecessary(bean, requiredType);
385+
T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
386+
if (convertedBean == null) {
387+
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
388+
}
389+
return convertedBean;
386390
}
387391
catch (TypeMismatchException ex) {
388392
if (logger.isDebugEnabled()) {
@@ -421,9 +425,6 @@ public boolean isSingleton(String name) throws NoSuchBeanDefinitionException {
421425
return !BeanFactoryUtils.isFactoryDereference(name);
422426
}
423427
}
424-
else if (containsSingleton(beanName)) {
425-
return true;
426-
}
427428

428429
// No singleton instance found -> check bean definition.
429430
BeanFactory parentBeanFactory = getParentBeanFactory();
@@ -496,7 +497,7 @@ public boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuc
496497

497498
// Check manually registered singletons.
498499
Object beanInstance = getSingleton(beanName, false);
499-
if (beanInstance != null) {
500+
if (beanInstance != null && beanInstance.getClass() != NullBean.class) {
500501
if (beanInstance instanceof FactoryBean) {
501502
if (!BeanFactoryUtils.isFactoryDereference(name)) {
502503
Class<?> type = getTypeForFactoryBean((FactoryBean<?>) beanInstance);
@@ -605,18 +606,14 @@ public Class<?> getType(String name) throws NoSuchBeanDefinitionException {
605606

606607
// Check manually registered singletons.
607608
Object beanInstance = getSingleton(beanName, false);
608-
if (beanInstance != null) {
609+
if (beanInstance != null && beanInstance.getClass() != NullBean.class) {
609610
if (beanInstance instanceof FactoryBean && !BeanFactoryUtils.isFactoryDereference(name)) {
610611
return getTypeForFactoryBean((FactoryBean<?>) beanInstance);
611612
}
612613
else {
613614
return beanInstance.getClass();
614615
}
615616
}
616-
else if (containsSingleton(beanName) && !containsBeanDefinition(beanName)) {
617-
// null instance registered
618-
return null;
619-
}
620617

621618
// No singleton instance found -> check bean definition.
622619
BeanFactory parentBeanFactory = getParentBeanFactory();
@@ -1014,10 +1011,6 @@ public boolean isFactoryBean(String name) throws NoSuchBeanDefinitionException {
10141011
if (beanInstance != null) {
10151012
return (beanInstance instanceof FactoryBean);
10161013
}
1017-
else if (containsSingleton(beanName)) {
1018-
// null instance registered
1019-
return false;
1020-
}
10211014

10221015
// No singleton instance found -> check bean definition.
10231016
if (!containsBeanDefinition(beanName) && getParentBeanFactory() instanceof ConfigurableBeanFactory) {
@@ -1631,13 +1624,8 @@ protected boolean hasBeanCreationStarted() {
16311624
* @param mbd the merged bean definition
16321625
* @return the object to expose for the bean
16331626
*/
1634-
@Nullable
16351627
protected Object getObjectForBeanInstance(
1636-
@Nullable Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
1637-
1638-
if (beanInstance == null) {
1639-
return null;
1640-
}
1628+
Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
16411629

16421630
// Don't let calling code try to dereference the factory if the bean isn't a factory.
16431631
if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {
@@ -1782,7 +1770,6 @@ protected void registerDisposableBeanIfNecessary(String beanName, Object bean, R
17821770
* @return a new instance of the bean
17831771
* @throws BeanCreationException if the bean could not be created
17841772
*/
1785-
@Nullable
17861773
protected abstract Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
17871774
throws BeanCreationException;
17881775

0 commit comments

Comments
 (0)