diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/ObjectFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/ObjectFactory.java index c92456f650..85d4806a55 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/ObjectFactory.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/ObjectFactory.java @@ -45,7 +45,6 @@ public interface ObjectFactory { * @return the resulting instance * @throws BeansException in case of creation errors */ - @Nullable T getObject() throws BeansException; } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/ObjectProvider.java b/spring-beans/src/main/java/org/springframework/beans/factory/ObjectProvider.java index 9fd5736416..de71971894 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/ObjectProvider.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/ObjectProvider.java @@ -40,7 +40,6 @@ public interface ObjectProvider extends ObjectFactory { * @throws BeansException in case of creation errors * @see #getObject() */ - @Nullable T getObject(Object... args) throws BeansException; /** diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java index 3c25657135..a3339b3f82 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java @@ -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); } } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/config/AutowireCapableBeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/config/AutowireCapableBeanFactory.java index 1a43bb9bfd..9facb43e18 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/config/AutowireCapableBeanFactory.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/config/AutowireCapableBeanFactory.java @@ -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; diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/config/DependencyDescriptor.java b/spring-beans/src/main/java/org/springframework/beans/factory/config/DependencyDescriptor.java index 24e8802346..4682f41142 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/config/DependencyDescriptor.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/config/DependencyDescriptor.java @@ -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); } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/config/SmartInstantiationAwareBeanPostProcessor.java b/spring-beans/src/main/java/org/springframework/beans/factory/config/SmartInstantiationAwareBeanPostProcessor.java index 4cae579140..5d52fae329 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/config/SmartInstantiationAwareBeanPostProcessor.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/config/SmartInstantiationAwareBeanPostProcessor.java @@ -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; } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java index 40270cb502..366663514c 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java @@ -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) () -> { @@ -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; diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java index a55b541655..7af742a9c0 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractBeanFactory.java @@ -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; diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/BeanDefinitionValueResolver.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/BeanDefinitionValueResolver.java index 1ed60c804d..5d0c0e5e13 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/BeanDefinitionValueResolver.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/BeanDefinitionValueResolver.java @@ -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( diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/ConstructorResolver.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/ConstructorResolver.java index b48380d5af..aefb66f89f 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/ConstructorResolver.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/ConstructorResolver.java @@ -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; } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java index 03ff2b76df..1cf6b17ff5 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java @@ -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 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(); } } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultSingletonBeanRegistry.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultSingletonBeanRegistry.java index 62a0105e30..bbafc653fa 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultSingletonBeanRegistry.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultSingletonBeanRegistry.java @@ -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; } } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/FactoryBeanRegistrySupport.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/FactoryBeanRegistrySupport.java index 1066165c52..b346d02bb1 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/FactoryBeanRegistrySupport.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/FactoryBeanRegistrySupport.java @@ -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; } diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/NullBean.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/NullBean.java new file mode 100644 index 0000000000..254af8fa87 --- /dev/null +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/NullBean.java @@ -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. + * + *

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"; + } + +} diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/support/SimpleInstantiationStrategy.java b/spring-beans/src/main/java/org/springframework/beans/factory/support/SimpleInstantiationStrategy.java index 1fd0e8126d..fecdb77eff 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/support/SimpleInstantiationStrategy.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/support/SimpleInstantiationStrategy.java @@ -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) { diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/FactoryBeanTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/FactoryBeanTests.java index d954534829..2c2754a911 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/FactoryBeanTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/FactoryBeanTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * 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. @@ -51,8 +51,8 @@ public class FactoryBeanTests { public void testFactoryBeanReturnsNull() throws Exception { DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); new XmlBeanDefinitionReader(factory).loadBeanDefinitions(RETURNS_NULL_CONTEXT); - Object result = factory.getBean("factoryBean"); - assertNull(result); + + assertEquals("null", factory.getBean("factoryBean").toString()); } @Test diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessorTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessorTests.java index 08d3c8587f..2be178a41c 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessorTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessorTests.java @@ -572,8 +572,9 @@ public class AutowiredAnnotationBeanPostProcessorTests { } @Test - public void testConstructorResourceInjectionWithNull() { + public void testConstructorResourceInjectionWithNullFromFactoryBean() { DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + bf.setAutowireCandidateResolver(new QualifierAnnotationAutowireCandidateResolver()); bf.registerResolvableDependency(BeanFactory.class, bf); AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor(); bpp.setBeanFactory(bf); @@ -603,6 +604,42 @@ public class AutowiredAnnotationBeanPostProcessorTests { assertSame(bf, bean.getBeanFactory()); } + @Test + public void testConstructorResourceInjectionWithNullFromFactoryMethod() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + bf.setAutowireCandidateResolver(new QualifierAnnotationAutowireCandidateResolver()); + bf.registerResolvableDependency(BeanFactory.class, bf); + AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor(); + bpp.setBeanFactory(bf); + bf.addBeanPostProcessor(bpp); + RootBeanDefinition bd = new RootBeanDefinition(ConstructorResourceInjectionBean.class); + bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE); + bf.registerBeanDefinition("annotatedBean", bd); + RootBeanDefinition tb = new RootBeanDefinition(NullFactoryMethods.class); + tb.setFactoryMethodName("createTestBean"); + bf.registerBeanDefinition("testBean", tb); + RootBeanDefinition ntb = new RootBeanDefinition(NullFactoryMethods.class); + ntb.setFactoryMethodName("createNestedTestBean"); + bf.registerBeanDefinition("nestedTestBean", ntb); + bf.registerSingleton("nestedTestBean2", new NestedTestBean()); + + ConstructorResourceInjectionBean bean = (ConstructorResourceInjectionBean) bf.getBean("annotatedBean"); + assertNull(bean.getTestBean()); + assertNull(bean.getTestBean2()); + assertNull(bean.getTestBean3()); + assertNull(bean.getTestBean4()); + assertNull(bean.getNestedTestBean()); + assertSame(bf, bean.getBeanFactory()); + + bean = (ConstructorResourceInjectionBean) bf.getBean("annotatedBean"); + assertNull(bean.getTestBean()); + assertNull(bean.getTestBean2()); + assertNull(bean.getTestBean3()); + assertNull(bean.getTestBean4()); + assertNull(bean.getNestedTestBean()); + assertSame(bf, bean.getBeanFactory()); + } + @Test public void testConstructorResourceInjectionWithMultipleCandidates() { DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); @@ -756,6 +793,33 @@ public class AutowiredAnnotationBeanPostProcessorTests { bf.destroySingletons(); } + @Test(expected = UnsatisfiedDependencyException.class) + public void testSingleConstructorInjectionWithMissingDependency() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + bf.setAutowireCandidateResolver(new QualifierAnnotationAutowireCandidateResolver()); + AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor(); + bpp.setBeanFactory(bf); + bf.addBeanPostProcessor(bpp); + bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(SingleConstructorCollectionInjectionBean.class)); + + bf.getBean("annotatedBean"); + } + + @Test(expected = UnsatisfiedDependencyException.class) + public void testSingleConstructorInjectionWithNullDependency() { + DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); + bf.setAutowireCandidateResolver(new QualifierAnnotationAutowireCandidateResolver()); + AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor(); + bpp.setBeanFactory(bf); + bf.addBeanPostProcessor(bpp); + bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(SingleConstructorCollectionInjectionBean.class)); + RootBeanDefinition tb = new RootBeanDefinition(NullFactoryMethods.class); + tb.setFactoryMethodName("createTestBean"); + bf.registerBeanDefinition("testBean", tb); + + bf.getBean("annotatedBean"); + } + @Test public void testConstructorResourceInjectionWithMultipleCandidatesAndFallback() { DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); @@ -2634,7 +2698,7 @@ public class AutowiredAnnotationBeanPostProcessorTests { public static class ConstructorResourceInjectionBean extends ResourceInjectionBean { - @Autowired + @Autowired(required = false) protected ITestBean testBean3; private ITestBean testBean4; @@ -2643,7 +2707,6 @@ public class AutowiredAnnotationBeanPostProcessorTests { private ConfigurableListableBeanFactory beanFactory; - public ConstructorResourceInjectionBean() { throw new UnsupportedOperationException(); } @@ -2653,7 +2716,8 @@ public class AutowiredAnnotationBeanPostProcessorTests { } @Autowired - public ConstructorResourceInjectionBean(ITestBean testBean4, NestedTestBean nestedTestBean, + public ConstructorResourceInjectionBean(@Autowired(required = false) ITestBean testBean4, + @Autowired(required = false) NestedTestBean nestedTestBean, ConfigurableListableBeanFactory beanFactory) { this.testBean4 = testBean4; this.nestedTestBean = nestedTestBean; @@ -2669,7 +2733,7 @@ public class AutowiredAnnotationBeanPostProcessorTests { } @Override - @Autowired + @Autowired(required = false) public void setTestBean2(TestBean testBean2) { super.setTestBean2(testBean2); } @@ -3802,6 +3866,18 @@ public class AutowiredAnnotationBeanPostProcessorTests { } + public static class NullFactoryMethods { + + public static TestBean createTestBean() { + return null; + } + + public static NestedTestBean createNestedTestBean() { + return null; + } + } + + public static class ProvidedArgumentBean { public ProvidedArgumentBean(String[] args) { diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/config/PropertyPathFactoryBeanTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/config/PropertyPathFactoryBeanTests.java index f50cd07242..5aaf05bdb8 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/config/PropertyPathFactoryBeanTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/config/PropertyPathFactoryBeanTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * 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. @@ -38,6 +38,7 @@ public class PropertyPathFactoryBeanTests { private static final Resource CONTEXT = qualifiedResource(PropertyPathFactoryBeanTests.class, "context.xml"); + @Test public void testPropertyPathFactoryBeanWithSingletonResult() { DefaultListableBeanFactory xbf = new DefaultListableBeanFactory(); @@ -78,7 +79,7 @@ public class PropertyPathFactoryBeanTests { DefaultListableBeanFactory xbf = new DefaultListableBeanFactory(); new XmlBeanDefinitionReader(xbf).loadBeanDefinitions(CONTEXT); assertNull(xbf.getType("tb.spouse.spouse")); - assertNull(xbf.getBean("tb.spouse.spouse")); + assertEquals("null", xbf.getBean("tb.spouse.spouse").toString()); } @Test @@ -92,4 +93,18 @@ public class PropertyPathFactoryBeanTests { assertSame(spouse, tbWithInner.getFriends().iterator().next()); } + @Test + public void testPropertyPathFactoryBeanAsNullReference() { + DefaultListableBeanFactory xbf = new DefaultListableBeanFactory(); + new XmlBeanDefinitionReader(xbf).loadBeanDefinitions(CONTEXT); + assertNull(xbf.getBean("tbWithNullReference", TestBean.class).getSpouse()); + } + + @Test + public void testPropertyPathFactoryBeanAsInnerNull() { + DefaultListableBeanFactory xbf = new DefaultListableBeanFactory(); + new XmlBeanDefinitionReader(xbf).loadBeanDefinitions(CONTEXT); + assertNull(xbf.getBean("tbWithInnerNull", TestBean.class).getSpouse()); + } + } diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/xml/FactoryMethodTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/xml/FactoryMethodTests.java index a27e13a6d2..42279ded04 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/xml/FactoryMethodTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/xml/FactoryMethodTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2014 the original author or authors. + * 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. @@ -91,8 +91,7 @@ public class FactoryMethodTests { XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(xbf); reader.loadBeanDefinitions(new ClassPathResource("factory-methods.xml", getClass())); - FactoryMethods fm = (FactoryMethods) xbf.getBean("null"); - assertNull(fm); + assertEquals("null", xbf.getBean("null").toString()); try { xbf.getBean("nullWithProperty"); diff --git a/spring-beans/src/test/resources/org/springframework/beans/factory/config/PropertyPathFactoryBeanTests-context.xml b/spring-beans/src/test/resources/org/springframework/beans/factory/config/PropertyPathFactoryBeanTests-context.xml index 5dfa450fe2..bc9234d1c3 100644 --- a/spring-beans/src/test/resources/org/springframework/beans/factory/config/PropertyPathFactoryBeanTests-context.xml +++ b/spring-beans/src/test/resources/org/springframework/beans/factory/config/PropertyPathFactoryBeanTests-context.xml @@ -57,6 +57,16 @@ - + + + + + + + + + + + diff --git a/spring-context/src/main/java/org/springframework/cache/support/NullValue.java b/spring-context/src/main/java/org/springframework/cache/support/NullValue.java index 3e8337991e..249c6fe56a 100644 --- a/spring-context/src/main/java/org/springframework/cache/support/NullValue.java +++ b/spring-context/src/main/java/org/springframework/cache/support/NullValue.java @@ -18,6 +18,8 @@ package org.springframework.cache.support; import java.io.Serializable; +import org.springframework.lang.Nullable; + /** * Simple serializable class that serves as a {@code null} replacement * for cache stores which otherwise do not support {@code null} values. @@ -46,4 +48,20 @@ public final class NullValue implements Serializable { return INSTANCE; } + + @Override + public boolean equals(@Nullable Object obj) { + return (this == obj || obj == null); + } + + @Override + public int hashCode() { + return NullValue.class.hashCode(); + } + + @Override + public String toString() { + return "null"; + } + } diff --git a/spring-context/src/main/java/org/springframework/context/support/SimpleThreadScope.java b/spring-context/src/main/java/org/springframework/context/support/SimpleThreadScope.java index 6101de2a10..dcee976ecf 100644 --- a/spring-context/src/main/java/org/springframework/context/support/SimpleThreadScope.java +++ b/spring-context/src/main/java/org/springframework/context/support/SimpleThreadScope.java @@ -72,7 +72,6 @@ public class SimpleThreadScope implements Scope { Object scopedObject = scope.get(name); if (scopedObject == null) { scopedObject = objectFactory.getObject(); - Assert.state(scopedObject != null, "Scoped object resolved to null"); scope.put(name, scopedObject); } return scopedObject; diff --git a/spring-context/src/main/java/org/springframework/jmx/export/MBeanExporter.java b/spring-context/src/main/java/org/springframework/jmx/export/MBeanExporter.java index a5825c8fa0..14c5ea1eb9 100644 --- a/spring-context/src/main/java/org/springframework/jmx/export/MBeanExporter.java +++ b/spring-context/src/main/java/org/springframework/jmx/export/MBeanExporter.java @@ -508,7 +508,7 @@ public class MBeanExporter extends MBeanRegistrationSupport implements MBeanExpo //--------------------------------------------------------------------- /** - * Registers the defined beans with the {@link MBeanServer}. + * Register the defined beans with the {@link MBeanServer}. *

Each bean is exposed to the {@code MBeanServer} via a * {@code ModelMBean}. The actual implemetation of the * {@code ModelMBean} interface used depends on the implementation of @@ -566,7 +566,7 @@ public class MBeanExporter extends MBeanRegistrationSupport implements MBeanExpo } /** - * Registers an individual bean with the {@link #setServer MBeanServer}. + * Register an individual bean with the {@link #setServer MBeanServer}. *

This method is responsible for deciding how a bean * should be exposed to the {@code MBeanServer}. Specifically, if the * supplied {@code mapValue} is the name of a bean that is configured @@ -579,15 +579,13 @@ public class MBeanExporter extends MBeanRegistrationSupport implements MBeanExpo * @param mapValue the value configured for this bean in the beans map; * may be either the {@code String} name of a bean, or the bean itself * @param beanKey the key associated with this bean in the beans map - * @return the {@code ObjectName} under which the resource was registered, - * or {@code null} if the actual resource was {@code null} as well + * @return the {@code ObjectName} under which the resource was registered * @throws MBeanExportException if the export failed * @see #setBeans * @see #registerBeanInstance * @see #registerLazyInit */ - @Nullable - protected ObjectName registerBeanNameOrInstance(@Nullable Object mapValue, String beanKey) throws MBeanExportException { + protected ObjectName registerBeanNameOrInstance(Object mapValue, String beanKey) throws MBeanExportException { try { if (mapValue instanceof String) { // Bean name pointing to a potentially lazy-init bean in the factory. @@ -607,7 +605,7 @@ public class MBeanExporter extends MBeanRegistrationSupport implements MBeanExpo return objectName; } } - else if (mapValue != null) { + else { // Plain bean instance -> register it directly. if (this.beanFactory != null) { Map beansOfSameType = @@ -623,9 +621,6 @@ public class MBeanExporter extends MBeanRegistrationSupport implements MBeanExpo } return registerBeanInstance(mapValue, beanKey); } - else { - return null; - } } catch (Throwable ex) { throw new UnableToRegisterMBeanException( @@ -634,14 +629,14 @@ public class MBeanExporter extends MBeanRegistrationSupport implements MBeanExpo } /** - * Replaces any bean names used as keys in the {@code NotificationListener} + * Replace any bean names used as keys in the {@code NotificationListener} * mappings with their corresponding {@code ObjectName} values. * @param beanName the name of the bean to be registered * @param objectName the {@code ObjectName} under which the bean will be registered * with the {@code MBeanServer} */ - private void replaceNotificationListenerBeanNameKeysIfNecessary(String beanName, @Nullable ObjectName objectName) { - if (objectName != null && this.notificationListeners != null) { + private void replaceNotificationListenerBeanNameKeysIfNecessary(String beanName, ObjectName objectName) { + if (this.notificationListeners != null) { for (NotificationListenerBean notificationListener : this.notificationListeners) { notificationListener.replaceObjectName(beanName, objectName); } @@ -656,12 +651,7 @@ public class MBeanExporter extends MBeanRegistrationSupport implements MBeanExpo * @return the {@code ObjectName} under which the bean was registered * with the {@code MBeanServer} */ - @Nullable - private ObjectName registerBeanInstance(@Nullable Object bean, String beanKey) throws JMException { - if (bean == null) { - return null; - } - + private ObjectName registerBeanInstance(Object bean, String beanKey) throws JMException { ObjectName objectName = getObjectName(bean, beanKey); Object mbeanToExpose = null; if (isMBean(bean.getClass())) { @@ -695,7 +685,7 @@ public class MBeanExporter extends MBeanRegistrationSupport implements MBeanExpo } /** - * Registers beans that are configured for lazy initialization with the + * Register beans that are configured for lazy initialization with the * {@code MBeanServer} indirectly through a proxy. * @param beanName the name of the bean in the {@code BeanFactory} * @param beanKey the key associated with this bean in the beans map @@ -890,7 +880,13 @@ public class MBeanExporter extends MBeanRegistrationSupport implements MBeanExpo Class beanClass = this.beanFactory.getType(beanName); if (beanClass != null && callback.include(beanClass, beanName)) { boolean lazyInit = isBeanDefinitionLazyInit(this.beanFactory, beanName); - Object beanInstance = (!lazyInit ? this.beanFactory.getBean(beanName) : null); + Object beanInstance = null; + if (!lazyInit) { + beanInstance = this.beanFactory.getBean(beanName); + if (!beanClass.isInstance(beanInstance)) { + continue; + } + } if (!ScopedProxyUtils.isScopedTarget(beanName) && !beans.containsValue(beanName) && (beanInstance == null || !CollectionUtils.containsInstance(beans.values(), beanInstance))) { diff --git a/spring-context/src/test/java/org/springframework/cache/interceptor/CacheResolverCustomizationTests.java b/spring-context/src/test/java/org/springframework/cache/interceptor/CacheResolverCustomizationTests.java index db330ce19d..ba9982ba65 100644 --- a/spring-context/src/test/java/org/springframework/cache/interceptor/CacheResolverCustomizationTests.java +++ b/spring-context/src/test/java/org/springframework/cache/interceptor/CacheResolverCustomizationTests.java @@ -58,14 +58,14 @@ public class CacheResolverCustomizationTests { @Before - public void setUp() { + public void setup() { ApplicationContext context = new AnnotationConfigApplicationContext(Config.class); this.cacheManager = context.getBean("cacheManager", CacheManager.class); this.anotherCacheManager = context.getBean("anotherCacheManager", CacheManager.class); - this.simpleService = context.getBean(SimpleService.class); } + @Test public void noCustomization() { Cache cache = this.cacheManager.getCache("default"); @@ -162,12 +162,6 @@ public class CacheResolverCustomizationTests { return CacheTestUtils.createSimpleCacheManager("default", "primary", "secondary"); } - @Override - @Bean - public KeyGenerator keyGenerator() { - return null; - } - @Bean public CacheManager anotherCacheManager() { return CacheTestUtils.createSimpleCacheManager("default", "primary", "secondary"); diff --git a/spring-context/src/test/java/org/springframework/context/annotation/CommonAnnotationBeanPostProcessorTests.java b/spring-context/src/test/java/org/springframework/context/annotation/CommonAnnotationBeanPostProcessorTests.java index 2dfd1ef095..8da452bbcd 100644 --- a/spring-context/src/test/java/org/springframework/context/annotation/CommonAnnotationBeanPostProcessorTests.java +++ b/spring-context/src/test/java/org/springframework/context/annotation/CommonAnnotationBeanPostProcessorTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2015 the original author or authors. + * 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. @@ -114,7 +114,7 @@ public class CommonAnnotationBeanPostProcessorTests { rbd.setFactoryMethodName("create"); bf.registerBeanDefinition("bean", rbd); - assertNull(bf.getBean("bean")); + assertEquals("null", bf.getBean("bean").toString()); bf.destroySingletons(); } diff --git a/spring-context/src/test/java/org/springframework/context/support/GenericApplicationContextTests.java b/spring-context/src/test/java/org/springframework/context/support/GenericApplicationContextTests.java index 0e1512df9c..6a42e68062 100644 --- a/spring-context/src/test/java/org/springframework/context/support/GenericApplicationContextTests.java +++ b/spring-context/src/test/java/org/springframework/context/support/GenericApplicationContextTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2016 the original author or authors. + * 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. @@ -30,13 +30,6 @@ import static org.junit.Assert.*; */ public class GenericApplicationContextTests { - @Test - public void nullBeanRegistration() { - DefaultListableBeanFactory bf = new DefaultListableBeanFactory(); - bf.registerSingleton("nullBean", null); - new GenericApplicationContext(bf).refresh(); - } - @Test public void getBeanForClass() { GenericApplicationContext ac = new GenericApplicationContext(); diff --git a/spring-messaging/src/main/java/org/springframework/messaging/simp/SimpSessionScope.java b/spring-messaging/src/main/java/org/springframework/messaging/simp/SimpSessionScope.java index cf304368ab..a7128b756b 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/simp/SimpSessionScope.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/simp/SimpSessionScope.java @@ -19,7 +19,6 @@ package org.springframework.messaging.simp; import org.springframework.beans.factory.ObjectFactory; import org.springframework.beans.factory.config.Scope; import org.springframework.lang.Nullable; -import org.springframework.util.Assert; /** * A {@link Scope} implementation exposing the attributes of a SiMP session @@ -44,7 +43,6 @@ public class SimpSessionScope implements Scope { scopedObject = simpAttributes.getAttribute(name); if (scopedObject == null) { scopedObject = objectFactory.getObject(); - Assert.state(scopedObject != null, "Scoped object resolved to null"); simpAttributes.setAttribute(name, scopedObject); } return scopedObject; diff --git a/spring-tx/src/main/java/org/springframework/transaction/support/SimpleTransactionScope.java b/spring-tx/src/main/java/org/springframework/transaction/support/SimpleTransactionScope.java index e51030a52b..a012763e70 100644 --- a/spring-tx/src/main/java/org/springframework/transaction/support/SimpleTransactionScope.java +++ b/spring-tx/src/main/java/org/springframework/transaction/support/SimpleTransactionScope.java @@ -54,7 +54,6 @@ public class SimpleTransactionScope implements Scope { Object scopedObject = scopedObjects.scopedInstances.get(name); if (scopedObject == null) { scopedObject = objectFactory.getObject(); - Assert.state(scopedObject != null, "Scoped object resolved to null"); scopedObjects.scopedInstances.put(name, scopedObject); } return scopedObject; diff --git a/spring-web/src/main/java/org/springframework/web/context/request/AbstractRequestAttributesScope.java b/spring-web/src/main/java/org/springframework/web/context/request/AbstractRequestAttributesScope.java index 0a16dee7e5..368e63cf65 100644 --- a/spring-web/src/main/java/org/springframework/web/context/request/AbstractRequestAttributesScope.java +++ b/spring-web/src/main/java/org/springframework/web/context/request/AbstractRequestAttributesScope.java @@ -19,7 +19,6 @@ package org.springframework.web.context.request; import org.springframework.beans.factory.ObjectFactory; import org.springframework.beans.factory.config.Scope; import org.springframework.lang.Nullable; -import org.springframework.util.Assert; /** * Abstract {@link Scope} implementation that reads from a particular scope @@ -44,7 +43,6 @@ public abstract class AbstractRequestAttributesScope implements Scope { Object scopedObject = attributes.getAttribute(name, getScope()); if (scopedObject == null) { scopedObject = objectFactory.getObject(); - Assert.state(scopedObject != null, "Scoped object resolved to null"); attributes.setAttribute(name, scopedObject, getScope()); // Retrieve object again, registering it for implicit session attribute updates. // As a bonus, we also allow for potential decoration at the getAttribute level. diff --git a/spring-web/src/main/java/org/springframework/web/context/support/ServletContextScope.java b/spring-web/src/main/java/org/springframework/web/context/support/ServletContextScope.java index b550de66af..7003c782da 100644 --- a/spring-web/src/main/java/org/springframework/web/context/support/ServletContextScope.java +++ b/spring-web/src/main/java/org/springframework/web/context/support/ServletContextScope.java @@ -68,7 +68,6 @@ public class ServletContextScope implements Scope, DisposableBean { Object scopedObject = this.servletContext.getAttribute(name); if (scopedObject == null) { scopedObject = objectFactory.getObject(); - Assert.state(scopedObject != null, "Scoped object resolved to null"); this.servletContext.setAttribute(name, scopedObject); } return scopedObject;