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
This commit is contained in:
Juergen Hoeller
2017-08-18 00:11:35 +02:00
parent 10dcaa9bf6
commit b94302b5bd
30 changed files with 344 additions and 204 deletions

View File

@@ -45,7 +45,6 @@ public interface ObjectFactory<T> {
* @return the resulting instance
* @throws BeansException in case of creation errors
*/
@Nullable
T getObject() throws BeansException;
}

View File

@@ -40,7 +40,6 @@ public interface ObjectProvider<T> extends ObjectFactory<T> {
* @throws BeansException in case of creation errors
* @see #getObject()
*/
@Nullable
T getObject(Object... args) throws BeansException;
/**

View File

@@ -725,7 +725,7 @@ public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBean
@Override
public Object resolveShortcut(BeanFactory beanFactory) {
return resolveCandidate(this.shortcut, this.requiredType, beanFactory);
return beanFactory.getBean(this.shortcut, this.requiredType);
}
}

View File

@@ -268,7 +268,6 @@ public interface AutowireCapableBeanFactory extends BeanFactory {
* @return the bean instance to use, either the original or a wrapped one
* @throws BeansException if the initialization failed
*/
@Nullable
Object initializeBean(Object existingBean, String beanName) throws BeansException;
/**
@@ -281,7 +280,6 @@ public interface AutowireCapableBeanFactory extends BeanFactory {
* @throws BeansException if any post-processing failed
* @see BeanPostProcessor#postProcessBeforeInitialization
*/
@Nullable
Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException;
@@ -295,7 +293,6 @@ public interface AutowireCapableBeanFactory extends BeanFactory {
* @throws BeansException if any post-processing failed
* @see BeanPostProcessor#postProcessAfterInitialization
*/
@Nullable
Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException;

View File

@@ -252,7 +252,7 @@ public class DependencyDescriptor extends InjectionPoint implements Serializable
public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFactory beanFactory)
throws BeansException {
return beanFactory.getBean(beanName, requiredType);
return beanFactory.getBean(beanName);
}

View File

@@ -87,7 +87,6 @@ public interface SmartInstantiationAwareBeanPostProcessor extends InstantiationA
* (typically with the passed-in bean instance as default)
* @throws org.springframework.beans.BeansException in case of errors
*/
@Nullable
default Object getEarlyBeanReference(Object bean, String beanName) throws BeansException {
return bean;
}

View File

@@ -410,37 +410,36 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
}
@Override
@Nullable
public Object initializeBean(Object existingBean, String beanName) {
return initializeBean(beanName, existingBean, null);
}
@Override
@Nullable
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
result = beanProcessor.postProcessBeforeInitialization(result, beanName);
if (result == null) {
return null;
Object current = beanProcessor.postProcessBeforeInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
@Override
@Nullable
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
result = beanProcessor.postProcessAfterInitialization(result, beanName);
if (result == null) {
return null;
Object current = beanProcessor.postProcessAfterInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
@@ -461,7 +460,6 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
* @see #doCreateBean
*/
@Override
@Nullable
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
@@ -535,7 +533,6 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
* @see #instantiateUsingFactoryMethod
* @see #autowireConstructor
*/
@Nullable
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
@@ -547,23 +544,23 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
mbd.resolvedTargetType = beanType;
final Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
if (beanType != null) {
// Allow post-processors to modify the merged bean definition.
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
// Allow post-processors to modify the merged bean definition.
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
}
}
@@ -583,9 +580,7 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
Object exposedObject = bean;
try {
populateBean(beanName, mbd, instanceWrapper);
if (exposedObject != null) {
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
@@ -624,15 +619,13 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
}
}
if (bean != null) {
// Register bean as disposable.
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
// Register bean as disposable.
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
return exposedObject;
@@ -904,17 +897,13 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
* @param bean the raw bean instance
* @return the object to expose as bean reference
*/
@Nullable
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, @Nullable Object bean) {
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (bean != null && !mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
if (exposedObject == null) {
return null;
}
}
}
}
@@ -954,9 +943,6 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
instance = resolveBeforeInstantiation(beanName, mbd);
if (instance == null) {
bw = createBeanInstance(beanName, mbd, null);
if (bw == null) {
return null;
}
instance = bw.getWrappedInstance();
}
}
@@ -995,9 +981,6 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
instance = resolveBeforeInstantiation(beanName, mbd);
if (instance == null) {
BeanWrapper bw = createBeanInstance(beanName, mbd, null);
if (bw == null) {
return null;
}
instance = bw.getWrappedInstance();
}
}
@@ -1097,7 +1080,6 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
* @see #autowireConstructor
* @see #instantiateBean
*/
@Nullable
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
// Make sure bean class is actually resolved at this point.
Class<?> beanClass = resolveBeanClass(mbd, beanName);
@@ -1184,9 +1166,8 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
* @see #obtainFromSupplier
*/
@Override
@Nullable
protected Object getObjectForBeanInstance(
@Nullable Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
String currentlyCreatedBean = this.currentlyCreatedBean.get();
if (currentlyCreatedBean != null) {
@@ -1262,7 +1243,6 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
* @return a BeanWrapper for the new instance
* @see #getBean(String, Object[])
*/
@Nullable
protected BeanWrapper instantiateUsingFactoryMethod(
String beanName, RootBeanDefinition mbd, @Nullable Object[] explicitArgs) {
@@ -1698,7 +1678,6 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
* @see #invokeInitMethods
* @see #applyBeanPostProcessorsAfterInitialization
*/
@Nullable
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
@@ -1715,18 +1694,16 @@ public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFac
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
if (wrappedBean != null) {
try {
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
try {
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;

View File

@@ -380,9 +380,13 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
// corner cases, in particular in functional configuration and Kotlin scenarios.
// A future Spring generation might eventually forbid null values completely
// and throw IllegalStateExceptions instead of leniently passing them through.
if (requiredType != null && bean != null && !requiredType.isInstance(bean)) {
if (requiredType != null && !requiredType.isInstance(bean)) {
try {
return getTypeConverter().convertIfNecessary(bean, requiredType);
T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
if (convertedBean == null) {
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
return convertedBean;
}
catch (TypeMismatchException ex) {
if (logger.isDebugEnabled()) {
@@ -421,9 +425,6 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
return !BeanFactoryUtils.isFactoryDereference(name);
}
}
else if (containsSingleton(beanName)) {
return true;
}
// No singleton instance found -> check bean definition.
BeanFactory parentBeanFactory = getParentBeanFactory();
@@ -496,7 +497,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
// Check manually registered singletons.
Object beanInstance = getSingleton(beanName, false);
if (beanInstance != null) {
if (beanInstance != null && beanInstance.getClass() != NullBean.class) {
if (beanInstance instanceof FactoryBean) {
if (!BeanFactoryUtils.isFactoryDereference(name)) {
Class<?> type = getTypeForFactoryBean((FactoryBean<?>) beanInstance);
@@ -605,7 +606,7 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
// Check manually registered singletons.
Object beanInstance = getSingleton(beanName, false);
if (beanInstance != null) {
if (beanInstance != null && beanInstance.getClass() != NullBean.class) {
if (beanInstance instanceof FactoryBean && !BeanFactoryUtils.isFactoryDereference(name)) {
return getTypeForFactoryBean((FactoryBean<?>) beanInstance);
}
@@ -613,10 +614,6 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
return beanInstance.getClass();
}
}
else if (containsSingleton(beanName) && !containsBeanDefinition(beanName)) {
// null instance registered
return null;
}
// No singleton instance found -> check bean definition.
BeanFactory parentBeanFactory = getParentBeanFactory();
@@ -1014,10 +1011,6 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
if (beanInstance != null) {
return (beanInstance instanceof FactoryBean);
}
else if (containsSingleton(beanName)) {
// null instance registered
return false;
}
// No singleton instance found -> check bean definition.
if (!containsBeanDefinition(beanName) && getParentBeanFactory() instanceof ConfigurableBeanFactory) {
@@ -1631,13 +1624,8 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
* @param mbd the merged bean definition
* @return the object to expose for the bean
*/
@Nullable
protected Object getObjectForBeanInstance(
@Nullable Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
if (beanInstance == null) {
return null;
}
Object beanInstance, String name, String beanName, @Nullable RootBeanDefinition mbd) {
// Don't let calling code try to dereference the factory if the bean isn't a factory.
if (BeanFactoryUtils.isFactoryDereference(name) && !(beanInstance instanceof FactoryBean)) {
@@ -1782,7 +1770,6 @@ public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport imp
* @return a new instance of the bean
* @throws BeanCreationException if the bean could not be created
*/
@Nullable
protected abstract Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException;

View File

@@ -205,6 +205,9 @@ class BeanDefinitionValueResolver {
"Error converting typed String value for " + argName, ex);
}
}
else if (value instanceof NullBean) {
return null;
}
else {
return evaluate(value);
}
@@ -309,12 +312,13 @@ class BeanDefinitionValueResolver {
Object innerBean = this.beanFactory.createBean(actualInnerBeanName, mbd, null);
if (innerBean instanceof FactoryBean) {
boolean synthetic = mbd.isSynthetic();
return this.beanFactory.getObjectFromFactoryBean(
innerBean = this.beanFactory.getObjectFromFactoryBean(
(FactoryBean<?>) innerBean, actualInnerBeanName, !synthetic);
}
else {
return innerBean;
if (innerBean instanceof NullBean) {
innerBean = null;
}
return innerBean;
}
catch (BeansException ex) {
throw new BeanCreationException(
@@ -344,8 +348,10 @@ class BeanDefinitionValueResolver {
/**
* Resolve a reference to another bean in the factory.
*/
@Nullable
private Object resolveReference(Object argName, RuntimeBeanReference ref) {
try {
Object bean;
String refName = ref.getBeanName();
refName = String.valueOf(doEvaluate(refName));
if (ref.isToParent()) {
@@ -355,13 +361,16 @@ class BeanDefinitionValueResolver {
"Can't resolve reference to bean '" + refName +
"' in parent factory: no parent factory available");
}
return this.beanFactory.getParentBeanFactory().getBean(refName);
bean = this.beanFactory.getParentBeanFactory().getBean(refName);
}
else {
Object bean = this.beanFactory.getBean(refName);
bean = this.beanFactory.getBean(refName);
this.beanFactory.registerDependentBean(refName, this.beanName);
return bean;
}
if (bean instanceof NullBean) {
bean = null;
}
return bean;
}
catch (BeansException ex) {
throw new BeanCreationException(

View File

@@ -348,7 +348,6 @@ class ConstructorResolver {
* method, or {@code null} if none (-> use constructor argument values from bean definition)
* @return a BeanWrapper for the new instance
*/
@Nullable
public BeanWrapper instantiateUsingFactoryMethod(
final String beanName, final RootBeanDefinition mbd, @Nullable final Object[] explicitArgs) {
@@ -576,9 +575,6 @@ class ConstructorResolver {
mbd, beanName, this.beanFactory, factoryBean, factoryMethodToUse, argsToUse);
}
if (beanInstance == null) {
return null;
}
bw.setBeanInstance(beanInstance);
return bw;
}

View File

@@ -1129,14 +1129,27 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
if (autowiredBeanNames != null) {
autowiredBeanNames.add(autowiredBeanName);
}
return (instanceCandidate instanceof Class ?
descriptor.resolveCandidate(autowiredBeanName, type, this) : instanceCandidate);
if (instanceCandidate instanceof Class) {
instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
}
Object result = instanceCandidate;
if (result instanceof NullBean) {
if (isRequired(descriptor)) {
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}
result = null;
}
if (!ClassUtils.isAssignableValue(type, result)) {
throw new BeanNotOfRequiredTypeException(autowiredBeanName, type, instanceCandidate.getClass());
}
return result;
}
finally {
ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
}
}
@Nullable
private Object resolveMultipleBeans(DependencyDescriptor descriptor, @Nullable String beanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) {
@@ -1500,7 +1513,8 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
isAutowireCandidate(beanName, mbd, descriptor, getAutowireCandidateResolver())) {
// Probably a proxy interfering with target type match -> throw meaningful exception.
Object beanInstance = getSingleton(beanName, false);
Class<?> beanType = (beanInstance != null ? beanInstance.getClass() : predictBeanType(beanName, mbd));
Class<?> beanType = (beanInstance != null && beanInstance.getClass() != NullBean.class) ?
beanInstance.getClass() : predictBeanType(beanName, mbd);
if (beanType != null && !type.isAssignableFrom(beanType)) {
throw new BeanNotOfRequiredTypeException(beanName, type, beanType);
}
@@ -1526,7 +1540,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
}
@Override
public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFactory beanFactory) {
return (!ObjectUtils.isEmpty(args) ? beanFactory.getBean(beanName, requiredType, args) :
return (!ObjectUtils.isEmpty(args) ? beanFactory.getBean(beanName, args) :
super.resolveCandidate(beanName, requiredType, beanFactory));
}
};
@@ -1615,18 +1629,20 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
}
@Override
@Nullable
public Object getObject() throws BeansException {
if (this.optional) {
return createOptionalDependency(this.descriptor, this.beanName);
}
else {
return doResolveDependency(this.descriptor, this.beanName, null, null);
Object result = doResolveDependency(this.descriptor, this.beanName, null, null);
if (result == null) {
throw new NoSuchBeanDefinitionException(this.descriptor.getResolvableType());
}
return result;
}
}
@Override
@Nullable
public Object getObject(final Object... args) throws BeansException {
if (this.optional) {
return createOptionalDependency(this.descriptor, this.beanName, args);
@@ -1635,10 +1651,14 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
DependencyDescriptor descriptorToUse = new DependencyDescriptor(descriptor) {
@Override
public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFactory beanFactory) {
return ((AbstractBeanFactory) beanFactory).getBean(beanName, requiredType, args);
return beanFactory.getBean(beanName, args);
}
};
return doResolveDependency(descriptorToUse, this.beanName, null, null);
Object result = doResolveDependency(descriptorToUse, this.beanName, null, null);
if (result == null) {
throw new NoSuchBeanDefinitionException(this.descriptor.getResolvableType());
}
return result;
}
}
@@ -1680,6 +1700,16 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
return doResolveDependency(descriptorToUse, this.beanName, null, null);
}
}
@Nullable
protected Object getValue() throws BeansException {
if (this.optional) {
return createOptionalDependency(this.descriptor, this.beanName);
}
else {
return doResolveDependency(this.descriptor, this.beanName, null, null);
}
}
}
@@ -1695,7 +1725,7 @@ public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFacto
@Override
@Nullable
public Object get() throws BeansException {
return getObject();
return getValue();
}
}

View File

@@ -73,13 +73,6 @@ import org.springframework.util.StringUtils;
*/
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
/**
* Internal marker for a null singleton object:
* used as marker value for concurrent Maps (which don't support null values).
*/
protected static final Object NULL_OBJECT = new Object();
/** Logger available to subclasses */
protected final Log logger = LogFactory.getLog(getClass());
@@ -125,7 +118,8 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements
@Override
public void registerSingleton(String beanName, Object singletonObject) throws IllegalStateException {
Assert.notNull(beanName, "'beanName' must not be null");
Assert.notNull(beanName, "Bean name must not be null");
Assert.notNull(singletonObject, "Singleton object must not be null");
synchronized (this.singletonObjects) {
Object oldObject = this.singletonObjects.get(beanName);
if (oldObject != null) {
@@ -142,9 +136,9 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements
* @param beanName the name of the bean
* @param singletonObject the singleton object
*/
protected void addSingleton(String beanName, @Nullable Object singletonObject) {
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
this.singletonObjects.put(beanName, (singletonObject != null ? singletonObject : NULL_OBJECT));
this.singletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
@@ -200,7 +194,7 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements
}
}
}
return (singletonObject != NULL_OBJECT ? singletonObject : null);
return singletonObject;
}
/**
@@ -211,9 +205,8 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements
* with, if necessary
* @return the registered singleton object
*/
@Nullable
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "'beanName' must not be null");
Assert.notNull(beanName, "Bean name must not be null");
synchronized (this.singletonObjects) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
@@ -261,7 +254,7 @@ public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements
addSingleton(beanName, singletonObject);
}
}
return (singletonObject != NULL_OBJECT ? singletonObject : null);
return singletonObject;
}
}

View File

@@ -81,8 +81,7 @@ public abstract class FactoryBeanRegistrySupport extends DefaultSingletonBeanReg
*/
@Nullable
protected Object getCachedObjectForFactoryBean(String beanName) {
Object object = this.factoryBeanObjectCache.get(beanName);
return (object != NULL_OBJECT ? object : null);
return this.factoryBeanObjectCache.get(beanName);
}
/**
@@ -94,7 +93,6 @@ public abstract class FactoryBeanRegistrySupport extends DefaultSingletonBeanReg
* @throws BeanCreationException if FactoryBean object creation failed
* @see org.springframework.beans.factory.FactoryBean#getObject()
*/
@Nullable
protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
if (factory.isSingleton() && containsSingleton(beanName)) {
synchronized (getSingletonMutex()) {
@@ -108,7 +106,7 @@ public abstract class FactoryBeanRegistrySupport extends DefaultSingletonBeanReg
object = alreadyThere;
}
else {
if (object != null && shouldPostProcess) {
if (shouldPostProcess) {
try {
object = postProcessObjectFromFactoryBean(object, beanName);
}
@@ -117,15 +115,15 @@ public abstract class FactoryBeanRegistrySupport extends DefaultSingletonBeanReg
"Post-processing of FactoryBean's singleton object failed", ex);
}
}
this.factoryBeanObjectCache.put(beanName, (object != null ? object : NULL_OBJECT));
this.factoryBeanObjectCache.put(beanName, object);
}
}
return (object != NULL_OBJECT ? object : null);
return object;
}
}
else {
Object object = doGetObjectFromFactoryBean(factory, beanName);
if (object != null && shouldPostProcess) {
if (shouldPostProcess) {
try {
object = postProcessObjectFromFactoryBean(object, beanName);
}
@@ -145,7 +143,6 @@ public abstract class FactoryBeanRegistrySupport extends DefaultSingletonBeanReg
* @throws BeanCreationException if FactoryBean object creation failed
* @see org.springframework.beans.factory.FactoryBean#getObject()
*/
@Nullable
private Object doGetObjectFromFactoryBean(final FactoryBean<?> factory, final String beanName)
throws BeanCreationException {
@@ -174,9 +171,12 @@ public abstract class FactoryBeanRegistrySupport extends DefaultSingletonBeanReg
// Do not accept a null value for a FactoryBean that's not fully
// initialized yet: Many FactoryBeans just return null then.
if (object == null && isSingletonCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(
beanName, "FactoryBean which is currently in creation returned null from getObject");
if (object == null) {
if (isSingletonCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(
beanName, "FactoryBean which is currently in creation returned null from getObject");
}
object = new NullBean();
}
return object;
}
@@ -191,7 +191,6 @@ public abstract class FactoryBeanRegistrySupport extends DefaultSingletonBeanReg
* @return the object to expose
* @throws org.springframework.beans.BeansException if any post-processing failed
*/
@Nullable
protected Object postProcessObjectFromFactoryBean(Object object, String beanName) throws BeansException {
return object;
}

View File

@@ -0,0 +1,57 @@
/*
* Copyright 2002-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.beans.factory.support;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.lang.Nullable;
/**
* Internal representation of a null bean instance, e.g. for a {@code null} value
* returned from {@link FactoryBean#getObject()} or from a factory method.
*
* <p>Each such null bean is represented by a dedicated {@code NullBean} instance
* which are not equal to each other, uniquely differentiating each bean as returned
* from all variants of {@link org.springframework.beans.factory.BeanFactory#getBean}.
* However, each such instance will return {@code true} for {@code #equals(null)}
* and returns "null" from {@code #toString()}, which is how they can be tested
* externally (since this class itself is not public).
*
* @author Juergen Hoeller
* @since 5.0
*/
final class NullBean {
NullBean() {
}
@Override
public boolean equals(@Nullable Object obj) {
return (this == obj || obj == null);
}
@Override
public int hashCode() {
return NullBean.class.hashCode();
}
@Override
public String toString() {
return "null";
}
}

View File

@@ -152,7 +152,11 @@ public class SimpleInstantiationStrategy implements InstantiationStrategy {
Method priorInvokedFactoryMethod = currentlyInvokedFactoryMethod.get();
try {
currentlyInvokedFactoryMethod.set(factoryMethod);
return factoryMethod.invoke(factoryBean, args);
Object result = factoryMethod.invoke(factoryBean, args);
if (result == null) {
result = new NullBean();
}
return result;
}
finally {
if (priorInvokedFactoryMethod != null) {