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:
@@ -45,7 +45,6 @@ public interface ObjectFactory<T> {
|
||||
* @return the resulting instance
|
||||
* @throws BeansException in case of creation errors
|
||||
*/
|
||||
@Nullable
|
||||
T getObject() throws BeansException;
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
/**
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user