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:
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user