Revisit GenericApplicationContext.registerBean constructor handling

Support for Kotlin primary constructor and non-default public constructors in addition to default instantiation, aligned with AnnotationConfigApplicationContext and model attribute processing.

Issue: SPR-17292
This commit is contained in:
Juergen Hoeller
2018-09-19 22:19:43 +02:00
parent 50c9542796
commit d3c08552e9
5 changed files with 279 additions and 91 deletions

View File

@@ -90,6 +90,21 @@ public class AnnotationConfigApplicationContextTests {
assertThat(testBean.name, equalTo("foo"));
}
@Test
public void getBeanByTypeRaisesNoSuchBeanDefinitionException() {
ApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
// attempt to retrieve a bean that does not exist
Class<?> targetType = Pattern.class;
try {
context.getBean(targetType);
fail("Should have thrown NoSuchBeanDefinitionException");
}
catch (NoSuchBeanDefinitionException ex) {
assertThat(ex.getMessage(), containsString(format("No qualifying bean of type '%s'", targetType.getName())));
}
}
/**
* Tests that Configuration classes are registered according to convention
* @see org.springframework.beans.factory.support.DefaultBeanNameGenerator#generateBeanName
@@ -116,6 +131,41 @@ public class AnnotationConfigApplicationContextTests {
assertNotNull(configObject);
}
@Test
public void autowiringIsEnabledByDefault() {
ApplicationContext context = new AnnotationConfigApplicationContext(AutowiredConfig.class);
assertThat(context.getBean(TestBean.class).name, equalTo("foo"));
}
@Test
public void nullReturningBeanPostProcessor() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(AutowiredConfig.class);
context.getBeanFactory().addBeanPostProcessor(new BeanPostProcessor() {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
return (bean instanceof TestBean ? null : bean);
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
return bean;
}
});
context.getBeanFactory().addBeanPostProcessor(new BeanPostProcessor() {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
bean.getClass().getName();
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
bean.getClass().getName();
return bean;
}
});
context.refresh();
}
@Test
public void individualBeans() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
@@ -299,74 +349,6 @@ public class AnnotationConfigApplicationContextTests {
assertEquals(FactoryBean.class, context.getType("&fb"));
}
@Test
public void getBeanByTypeRaisesNoSuchBeanDefinitionException() {
ApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
// attempt to retrieve a bean that does not exist
Class<?> targetType = Pattern.class;
try {
context.getBean(targetType);
fail("Should have thrown NoSuchBeanDefinitionException");
}
catch (NoSuchBeanDefinitionException ex) {
assertThat(ex.getMessage(), containsString(format("No qualifying bean of type '%s'", targetType.getName())));
}
}
@Test
public void getBeanByTypeAmbiguityRaisesException() {
ApplicationContext context = new AnnotationConfigApplicationContext(TwoTestBeanConfig.class);
try {
context.getBean(TestBean.class);
}
catch (NoSuchBeanDefinitionException ex) {
assertThat(ex.getMessage(),
allOf(
containsString("No qualifying bean of type '" + TestBean.class.getName() + "'"),
containsString("tb1"),
containsString("tb2")
)
);
}
}
@Test
public void autowiringIsEnabledByDefault() {
ApplicationContext context = new AnnotationConfigApplicationContext(AutowiredConfig.class);
assertThat(context.getBean(TestBean.class).name, equalTo("foo"));
}
@Test
public void nullReturningBeanPostProcessor() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(AutowiredConfig.class);
context.getBeanFactory().addBeanPostProcessor(new BeanPostProcessor() {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
return (bean instanceof TestBean ? null : bean);
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
return bean;
}
});
context.getBeanFactory().addBeanPostProcessor(new BeanPostProcessor() {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
bean.getClass().getName();
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
bean.getClass().getName();
return bean;
}
});
context.refresh();
}
@Configuration
static class Config {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2018 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.
@@ -19,8 +19,10 @@ package org.springframework.context.support;
import org.junit.Test;
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.util.ObjectUtils;
import static org.junit.Assert.*;
@@ -104,4 +106,140 @@ public class GenericApplicationContextTests {
}
}
@Test
public void individualBeans() {
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean(BeanA.class);
context.registerBean(BeanB.class);
context.registerBean(BeanC.class);
context.refresh();
assertSame(context.getBean(BeanB.class), context.getBean(BeanA.class).b);
assertSame(context.getBean(BeanC.class), context.getBean(BeanA.class).c);
assertSame(context, context.getBean(BeanB.class).applicationContext);
}
@Test
public void individualNamedBeans() {
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean("a", BeanA.class);
context.registerBean("b", BeanB.class);
context.registerBean("c", BeanC.class);
context.refresh();
assertSame(context.getBean("b"), context.getBean("a", BeanA.class).b);
assertSame(context.getBean("c"), context.getBean("a", BeanA.class).c);
assertSame(context, context.getBean("b", BeanB.class).applicationContext);
}
@Test
public void individualBeanWithSupplier() {
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean(BeanA.class,
() -> new BeanA(context.getBean(BeanB.class), context.getBean(BeanC.class)));
context.registerBean(BeanB.class, BeanB::new);
context.registerBean(BeanC.class, BeanC::new);
context.refresh();
assertTrue(context.getBeanFactory().containsSingleton(BeanA.class.getName()));
assertSame(context.getBean(BeanB.class), context.getBean(BeanA.class).b);
assertSame(context.getBean(BeanC.class), context.getBean(BeanA.class).c);
assertSame(context, context.getBean(BeanB.class).applicationContext);
assertArrayEquals(new String[] {BeanA.class.getName()},
context.getDefaultListableBeanFactory().getDependentBeans(BeanB.class.getName()));
assertArrayEquals(new String[] {BeanA.class.getName()},
context.getDefaultListableBeanFactory().getDependentBeans(BeanC.class.getName()));
}
@Test
public void individualBeanWithSupplierAndCustomizer() {
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean(BeanA.class,
() -> new BeanA(context.getBean(BeanB.class), context.getBean(BeanC.class)),
bd -> bd.setLazyInit(true));
context.registerBean(BeanB.class, BeanB::new);
context.registerBean(BeanC.class, BeanC::new);
context.refresh();
assertFalse(context.getBeanFactory().containsSingleton(BeanA.class.getName()));
assertSame(context.getBean(BeanB.class), context.getBean(BeanA.class).b);
assertSame(context.getBean(BeanC.class), context.getBean(BeanA.class).c);
assertSame(context, context.getBean(BeanB.class).applicationContext);
}
@Test
public void individualNamedBeanWithSupplier() {
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean("a", BeanA.class,
() -> new BeanA(context.getBean(BeanB.class), context.getBean(BeanC.class)));
context.registerBean("b", BeanB.class, BeanB::new);
context.registerBean("c", BeanC.class, BeanC::new);
context.refresh();
assertTrue(context.getBeanFactory().containsSingleton("a"));
assertSame(context.getBean("b", BeanB.class), context.getBean(BeanA.class).b);
assertSame(context.getBean("c"), context.getBean("a", BeanA.class).c);
assertSame(context, context.getBean("b", BeanB.class).applicationContext);
}
@Test
public void individualNamedBeanWithSupplierAndCustomizer() {
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean("a", BeanA.class,
() -> new BeanA(context.getBean(BeanB.class), context.getBean(BeanC.class)),
bd -> bd.setLazyInit(true));
context.registerBean("b", BeanB.class, BeanB::new);
context.registerBean("c", BeanC.class, BeanC::new);
context.refresh();
assertFalse(context.getBeanFactory().containsSingleton("a"));
assertSame(context.getBean("b", BeanB.class), context.getBean(BeanA.class).b);
assertSame(context.getBean("c"), context.getBean("a", BeanA.class).c);
assertSame(context, context.getBean("b", BeanB.class).applicationContext);
}
@Test
public void individualBeanWithNullReturningSupplier() {
GenericApplicationContext context = new GenericApplicationContext();
context.registerBean("a", BeanA.class, () -> null);
context.registerBean("b", BeanB.class, BeanB::new);
context.registerBean("c", BeanC.class, BeanC::new);
context.refresh();
assertTrue(ObjectUtils.containsElement(context.getBeanNamesForType(BeanA.class), "a"));
assertTrue(ObjectUtils.containsElement(context.getBeanNamesForType(BeanB.class), "b"));
assertTrue(ObjectUtils.containsElement(context.getBeanNamesForType(BeanC.class), "c"));
assertTrue(context.getBeansOfType(BeanA.class).isEmpty());
assertSame(context.getBean(BeanB.class), context.getBeansOfType(BeanB.class).values().iterator().next());
assertSame(context.getBean(BeanC.class), context.getBeansOfType(BeanC.class).values().iterator().next());
}
static class BeanA {
BeanB b;
BeanC c;
public BeanA(BeanB b, BeanC c) {
this.b = b;
this.c = c;
}
}
static class BeanB implements ApplicationContextAware {
ApplicationContext applicationContext;
public BeanB() {
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
}
static class BeanC {}
}