Programmatic ObjectProvider retrieval through BeanFactory API

Introduces getBeanProvider(Class) and getBeanProvider(ResolvableType), also narrowing getBean(String, Class) and isTypeMatch(String, Class) to a non-null Class argument and enriching NoUniqueBeanDefinitionException with a full ResolvableType. In addition, ObjectProvider supports iterable/stream access for collection-style resolution of multiple matching beans now, and collection injection falls back to an empty collection in a single-constructor case with non-null arguments.

Issue: SPR-17075
Issue: SPR-11419
Issue: SPR-15338
This commit is contained in:
Juergen Hoeller
2018-07-24 00:42:03 +02:00
parent 82194f4ee0
commit 1603c4ab2f
16 changed files with 918 additions and 100 deletions

View File

@@ -27,14 +27,17 @@ import java.security.PrivilegedAction;
import java.text.NumberFormat;
import java.text.ParseException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.stream.Collectors;
import javax.annotation.Priority;
import javax.security.auth.Subject;
@@ -95,6 +98,7 @@ import org.springframework.tests.sample.beans.NestedTestBean;
import org.springframework.tests.sample.beans.SideEffectBean;
import org.springframework.tests.sample.beans.TestBean;
import org.springframework.tests.sample.beans.factory.DummyFactory;
import org.springframework.util.SerializationTestUtils;
import org.springframework.util.StopWatch;
import org.springframework.util.StringValueResolver;
@@ -1559,10 +1563,42 @@ public class DefaultListableBeanFactoryTests {
}
}
@Test(expected = NoSuchBeanDefinitionException.class)
@Test
public void testGetBeanByTypeInstanceWithNoneFound() {
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
lbf.getBean(ConstructorDependency.class, 42);
try {
lbf.getBean(ConstructorDependency.class);
fail("Should have thrown NoSuchBeanDefinitionException");
}
catch (NoSuchBeanDefinitionException ex) {
// expected
}
try {
lbf.getBean(ConstructorDependency.class, 42);
fail("Should have thrown NoSuchBeanDefinitionException");
}
catch (NoSuchBeanDefinitionException ex) {
// expected
}
ObjectProvider<ConstructorDependency> provider = lbf.getBeanProvider(ConstructorDependency.class);
try {
provider.getObject();
fail("Should have thrown NoSuchBeanDefinitionException");
}
catch (NoSuchBeanDefinitionException ex) {
// expected
}
try {
provider.getObject(42);
fail("Should have thrown NoSuchBeanDefinitionException");
}
catch (NoSuchBeanDefinitionException ex) {
// expected
}
assertNull(provider.getIfAvailable());
assertNull(provider.getIfUnique());
}
@Test
@@ -1571,9 +1607,27 @@ public class DefaultListableBeanFactoryTests {
RootBeanDefinition bd1 = createConstructorDependencyBeanDefinition(99);
parent.registerBeanDefinition("bd1", bd1);
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory(parent);
ConstructorDependency bean = lbf.getBean(ConstructorDependency.class, 42);
ConstructorDependency bean = lbf.getBean(ConstructorDependency.class);
assertThat(bean.beanName, equalTo("bd1"));
assertThat(bean.spouseAge, equalTo(99));
bean = lbf.getBean(ConstructorDependency.class, 42);
assertThat(bean.beanName, equalTo("bd1"));
assertThat(bean.spouseAge, equalTo(42));
ObjectProvider<ConstructorDependency> provider = lbf.getBeanProvider(ConstructorDependency.class);
bean = provider.getObject();
assertThat(bean.beanName, equalTo("bd1"));
assertThat(bean.spouseAge, equalTo(99));
bean = provider.getObject(42);
assertThat(bean.beanName, equalTo("bd1"));
assertThat(bean.spouseAge, equalTo(42));
bean = provider.getIfAvailable();
assertThat(bean.beanName, equalTo("bd1"));
assertThat(bean.spouseAge, equalTo(99));
bean = provider.getIfUnique();
assertThat(bean.beanName, equalTo("bd1"));
assertThat(bean.spouseAge, equalTo(99));
}
@Test
@@ -1583,12 +1637,66 @@ public class DefaultListableBeanFactoryTests {
RootBeanDefinition bd2 = new RootBeanDefinition(ConstructorDependency.class);
bd2.setScope(RootBeanDefinition.SCOPE_PROTOTYPE);
bd2.getConstructorArgumentValues().addGenericArgumentValue("43");
lbf.registerBeanDefinition("bd1", bd1);
lbf.registerBeanDefinition("bd2", bd2);
thrown.expect(NoUniqueBeanDefinitionException.class);
lbf.getBean(ConstructorDependency.class, 42);
try {
lbf.getBean(ConstructorDependency.class);
fail("Should have thrown NoUniqueBeanDefinitionException");
}
catch (NoUniqueBeanDefinitionException ex) {
// expected
}
try {
lbf.getBean(ConstructorDependency.class, 42);
fail("Should have thrown NoUniqueBeanDefinitionException");
}
catch (NoUniqueBeanDefinitionException ex) {
// expected
}
ObjectProvider<ConstructorDependency> provider = lbf.getBeanProvider(ConstructorDependency.class);
try {
provider.getObject();
fail("Should have thrown NoUniqueBeanDefinitionException");
}
catch (NoUniqueBeanDefinitionException ex) {
// expected
}
try {
provider.getObject(42);
fail("Should have thrown NoUniqueBeanDefinitionException");
}
catch (NoUniqueBeanDefinitionException ex) {
// expected
}
try {
provider.getIfAvailable();
fail("Should have thrown NoUniqueBeanDefinitionException");
}
catch (NoUniqueBeanDefinitionException ex) {
// expected
}
assertNull(provider.getIfUnique());
Set<Object> resolved = new HashSet<>();
for (ConstructorDependency instance : provider) {
resolved.add(instance);
}
assertEquals(2, resolved.size());
assertTrue(resolved.contains(lbf.getBean("bd1")));
assertTrue(resolved.contains(lbf.getBean("bd2")));
resolved = new HashSet<>();
provider.forEach(resolved::add);
assertEquals(2, resolved.size());
assertTrue(resolved.contains(lbf.getBean("bd1")));
assertTrue(resolved.contains(lbf.getBean("bd2")));
resolved = provider.stream().collect(Collectors.toSet());
assertEquals(2, resolved.size());
assertTrue(resolved.contains(lbf.getBean("bd1")));
assertTrue(resolved.contains(lbf.getBean("bd2")));
}
@Test
@@ -1599,9 +1707,46 @@ public class DefaultListableBeanFactoryTests {
bd2.setPrimary(true);
lbf.registerBeanDefinition("bd1", bd1);
lbf.registerBeanDefinition("bd2", bd2);
ConstructorDependency bean = lbf.getBean(ConstructorDependency.class, 42);
ConstructorDependency bean = lbf.getBean(ConstructorDependency.class);
assertThat(bean.beanName, equalTo("bd2"));
assertThat(bean.spouseAge, equalTo(43));
bean = lbf.getBean(ConstructorDependency.class, 42);
assertThat(bean.beanName, equalTo("bd2"));
assertThat(bean.spouseAge, equalTo(42));
ObjectProvider<ConstructorDependency> provider = lbf.getBeanProvider(ConstructorDependency.class);
bean = provider.getObject();
assertThat(bean.beanName, equalTo("bd2"));
assertThat(bean.spouseAge, equalTo(43));
bean = provider.getObject(42);
assertThat(bean.beanName, equalTo("bd2"));
assertThat(bean.spouseAge, equalTo(42));
bean = provider.getIfAvailable();
assertThat(bean.beanName, equalTo("bd2"));
assertThat(bean.spouseAge, equalTo(43));
bean = provider.getIfUnique();
assertThat(bean.beanName, equalTo("bd2"));
assertThat(bean.spouseAge, equalTo(43));
Set<Object> resolved = new HashSet<>();
for (ConstructorDependency instance : provider) {
resolved.add(instance);
}
assertEquals(2, resolved.size());
assertTrue(resolved.contains(lbf.getBean("bd1")));
assertTrue(resolved.contains(lbf.getBean("bd2")));
resolved = new HashSet<>();
provider.forEach(resolved::add);
assertEquals(2, resolved.size());
assertTrue(resolved.contains(lbf.getBean("bd1")));
assertTrue(resolved.contains(lbf.getBean("bd2")));
resolved = provider.stream().collect(Collectors.toSet());
assertEquals(2, resolved.size());
assertTrue(resolved.contains(lbf.getBean("bd1")));
assertTrue(resolved.contains(lbf.getBean("bd2")));
}
@Test
@@ -1611,9 +1756,9 @@ public class DefaultListableBeanFactoryTests {
RootBeanDefinition bd2 = createConstructorDependencyBeanDefinition(43);
bd1.setPrimary(true);
bd2.setPrimary(true);
lbf.registerBeanDefinition("bd1", bd1);
lbf.registerBeanDefinition("bd2", bd2);
thrown.expect(NoUniqueBeanDefinitionException.class);
thrown.expectMessage(containsString("more than one 'primary'"));
lbf.getBean(ConstructorDependency.class, 42);
@@ -1642,6 +1787,31 @@ public class DefaultListableBeanFactoryTests {
}
}
@Test
public void testBeanProviderSerialization() throws Exception {
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
lbf.setSerializationId("test");
ObjectProvider<ConstructorDependency> provider = lbf.getBeanProvider(ConstructorDependency.class);
ObjectProvider deserialized = (ObjectProvider) SerializationTestUtils.serializeAndDeserialize(provider);
try {
deserialized.getObject();
fail("Should have thrown NoSuchBeanDefinitionException");
}
catch (NoSuchBeanDefinitionException ex) {
// expected
}
try {
deserialized.getObject(42);
fail("Should have thrown NoSuchBeanDefinitionException");
}
catch (NoSuchBeanDefinitionException ex) {
// expected
}
assertNull(deserialized.getIfAvailable());
assertNull(deserialized.getIfUnique());
}
@Test
public void testGetBeanWithArgsNotCreatedForFactoryBeanChecking() {
DefaultListableBeanFactory lbf = new DefaultListableBeanFactory();
@@ -2859,6 +3029,21 @@ public class DefaultListableBeanFactoryTests {
public void setBeanName(String name) {
this.beanName = name;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ConstructorDependency that = (ConstructorDependency) o;
return spouseAge == that.spouseAge &&
Objects.equals(spouse, that.spouse) &&
Objects.equals(beanName, that.beanName);
}
@Override
public int hashCode() {
return Objects.hash(spouse, spouseAge, beanName);
}
}

View File

@@ -35,6 +35,7 @@ import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.stream.Collectors;
import org.junit.Ignore;
import org.junit.Test;
@@ -811,13 +812,13 @@ public class AutowiredAnnotationBeanPostProcessorTests {
}
@Test
public void testSingleConstructorInjectionWithMultipleCandidatesAsOrderedCollection() {
public void testSingleConstructorInjectionWithMultipleCandidatesAsRequiredCollection() {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
bf.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
bpp.setBeanFactory(bf);
bf.addBeanPostProcessor(bpp);
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(SingleConstructorCollectionInjectionBean.class));
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(SingleConstructorRequiredCollectionBean.class));
TestBean tb = new TestBean();
bf.registerSingleton("testBean", tb);
FixedOrder2NestedTestBean ntb1 = new FixedOrder2NestedTestBean();
@@ -825,7 +826,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
FixedOrder1NestedTestBean ntb2 = new FixedOrder1NestedTestBean();
bf.registerSingleton("nestedTestBean2", ntb2);
SingleConstructorCollectionInjectionBean bean = (SingleConstructorCollectionInjectionBean) bf.getBean("annotatedBean");
SingleConstructorRequiredCollectionBean bean = (SingleConstructorRequiredCollectionBean) bf.getBean("annotatedBean");
assertSame(tb, bean.getTestBean());
assertEquals(2, bean.getNestedTestBeans().size());
assertSame(ntb2, bean.getNestedTestBeans().get(0));
@@ -840,11 +841,52 @@ public class AutowiredAnnotationBeanPostProcessorTests {
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
bpp.setBeanFactory(bf);
bf.addBeanPostProcessor(bpp);
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(SingleConstructorCollectionInjectionBean.class));
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(SingleConstructorRequiredCollectionBean.class));
TestBean tb = new TestBean();
bf.registerSingleton("testBean", tb);
SingleConstructorCollectionInjectionBean bean = (SingleConstructorCollectionInjectionBean) bf.getBean("annotatedBean");
SingleConstructorRequiredCollectionBean bean = (SingleConstructorRequiredCollectionBean) bf.getBean("annotatedBean");
assertSame(tb, bean.getTestBean());
assertNotNull(bean.getNestedTestBeans());
assertTrue(bean.getNestedTestBeans().isEmpty());
bf.destroySingletons();
}
@Test
public void testSingleConstructorInjectionWithMultipleCandidatesAsOrderedCollection() {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
bf.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
bpp.setBeanFactory(bf);
bf.addBeanPostProcessor(bpp);
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(SingleConstructorOptionalCollectionBean.class));
TestBean tb = new TestBean();
bf.registerSingleton("testBean", tb);
FixedOrder2NestedTestBean ntb1 = new FixedOrder2NestedTestBean();
bf.registerSingleton("nestedTestBean1", ntb1);
FixedOrder1NestedTestBean ntb2 = new FixedOrder1NestedTestBean();
bf.registerSingleton("nestedTestBean2", ntb2);
SingleConstructorOptionalCollectionBean bean = (SingleConstructorOptionalCollectionBean) bf.getBean("annotatedBean");
assertSame(tb, bean.getTestBean());
assertEquals(2, bean.getNestedTestBeans().size());
assertSame(ntb2, bean.getNestedTestBeans().get(0));
assertSame(ntb1, bean.getNestedTestBeans().get(1));
bf.destroySingletons();
}
@Test
public void testSingleConstructorInjectionWithEmptyCollectionAsNull() {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
bf.setAutowireCandidateResolver(new QualifierAnnotationAutowireCandidateResolver());
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
bpp.setBeanFactory(bf);
bf.addBeanPostProcessor(bpp);
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(SingleConstructorOptionalCollectionBean.class));
TestBean tb = new TestBean();
bf.registerSingleton("testBean", tb);
SingleConstructorOptionalCollectionBean bean = (SingleConstructorOptionalCollectionBean) bf.getBean("annotatedBean");
assertSame(tb, bean.getTestBean());
assertNull(bean.getNestedTestBeans());
bf.destroySingletons();
@@ -857,7 +899,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
bpp.setBeanFactory(bf);
bf.addBeanPostProcessor(bpp);
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(SingleConstructorCollectionInjectionBean.class));
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(SingleConstructorOptionalCollectionBean.class));
bf.getBean("annotatedBean");
}
@@ -869,7 +911,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
bpp.setBeanFactory(bf);
bf.addBeanPostProcessor(bpp);
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(SingleConstructorCollectionInjectionBean.class));
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(SingleConstructorOptionalCollectionBean.class));
RootBeanDefinition tb = new RootBeanDefinition(NullFactoryMethods.class);
tb.setFactoryMethodName("createTestBean");
bf.registerBeanDefinition("testBean", tb);
@@ -1333,17 +1375,17 @@ public class AutowiredAnnotationBeanPostProcessorTests {
}
@Test
public void testSmartObjectFactoryInjectionWithPrototype() {
public void testObjectProviderInjectionWithPrototype() {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
bpp.setBeanFactory(bf);
bf.addBeanPostProcessor(bpp);
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(SmartObjectFactoryInjectionBean.class));
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(ObjectProviderInjectionBean.class));
RootBeanDefinition tbd = new RootBeanDefinition(TestBean.class);
tbd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE);
bf.registerBeanDefinition("testBean", tbd);
SmartObjectFactoryInjectionBean bean = (SmartObjectFactoryInjectionBean) bf.getBean("annotatedBean");
ObjectProviderInjectionBean bean = (ObjectProviderInjectionBean) bf.getBean("annotatedBean");
assertEquals(bf.getBean("testBean"), bean.getTestBean());
assertEquals(bf.getBean("testBean", "myName"), bean.getTestBean("myName"));
assertEquals(bf.getBean("testBean"), bean.getOptionalTestBean());
@@ -1352,19 +1394,30 @@ public class AutowiredAnnotationBeanPostProcessorTests {
assertEquals(bf.getBean("testBean"), bean.getUniqueTestBean());
assertEquals(bf.getBean("testBean"), bean.getUniqueTestBeanWithDefault());
assertEquals(bf.getBean("testBean"), bean.consumeUniqueTestBean());
List<?> testBeans = bean.iterateTestBeans();
assertEquals(1, testBeans.size());
assertTrue(testBeans.contains(bf.getBean("testBean")));
testBeans = bean.forEachTestBeans();
assertEquals(1, testBeans.size());
assertTrue(testBeans.contains(bf.getBean("testBean")));
testBeans = bean.streamTestBeans();
assertEquals(1, testBeans.size());
assertTrue(testBeans.contains(bf.getBean("testBean")));
bf.destroySingletons();
}
@Test
public void testSmartObjectFactoryInjectionWithSingletonTarget() {
public void testObjectProviderInjectionWithSingletonTarget() {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
bpp.setBeanFactory(bf);
bf.addBeanPostProcessor(bpp);
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(SmartObjectFactoryInjectionBean.class));
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(ObjectProviderInjectionBean.class));
bf.registerBeanDefinition("testBean", new RootBeanDefinition(TestBean.class));
SmartObjectFactoryInjectionBean bean = (SmartObjectFactoryInjectionBean) bf.getBean("annotatedBean");
ObjectProviderInjectionBean bean = (ObjectProviderInjectionBean) bf.getBean("annotatedBean");
assertSame(bf.getBean("testBean"), bean.getTestBean());
assertSame(bf.getBean("testBean"), bean.getOptionalTestBean());
assertSame(bf.getBean("testBean"), bean.getOptionalTestBeanWithDefault());
@@ -1372,18 +1425,29 @@ public class AutowiredAnnotationBeanPostProcessorTests {
assertSame(bf.getBean("testBean"), bean.getUniqueTestBean());
assertSame(bf.getBean("testBean"), bean.getUniqueTestBeanWithDefault());
assertEquals(bf.getBean("testBean"), bean.consumeUniqueTestBean());
List<?> testBeans = bean.iterateTestBeans();
assertEquals(1, testBeans.size());
assertTrue(testBeans.contains(bf.getBean("testBean")));
testBeans = bean.forEachTestBeans();
assertEquals(1, testBeans.size());
assertTrue(testBeans.contains(bf.getBean("testBean")));
testBeans = bean.streamTestBeans();
assertEquals(1, testBeans.size());
assertTrue(testBeans.contains(bf.getBean("testBean")));
bf.destroySingletons();
}
@Test
public void testSmartObjectFactoryInjectionWithTargetNotAvailable() {
public void testObjectProviderInjectionWithTargetNotAvailable() {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
bpp.setBeanFactory(bf);
bf.addBeanPostProcessor(bpp);
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(SmartObjectFactoryInjectionBean.class));
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(ObjectProviderInjectionBean.class));
SmartObjectFactoryInjectionBean bean = (SmartObjectFactoryInjectionBean) bf.getBean("annotatedBean");
ObjectProviderInjectionBean bean = (ObjectProviderInjectionBean) bf.getBean("annotatedBean");
try {
bean.getTestBean();
fail("Should have thrown NoSuchBeanDefinitionException");
@@ -1397,20 +1461,28 @@ public class AutowiredAnnotationBeanPostProcessorTests {
assertEquals(new TestBean("default"), bean.getUniqueTestBeanWithDefault());
assertNull(bean.getUniqueTestBean());
assertNull(bean.consumeUniqueTestBean());
List<?> testBeans = bean.iterateTestBeans();
assertTrue(testBeans.isEmpty());
testBeans = bean.forEachTestBeans();
assertTrue(testBeans.isEmpty());
testBeans = bean.streamTestBeans();
assertTrue(testBeans.isEmpty());
bf.destroySingletons();
}
@Test
public void testSmartObjectFactoryInjectionWithTargetNotUnique() {
public void testObjectProviderInjectionWithTargetNotUnique() {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
bpp.setBeanFactory(bf);
bf.addBeanPostProcessor(bpp);
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(SmartObjectFactoryInjectionBean.class));
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(ObjectProviderInjectionBean.class));
bf.registerBeanDefinition("testBean1", new RootBeanDefinition(TestBean.class));
bf.registerBeanDefinition("testBean2", new RootBeanDefinition(TestBean.class));
SmartObjectFactoryInjectionBean bean = (SmartObjectFactoryInjectionBean) bf.getBean("annotatedBean");
ObjectProviderInjectionBean bean = (ObjectProviderInjectionBean) bf.getBean("annotatedBean");
try {
bean.getTestBean();
fail("Should have thrown NoUniqueBeanDefinitionException");
@@ -1434,16 +1506,30 @@ public class AutowiredAnnotationBeanPostProcessorTests {
}
assertNull(bean.getUniqueTestBean());
assertNull(bean.consumeUniqueTestBean());
List<?> testBeans = bean.iterateTestBeans();
assertEquals(2, testBeans.size());
assertTrue(testBeans.contains(bf.getBean("testBean1")));
assertTrue(testBeans.contains(bf.getBean("testBean2")));
testBeans = bean.forEachTestBeans();
assertEquals(2, testBeans.size());
assertTrue(testBeans.contains(bf.getBean("testBean1")));
assertTrue(testBeans.contains(bf.getBean("testBean2")));
testBeans = bean.streamTestBeans();
assertEquals(2, testBeans.size());
assertTrue(testBeans.contains(bf.getBean("testBean1")));
assertTrue(testBeans.contains(bf.getBean("testBean2")));
bf.destroySingletons();
}
@Test
public void testSmartObjectFactoryInjectionWithTargetPrimary() {
public void testObjectProviderInjectionWithTargetPrimary() {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
bpp.setBeanFactory(bf);
bf.addBeanPostProcessor(bpp);
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(SmartObjectFactoryInjectionBean.class));
bf.registerBeanDefinition("annotatedBean", new RootBeanDefinition(ObjectProviderInjectionBean.class));
RootBeanDefinition tb1 = new RootBeanDefinition(TestBean.class);
tb1.setPrimary(true);
bf.registerBeanDefinition("testBean1", tb1);
@@ -1451,13 +1537,27 @@ public class AutowiredAnnotationBeanPostProcessorTests {
tb2.setLazyInit(true);
bf.registerBeanDefinition("testBean2", tb2);
SmartObjectFactoryInjectionBean bean = (SmartObjectFactoryInjectionBean) bf.getBean("annotatedBean");
ObjectProviderInjectionBean bean = (ObjectProviderInjectionBean) bf.getBean("annotatedBean");
assertSame(bf.getBean("testBean1"), bean.getTestBean());
assertSame(bf.getBean("testBean1"), bean.getOptionalTestBean());
assertSame(bf.getBean("testBean1"), bean.consumeOptionalTestBean());
assertSame(bf.getBean("testBean1"), bean.getUniqueTestBean());
assertSame(bf.getBean("testBean1"), bean.consumeUniqueTestBean());
assertFalse(bf.containsSingleton("testBean2"));
List<?> testBeans = bean.iterateTestBeans();
assertEquals(2, testBeans.size());
assertTrue(testBeans.contains(bf.getBean("testBean1")));
assertTrue(testBeans.contains(bf.getBean("testBean2")));
testBeans = bean.forEachTestBeans();
assertEquals(2, testBeans.size());
assertTrue(testBeans.contains(bf.getBean("testBean1")));
assertTrue(testBeans.contains(bf.getBean("testBean2")));
testBeans = bean.streamTestBeans();
assertEquals(2, testBeans.size());
assertTrue(testBeans.contains(bf.getBean("testBean1")));
assertTrue(testBeans.contains(bf.getBean("testBean2")));
bf.destroySingletons();
}
@@ -2941,13 +3041,34 @@ public class AutowiredAnnotationBeanPostProcessorTests {
}
public static class SingleConstructorCollectionInjectionBean {
public static class SingleConstructorRequiredCollectionBean {
private ITestBean testBean;
private List<NestedTestBean> nestedTestBeans;
public SingleConstructorCollectionInjectionBean(ITestBean testBean,
public SingleConstructorRequiredCollectionBean(ITestBean testBean, List<NestedTestBean> nestedTestBeans) {
this.testBean = testBean;
this.nestedTestBeans = nestedTestBeans;
}
public ITestBean getTestBean() {
return this.testBean;
}
public List<NestedTestBean> getNestedTestBeans() {
return this.nestedTestBeans;
}
}
public static class SingleConstructorOptionalCollectionBean {
private ITestBean testBean;
private List<NestedTestBean> nestedTestBeans;
public SingleConstructorOptionalCollectionBean(ITestBean testBean,
@Autowired(required = false) List<NestedTestBean> nestedTestBeans) {
this.testBean = testBean;
this.nestedTestBeans = nestedTestBeans;
@@ -3096,46 +3217,64 @@ public class AutowiredAnnotationBeanPostProcessorTests {
}
public static class SmartObjectFactoryInjectionBean {
public static class ObjectProviderInjectionBean {
@Autowired
private ObjectProvider<TestBean> testBeanFactory;
private ObjectProvider<TestBean> testBeanProvider;
private TestBean consumedTestBean;
public TestBean getTestBean() {
return this.testBeanFactory.getObject();
return this.testBeanProvider.getObject();
}
public TestBean getTestBean(String name) {
return this.testBeanFactory.getObject(name);
return this.testBeanProvider.getObject(name);
}
public TestBean getOptionalTestBean() {
return this.testBeanFactory.getIfAvailable();
return this.testBeanProvider.getIfAvailable();
}
public TestBean getOptionalTestBeanWithDefault() {
return this.testBeanFactory.getIfAvailable(() -> new TestBean("default"));
return this.testBeanProvider.getIfAvailable(() -> new TestBean("default"));
}
public TestBean consumeOptionalTestBean() {
this.testBeanFactory.ifAvailable(tb -> consumedTestBean = tb);
this.testBeanProvider.ifAvailable(tb -> consumedTestBean = tb);
return consumedTestBean;
}
public TestBean getUniqueTestBean() {
return this.testBeanFactory.getIfUnique();
return this.testBeanProvider.getIfUnique();
}
public TestBean getUniqueTestBeanWithDefault() {
return this.testBeanFactory.getIfUnique(() -> new TestBean("default"));
return this.testBeanProvider.getIfUnique(() -> new TestBean("default"));
}
public TestBean consumeUniqueTestBean() {
this.testBeanFactory.ifUnique(tb -> consumedTestBean = tb);
this.testBeanProvider.ifUnique(tb -> consumedTestBean = tb);
return consumedTestBean;
}
public List<TestBean> iterateTestBeans() {
List<TestBean> resolved = new LinkedList<>();
for (TestBean tb : this.testBeanProvider) {
resolved.add(tb);
}
return resolved;
}
public List<TestBean> forEachTestBeans() {
List<TestBean> resolved = new LinkedList<>();
this.testBeanProvider.forEach(resolved::add);
return resolved;
}
public List<TestBean> streamTestBeans() {
return this.testBeanProvider.stream().collect(Collectors.toList());
}
}

View File

@@ -30,6 +30,7 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import org.junit.Test;
import org.mockito.Mockito;
@@ -37,6 +38,8 @@ import org.mockito.Mockito;
import org.springframework.beans.PropertyEditorRegistrar;
import org.springframework.beans.PropertyEditorRegistry;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.config.TypedStringValue;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.beans.propertyeditors.CustomNumberEditor;
@@ -160,7 +163,7 @@ public class BeanFactoryGenericsTests {
}
@Test
public void testGenericListOfArraysProperty() throws MalformedURLException {
public void testGenericListOfArraysProperty() {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
new XmlBeanDefinitionReader(bf).loadBeanDefinitions(
new ClassPathResource("genericBeanTests.xml", getClass()));
@@ -863,6 +866,66 @@ public class BeanFactoryGenericsTests {
assertEquals("store1", doubleStoreNames[0]);
assertEquals(1, floatStoreNames.length);
assertEquals("store2", floatStoreNames[0]);
ObjectProvider<NumberStore<?>> numberStoreProvider = bf.getBeanProvider(ResolvableType.forClass(NumberStore.class));
ObjectProvider<NumberStore<Double>> doubleStoreProvider = bf.getBeanProvider(ResolvableType.forClassWithGenerics(NumberStore.class, Double.class));
ObjectProvider<NumberStore<Float>> floatStoreProvider = bf.getBeanProvider(ResolvableType.forClassWithGenerics(NumberStore.class, Float.class));
try {
numberStoreProvider.getObject();
fail("Should have thrown NoUniqueBeanDefinitionException");
}
catch (NoUniqueBeanDefinitionException ex) {
// expected
}
try {
numberStoreProvider.getIfAvailable();
fail("Should have thrown NoUniqueBeanDefinitionException");
}
catch (NoUniqueBeanDefinitionException ex) {
// expected
}
assertNull(numberStoreProvider.getIfUnique());
assertSame(bf.getBean("store1"), doubleStoreProvider.getObject());
assertSame(bf.getBean("store1"), doubleStoreProvider.getIfAvailable());
assertSame(bf.getBean("store1"), doubleStoreProvider.getIfUnique());
assertSame(bf.getBean("store2"), floatStoreProvider.getObject());
assertSame(bf.getBean("store2"), floatStoreProvider.getIfAvailable());
assertSame(bf.getBean("store2"), floatStoreProvider.getIfUnique());
Set<Object> resolved = new HashSet<>();
for (NumberStore<?> instance : numberStoreProvider) {
resolved.add(instance);
}
assertEquals(2, resolved.size());
assertTrue(resolved.contains(bf.getBean("store1")));
assertTrue(resolved.contains(bf.getBean("store2")));
resolved = numberStoreProvider.stream().collect(Collectors.toSet());
assertEquals(2, resolved.size());
assertTrue(resolved.contains(bf.getBean("store1")));
assertTrue(resolved.contains(bf.getBean("store2")));
resolved = new HashSet<>();
for (NumberStore<Double> instance : doubleStoreProvider) {
resolved.add(instance);
}
assertEquals(1, resolved.size());
assertTrue(resolved.contains(bf.getBean("store1")));
resolved = doubleStoreProvider.stream().collect(Collectors.toSet());
assertEquals(1, resolved.size());
assertTrue(resolved.contains(bf.getBean("store1")));
resolved = new HashSet<>();
for (NumberStore<Float> instance : floatStoreProvider) {
resolved.add(instance);
}
assertEquals(1, resolved.size());
assertTrue(resolved.contains(bf.getBean("store2")));
resolved = floatStoreProvider.stream().collect(Collectors.toSet());
assertEquals(1, resolved.size());
assertTrue(resolved.contains(bf.getBean("store2")));
}