Allow `ApplicationContextRunner` to accept simple bean definitions
This commit adds `withBean` methods to the `ApplicationContextRunner` abstraction so that simple beans can be registered inline. This is a nice alternative for cases where a inner configuration class has to be defined for the purpose of creating a simple bean. Closes gh-16011
This commit is contained in:
parent
7054a33e70
commit
a780875390
|
@ -22,6 +22,7 @@ import java.util.List;
|
|||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.springframework.beans.factory.support.BeanNameGenerator;
|
||||
import org.springframework.boot.context.annotation.Configurations;
|
||||
import org.springframework.boot.context.annotation.UserConfigurations;
|
||||
import org.springframework.boot.test.context.FilteredClassLoader;
|
||||
|
@ -32,6 +33,7 @@ import org.springframework.context.ApplicationContext;
|
|||
import org.springframework.context.ApplicationContextInitializer;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.AnnotationConfigRegistry;
|
||||
import org.springframework.context.support.GenericApplicationContext;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.io.DefaultResourceLoader;
|
||||
|
@ -156,8 +158,7 @@ public abstract class AbstractApplicationContextRunner<SELF extends AbstractAppl
|
|||
* @param initializer the initializer to add
|
||||
* @return a new instance with the updated initializers
|
||||
*/
|
||||
public SELF withInitializer(
|
||||
ApplicationContextInitializer<? super ConfigurableApplicationContext> initializer) {
|
||||
public SELF withInitializer(ApplicationContextInitializer<? super C> initializer) {
|
||||
Assert.notNull(initializer, "Initializer must not be null");
|
||||
return newInstance(this.contextFactory, add(this.initializers, initializer),
|
||||
this.environmentProperties, this.systemProperties, this.classLoader,
|
||||
|
@ -221,6 +222,84 @@ public abstract class AbstractApplicationContextRunner<SELF extends AbstractAppl
|
|||
parent, this.configurations);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the specified user bean with the {@link ApplicationContext}. The bean name
|
||||
* is generated from the configured {@link BeanNameGenerator} on the underlying
|
||||
* context.
|
||||
* <p>
|
||||
* Such beans are registered after regular {@linkplain #withUserConfiguration(Class[])
|
||||
* user configurations} in the order of registration.
|
||||
* @param beanType the type of the bean
|
||||
* @param beanDefinition a supplier for the bean
|
||||
* @param <T> the type of the bean
|
||||
* @return a new instance with the updated bean
|
||||
*/
|
||||
public <T> SELF withBean(Class<T> beanType, Supplier<T> beanDefinition) {
|
||||
return withBean(null, beanType, beanDefinition);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the specified user bean with the {@link ApplicationContext}. The bean name
|
||||
* is generated from the configured {@link BeanNameGenerator} on the underlying
|
||||
* context.
|
||||
* <p>
|
||||
* Such beans are registered after regular {@linkplain #withUserConfiguration(Class[])
|
||||
* user configurations} in the order of registration.
|
||||
* @param beanType the type of the bean
|
||||
* @param beanDefinition a function that accepts the context and return the bean
|
||||
* @param <T> the type of the bean
|
||||
* @return a new instance with the updated bean
|
||||
*/
|
||||
public <T> SELF withBean(Class<T> beanType, Function<? super C, T> beanDefinition) {
|
||||
return withBean(null, beanType, beanDefinition);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the specified user bean with the {@link ApplicationContext}. If no bean
|
||||
* name is provided, a default one is generated from the configured
|
||||
* {@link BeanNameGenerator} on the underlying context.
|
||||
* <p>
|
||||
* Such beans are registered after regular {@linkplain #withUserConfiguration(Class[])
|
||||
* user configurations} in the order of registration.
|
||||
* @param beanName the name of the bean (may be {@code null})
|
||||
* @param beanType the type of the bean
|
||||
* @param beanDefinition a supplier for the bean
|
||||
* @param <T> the type of the bean
|
||||
* @return a new instance with the updated bean
|
||||
*/
|
||||
public <T> SELF withBean(String beanName, Class<T> beanType,
|
||||
Supplier<T> beanDefinition) {
|
||||
return withBean(beanName, beanType, (context) -> beanDefinition.get());
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the specified user bean with the {@link ApplicationContext}. If no bean
|
||||
* name is provided, a default one is generated from the configured
|
||||
* {@link BeanNameGenerator} on the underlying context.
|
||||
* <p>
|
||||
* Such beans are registered after regular {@linkplain #withUserConfiguration(Class[])
|
||||
* user configurations} in the order of registration.
|
||||
* @param beanName the name of the bean (may be {@code null})
|
||||
* @param beanType the type of the bean
|
||||
* @param beanDefinition a function that accepts the context and return the bean
|
||||
* @param <T> the type of the bean
|
||||
* @return a new instance with the updated bean
|
||||
*/
|
||||
public <T> SELF withBean(String beanName, Class<T> beanType,
|
||||
Function<? super C, T> beanDefinition) {
|
||||
return withInitializer(
|
||||
beanDefinitionRegistrar(beanName, beanType, beanDefinition));
|
||||
}
|
||||
|
||||
private <T> ApplicationContextInitializer<? super C> beanDefinitionRegistrar(
|
||||
String beanName, Class<T> beanType, Function<? super C, T> beanDefinition) {
|
||||
return (context) -> {
|
||||
Assert.isInstanceOf(GenericApplicationContext.class, context);
|
||||
((GenericApplicationContext) context).registerBean(beanName, beanType,
|
||||
() -> beanDefinition.apply(context));
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the specified user configuration classes with the
|
||||
* {@link ApplicationContext}.
|
||||
|
|
|
@ -39,6 +39,7 @@ import org.springframework.util.ClassUtils;
|
|||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.assertj.core.api.Assertions.assertThatIOException;
|
||||
import static org.assertj.core.api.Assertions.entry;
|
||||
|
||||
/**
|
||||
* Abstract tests for {@link AbstractApplicationContextRunner} implementations.
|
||||
|
@ -136,6 +137,45 @@ public abstract class AbstractApplicationContextRunnerTests<T extends AbstractAp
|
|||
.run((context) -> assertThat(context).hasBean("foo"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void runWithUserNamedBeanShouldRegisterBean() {
|
||||
get().withBean("foo", String.class, () -> "foo")
|
||||
.run((context) -> assertThat(context).hasBean("foo"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void runWithUserBeanShouldRegisterBeanWithDefaultName() {
|
||||
get().withBean(String.class, () -> "foo")
|
||||
.run((context) -> assertThat(context).hasBean("string"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void runWithUserBeanShouldBeRegisteredInOrder() {
|
||||
get().withBean(String.class, () -> "one").withBean(String.class, () -> "two")
|
||||
.withBean(String.class, () -> "three").run((context) -> {
|
||||
assertThat(context).hasBean("string");
|
||||
assertThat(context.getBean("string")).isEqualTo("three");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void runWithConfigurationsAndUserBeanShouldRegisterUserBeanLast() {
|
||||
get().withUserConfiguration(FooConfig.class)
|
||||
.withBean("foo", String.class, () -> "overridden").run((context) -> {
|
||||
assertThat(context).hasBean("foo");
|
||||
assertThat(context.getBean("foo")).isEqualTo("overridden");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void runWithUserBeanShouldHaveAccessToContext() {
|
||||
get().withUserConfiguration(FooConfig.class)
|
||||
.withBean(String.class, (context) -> "Result: " + context.getBean("foo"))
|
||||
.run((context) -> assertThat(context.getBeansOfType(String.class))
|
||||
.containsOnly(entry("foo", "foo"),
|
||||
entry("string", "Result: foo")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void runWithMultipleConfigurationsShouldRegisterAllConfigurations() {
|
||||
get().withUserConfiguration(FooConfig.class)
|
||||
|
|
Loading…
Reference in New Issue