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

@@ -44,12 +44,6 @@ import static org.springframework.util.StringUtils.*;
*/
public class AnnotationConfigApplicationContextTests {
@Test(expected = IllegalArgumentException.class)
public void nullGetBeanParameterIsDisallowed() {
ApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
context.getBean((Class<?>) null);
}
@Test
public void scanAndRefresh() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();

View File

@@ -801,6 +801,40 @@ public class ConfigurationClassPostProcessorTests {
assertSame(ctx.getBean(BarImpl.class), ctx.getBean(FooImpl.class).bar);
}
@Test
public void testCollectionArgumentOnBeanMethod() {
ApplicationContext ctx = new AnnotationConfigApplicationContext(CollectionArgumentConfiguration.class, TestBean.class);
CollectionArgumentConfiguration bean = ctx.getBean(CollectionArgumentConfiguration.class);
assertNotNull(bean.testBeans);
assertEquals(1, bean.testBeans.size());
assertSame(ctx.getBean(TestBean.class), bean.testBeans.get(0));
}
@Test
public void testEmptyCollectionArgumentOnBeanMethod() {
ApplicationContext ctx = new AnnotationConfigApplicationContext(CollectionArgumentConfiguration.class);
CollectionArgumentConfiguration bean = ctx.getBean(CollectionArgumentConfiguration.class);
assertNotNull(bean.testBeans);
assertTrue(bean.testBeans.isEmpty());
}
@Test
public void testMapArgumentOnBeanMethod() {
ApplicationContext ctx = new AnnotationConfigApplicationContext(MapArgumentConfiguration.class, DummyRunnable.class);
MapArgumentConfiguration bean = ctx.getBean(MapArgumentConfiguration.class);
assertNotNull(bean.testBeans);
assertEquals(1, bean.testBeans.size());
assertSame(ctx.getBean(Runnable.class), bean.testBeans.values().iterator().next());
}
@Test
public void testEmptyMapArgumentOnBeanMethod() {
ApplicationContext ctx = new AnnotationConfigApplicationContext(MapArgumentConfiguration.class);
MapArgumentConfiguration bean = ctx.getBean(MapArgumentConfiguration.class);
assertNotNull(bean.testBeans);
assertTrue(bean.testBeans.isEmpty());
}
@Test
public void testCollectionInjectionFromSameConfigurationClass() {
ApplicationContext ctx = new AnnotationConfigApplicationContext(CollectionInjectionConfiguration.class);
@@ -1564,6 +1598,43 @@ public class ConfigurationClassPostProcessorTests {
}
}
public static class DummyRunnable implements Runnable {
@Override
public void run() {
/* no-op */
}
}
@Configuration
static class CollectionArgumentConfiguration {
List<TestBean> testBeans;
@Bean(autowireCandidate = false)
public TestBean thing(List<TestBean> testBeans) {
this.testBeans = testBeans;
return new TestBean();
}
}
@Configuration
public static class MapArgumentConfiguration {
Map<String, Runnable> testBeans;
@Bean(autowireCandidate = false)
Runnable testBean(Map<String, Runnable> testBeans) {
this.testBeans = testBeans;
return () -> {};
}
// Unrelated, not to be considered as a factory method
private boolean testBean(boolean param) {
return param;
}
}
@Configuration
static class CollectionInjectionConfiguration {