Injection support for Collection/Map beans and self references

Issue: SPR-13585
Issue: SPR-12180
Issue: SPR-7915
Issue: SPR-8450
This commit is contained in:
Juergen Hoeller
2016-01-25 21:25:48 +01:00
parent 64e77de23b
commit 4a0fa69ce4
3 changed files with 217 additions and 62 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2015 the original author or authors.
* Copyright 2002-2016 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.
@@ -25,8 +25,13 @@ import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.Callable;
import org.junit.Ignore;
@@ -741,10 +746,10 @@ public class AutowiredAnnotationBeanPostProcessorTests {
RootBeanDefinition bd = new RootBeanDefinition(MapConstructorInjectionBean.class);
bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE);
bf.registerBeanDefinition("annotatedBean", bd);
TestBean tb1 = new TestBean();
TestBean tb2 = new TestBean();
TestBean tb1 = new TestBean("tb1");
TestBean tb2 = new TestBean("tb2");
bf.registerSingleton("testBean1", tb1);
bf.registerSingleton("testBean2", tb1);
bf.registerSingleton("testBean2", tb2);
MapConstructorInjectionBean bean = (MapConstructorInjectionBean) bf.getBean("annotatedBean");
assertEquals(2, bean.getTestBeanMap().size());
@@ -770,10 +775,10 @@ public class AutowiredAnnotationBeanPostProcessorTests {
RootBeanDefinition bd = new RootBeanDefinition(MapFieldInjectionBean.class);
bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE);
bf.registerBeanDefinition("annotatedBean", bd);
TestBean tb1 = new TestBean();
TestBean tb2 = new TestBean();
TestBean tb1 = new TestBean("tb1");
TestBean tb2 = new TestBean("tb2");
bf.registerSingleton("testBean1", tb1);
bf.registerSingleton("testBean2", tb1);
bf.registerSingleton("testBean2", tb2);
MapFieldInjectionBean bean = (MapFieldInjectionBean) bf.getBean("annotatedBean");
assertEquals(2, bean.getTestBeanMap().size());
@@ -829,7 +834,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
bf.getBean("annotatedBean");
fail("should have failed, more than one bean of type");
}
catch (BeanCreationException e) {
catch (BeanCreationException ex) {
// expected
}
bf.destroySingletons();
@@ -870,6 +875,108 @@ public class AutowiredAnnotationBeanPostProcessorTests {
bf.destroySingletons();
}
@Test
public void testConstructorInjectionWithTypedMapAsBean() {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
bf.setAutowireCandidateResolver(new QualifierAnnotationAutowireCandidateResolver());
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
bpp.setBeanFactory(bf);
bf.addBeanPostProcessor(bpp);
RootBeanDefinition bd = new RootBeanDefinition(MapConstructorInjectionBean.class);
bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE);
bf.registerBeanDefinition("annotatedBean", bd);
MyTestBeanMap tbm = new MyTestBeanMap();
tbm.put("testBean1", new TestBean("tb1"));
tbm.put("testBean2", new TestBean("tb2"));
bf.registerSingleton("testBeans", tbm);
bf.registerSingleton("otherMap", new Properties());
MapConstructorInjectionBean bean = (MapConstructorInjectionBean) bf.getBean("annotatedBean");
assertSame(tbm, bean.getTestBeanMap());
bean = (MapConstructorInjectionBean) bf.getBean("annotatedBean");
assertSame(tbm, bean.getTestBeanMap());
}
@Test
public void testConstructorInjectionWithPlainMapAsBean() {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
bf.setAutowireCandidateResolver(new QualifierAnnotationAutowireCandidateResolver());
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
bpp.setBeanFactory(bf);
bf.addBeanPostProcessor(bpp);
RootBeanDefinition bd = new RootBeanDefinition(MapConstructorInjectionBean.class);
bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE);
bf.registerBeanDefinition("annotatedBean", bd);
Map<String, TestBean> tbm = new LinkedHashMap<String, TestBean>();
tbm.put("testBean1", new TestBean("tb1"));
tbm.put("testBean2", new TestBean("tb2"));
bf.registerSingleton("testBeans", tbm);
bf.registerSingleton("otherMap", new Properties());
MapConstructorInjectionBean bean = (MapConstructorInjectionBean) bf.getBean("annotatedBean");
assertSame(tbm, bean.getTestBeanMap());
bean = (MapConstructorInjectionBean) bf.getBean("annotatedBean");
assertSame(tbm, bean.getTestBeanMap());
}
@Test
public void testConstructorInjectionWithTypedSetAsBean() {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
bf.setAutowireCandidateResolver(new QualifierAnnotationAutowireCandidateResolver());
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
bpp.setBeanFactory(bf);
bf.addBeanPostProcessor(bpp);
RootBeanDefinition bd = new RootBeanDefinition(SetConstructorInjectionBean.class);
bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE);
bf.registerBeanDefinition("annotatedBean", bd);
MyTestBeanSet tbs = new MyTestBeanSet();
tbs.add(new TestBean("tb1"));
tbs.add(new TestBean("tb2"));
bf.registerSingleton("testBeans", tbs);
bf.registerSingleton("otherSet", new HashSet<Object>());
SetConstructorInjectionBean bean = (SetConstructorInjectionBean) bf.getBean("annotatedBean");
assertSame(tbs, bean.getTestBeanSet());
bean = (SetConstructorInjectionBean) bf.getBean("annotatedBean");
assertSame(tbs, bean.getTestBeanSet());
}
@Test
public void testConstructorInjectionWithPlainSetAsBean() {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
bf.setAutowireCandidateResolver(new QualifierAnnotationAutowireCandidateResolver());
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
bpp.setBeanFactory(bf);
bf.addBeanPostProcessor(bpp);
RootBeanDefinition bd = new RootBeanDefinition(SetConstructorInjectionBean.class);
bd.setScope(RootBeanDefinition.SCOPE_PROTOTYPE);
bf.registerBeanDefinition("annotatedBean", bd);
Set<TestBean> tbs = new LinkedHashSet<TestBean>();
tbs.add(new TestBean("tb1"));
tbs.add(new TestBean("tb2"));
bf.registerSingleton("testBeanSet", tbs);
bf.registerSingleton("otherSet", new HashSet<Object>());
SetConstructorInjectionBean bean = (SetConstructorInjectionBean) bf.getBean("annotatedBean");
assertSame(tbs, bean.getTestBeanSet());
bean = (SetConstructorInjectionBean) bf.getBean("annotatedBean");
assertSame(tbs, bean.getTestBeanSet());
}
@Test
public void testSelfReference() {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
bf.setAutowireCandidateResolver(new QualifierAnnotationAutowireCandidateResolver());
AutowiredAnnotationBeanPostProcessor bpp = new AutowiredAnnotationBeanPostProcessor();
bpp.setBeanFactory(bf);
bf.addBeanPostProcessor(bpp);
RootBeanDefinition bd = new RootBeanDefinition(SelfInjectionBean.class);
bf.registerBeanDefinition("annotatedBean", bd);
SelfInjectionBean bean = (SelfInjectionBean) bf.getBean("annotatedBean");
assertSame(bean, bean.selfReference);
}
@Test
public void testObjectFactoryInjection() {
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
@@ -972,7 +1079,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
bf.getBean("customBean");
fail("expected BeanCreationException; no dependency available for required field");
}
catch (BeanCreationException e) {
catch (BeanCreationException ex) {
// expected
}
bf.destroySingletons();
@@ -998,7 +1105,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
bf.getBean("customBean");
fail("expected BeanCreationException; multiple beans of dependency type available");
}
catch (BeanCreationException e) {
catch (BeanCreationException ex) {
// expected
}
bf.destroySingletons();
@@ -1065,7 +1172,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
bf.getBean("customBean");
fail("expected BeanCreationException; multiple beans of dependency type available");
}
catch (BeanCreationException e) {
catch (BeanCreationException ex) {
// expected
}
bf.destroySingletons();
@@ -1131,7 +1238,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
bf.getBean("customBean");
fail("expected BeanCreationException; multiple beans of dependency type available");
}
catch (BeanCreationException e) {
catch (BeanCreationException ex) {
// expected
}
bf.destroySingletons();
@@ -1197,7 +1304,7 @@ public class AutowiredAnnotationBeanPostProcessorTests {
bf.getBean("customBean");
fail("expected BeanCreationException; multiple beans of dependency type available");
}
catch (BeanCreationException e) {
catch (BeanCreationException ex) {
// expected
}
bf.destroySingletons();
@@ -2244,6 +2351,14 @@ public class AutowiredAnnotationBeanPostProcessorTests {
}
public static class MyTestBeanMap extends LinkedHashMap<String, TestBean> {
}
public static class MyTestBeanSet extends LinkedHashSet<TestBean> {
}
public static class MapConstructorInjectionBean {
private Map<String, TestBean> testBeanMap;
@@ -2259,6 +2374,28 @@ public class AutowiredAnnotationBeanPostProcessorTests {
}
public static class SetConstructorInjectionBean {
private Set<TestBean> testBeanSet;
@Autowired
public SetConstructorInjectionBean(Set<TestBean> testBeanSet) {
this.testBeanSet = testBeanSet;
}
public Set<TestBean> getTestBeanSet() {
return this.testBeanSet;
}
}
public static class SelfInjectionBean {
@Autowired
public SelfInjectionBean selfReference;
}
public static class MapFieldInjectionBean {
@Autowired