diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/web/servlet/WebMvcEndpointChildContextConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/web/servlet/WebMvcEndpointChildContextConfigurationTests.java index e4aa6e719f..3cc74b437f 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/web/servlet/WebMvcEndpointChildContextConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/web/servlet/WebMvcEndpointChildContextConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2020 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. @@ -35,7 +35,8 @@ import static org.assertj.core.api.Assertions.assertThat; */ class WebMvcEndpointChildContextConfigurationTests { - private WebApplicationContextRunner contextRunner = new WebApplicationContextRunner(); + private WebApplicationContextRunner contextRunner = new WebApplicationContextRunner() + .withAllowBeanDefinitionOverriding(true); @Test void contextShouldConfigureRequestContextFilter() { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnBeanTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnBeanTests.java index b588ccfe8c..5e7c9b37c1 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnBeanTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnBeanTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2020 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. @@ -136,8 +136,8 @@ class ConditionalOnBeanTests { @Test void conditionEvaluationConsidersChangeInTypeWhenBeanIsOverridden() { - this.contextRunner.withUserConfiguration(OriginalDefinition.class, OverridingDefinition.class, - ConsumingConfiguration.class).run((context) -> { + this.contextRunner.withAllowBeanDefinitionOverriding(true).withUserConfiguration(OriginalDefinition.class, + OverridingDefinition.class, ConsumingConfiguration.class).run((context) -> { assertThat(context).hasBean("testBean"); assertThat(context).hasSingleBean(Integer.class); assertThat(context).doesNotHaveBean(ConsumingConfiguration.class); diff --git a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/runner/AbstractApplicationContextRunner.java b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/runner/AbstractApplicationContextRunner.java index 0c116a86a8..ee7dfd87a7 100644 --- a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/runner/AbstractApplicationContextRunner.java +++ b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/runner/AbstractApplicationContextRunner.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2020 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,7 +25,9 @@ import java.util.function.Supplier; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.BeanDefinitionCustomizer; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.support.BeanNameGenerator; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.boot.context.annotation.Configurations; import org.springframework.boot.context.annotation.UserConfigurations; import org.springframework.boot.test.context.FilteredClassLoader; @@ -105,6 +107,8 @@ public abstract class AbstractApplicationContextRunner contextFactory; + private final boolean allowBeanDefinitionOverriding; + private final List> initializers; private final TestPropertyValues environmentProperties; @@ -124,13 +128,14 @@ public abstract class AbstractApplicationContextRunner contextFactory) { - this(contextFactory, Collections.emptyList(), TestPropertyValues.empty(), TestPropertyValues.empty(), null, - null, Collections.emptyList(), Collections.emptyList()); + this(contextFactory, false, Collections.emptyList(), TestPropertyValues.empty(), TestPropertyValues.empty(), + null, null, Collections.emptyList(), Collections.emptyList()); } /** * Create a new {@link AbstractApplicationContextRunner} instance. * @param contextFactory the factory used to create the actual context + * @param allowBeanDefinitionOverriding whether bean definition overriding is allowed * @param initializers the initializers * @param environmentProperties the environment properties * @param systemProperties the system properties @@ -139,7 +144,7 @@ public abstract class AbstractApplicationContextRunner contextFactory, + protected AbstractApplicationContextRunner(Supplier contextFactory, boolean allowBeanDefinitionOverriding, List> initializers, TestPropertyValues environmentProperties, TestPropertyValues systemProperties, ClassLoader classLoader, ApplicationContext parent, List> beanRegistrations, List configurations) { @@ -149,6 +154,7 @@ public abstract class AbstractApplicationContextRunner initializer) { Assert.notNull(initializer, "Initializer must not be null"); - return newInstance(this.contextFactory, add(this.initializers, initializer), this.environmentProperties, - this.systemProperties, this.classLoader, this.parent, this.beanRegistrations, this.configurations); + return newInstance(this.contextFactory, this.allowBeanDefinitionOverriding, add(this.initializers, initializer), + this.environmentProperties, this.systemProperties, this.classLoader, this.parent, + this.beanRegistrations, this.configurations); } /** @@ -181,8 +202,9 @@ public abstract class AbstractApplicationContextRunner SELF withBean(String name, Class type, Object... constructorArgs) { - return newInstance(this.contextFactory, this.initializers, this.environmentProperties, this.systemProperties, - this.classLoader, this.parent, + return newInstance(this.contextFactory, this.allowBeanDefinitionOverriding, this.initializers, + this.environmentProperties, this.systemProperties, this.classLoader, this.parent, add(this.beanRegistrations, new BeanRegistration<>(name, type, constructorArgs)), this.configurations); } @@ -296,8 +320,8 @@ public abstract class AbstractApplicationContextRunner SELF withBean(String name, Class type, Supplier supplier, BeanDefinitionCustomizer... customizers) { - return newInstance(this.contextFactory, this.initializers, this.environmentProperties, this.systemProperties, - this.classLoader, this.parent, + return newInstance(this.contextFactory, this.allowBeanDefinitionOverriding, this.initializers, + this.environmentProperties, this.systemProperties, this.classLoader, this.parent, add(this.beanRegistrations, new BeanRegistration<>(name, type, supplier, customizers)), this.configurations); } @@ -319,8 +343,9 @@ public abstract class AbstractApplicationContextRunner contextFactory, + protected abstract SELF newInstance(Supplier contextFactory, boolean allowBeanDefinitionOverriding, List> initializers, TestPropertyValues environmentProperties, TestPropertyValues systemProperties, ClassLoader classLoader, ApplicationContext parent, List> beanRegistrations, List configurations); @@ -388,6 +413,11 @@ public abstract class AbstractApplicationContextRunner contextFactory, + boolean allowBeanDefinitionOverriding, List> initializers, TestPropertyValues environmentProperties, TestPropertyValues systemProperties, ClassLoader classLoader, ApplicationContext parent, List> beanRegistrations, List configurations) { - super(contextFactory, initializers, environmentProperties, systemProperties, classLoader, parent, - beanRegistrations, configurations); + super(contextFactory, allowBeanDefinitionOverriding, initializers, environmentProperties, systemProperties, + classLoader, parent, beanRegistrations, configurations); } @Override protected ApplicationContextRunner newInstance(Supplier contextFactory, + boolean allowBeanDefinitionOverriding, List> initializers, TestPropertyValues environmentProperties, TestPropertyValues systemProperties, ClassLoader classLoader, ApplicationContext parent, List> beanRegistrations, List configurations) { - return new ApplicationContextRunner(contextFactory, initializers, environmentProperties, systemProperties, - classLoader, parent, beanRegistrations, configurations); + return new ApplicationContextRunner(contextFactory, allowBeanDefinitionOverriding, initializers, + environmentProperties, systemProperties, classLoader, parent, beanRegistrations, configurations); } } diff --git a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/runner/ReactiveWebApplicationContextRunner.java b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/runner/ReactiveWebApplicationContextRunner.java index 7f05a8743f..932e27ff85 100644 --- a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/runner/ReactiveWebApplicationContextRunner.java +++ b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/runner/ReactiveWebApplicationContextRunner.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2020 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. @@ -59,23 +59,24 @@ public final class ReactiveWebApplicationContextRunner extends } private ReactiveWebApplicationContextRunner(Supplier contextFactory, + boolean allowBeanDefinitionOverriding, List> initializers, TestPropertyValues environmentProperties, TestPropertyValues systemProperties, ClassLoader classLoader, ApplicationContext parent, List> beanRegistrations, List configurations) { - super(contextFactory, initializers, environmentProperties, systemProperties, classLoader, parent, - beanRegistrations, configurations); + super(contextFactory, allowBeanDefinitionOverriding, initializers, environmentProperties, systemProperties, + classLoader, parent, beanRegistrations, configurations); } @Override protected ReactiveWebApplicationContextRunner newInstance( - Supplier contextFactory, + Supplier contextFactory, boolean allowBeanDefinitionOverriding, List> initializers, TestPropertyValues environmentProperties, TestPropertyValues systemProperties, ClassLoader classLoader, ApplicationContext parent, List> beanRegistrations, List configurations) { - return new ReactiveWebApplicationContextRunner(contextFactory, initializers, environmentProperties, - systemProperties, classLoader, parent, beanRegistrations, configurations); + return new ReactiveWebApplicationContextRunner(contextFactory, allowBeanDefinitionOverriding, initializers, + environmentProperties, systemProperties, classLoader, parent, beanRegistrations, configurations); } } diff --git a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/runner/WebApplicationContextRunner.java b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/runner/WebApplicationContextRunner.java index 1df1bca5fc..8f9c671cd0 100644 --- a/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/runner/WebApplicationContextRunner.java +++ b/spring-boot-project/spring-boot-test/src/main/java/org/springframework/boot/test/context/runner/WebApplicationContextRunner.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2020 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. @@ -63,22 +63,24 @@ public final class WebApplicationContextRunner extends } private WebApplicationContextRunner(Supplier contextFactory, + boolean allowBeanDefinitionOverriding, List> initializers, TestPropertyValues environmentProperties, TestPropertyValues systemProperties, ClassLoader classLoader, ApplicationContext parent, List> beanRegistrations, List configurations) { - super(contextFactory, initializers, environmentProperties, systemProperties, classLoader, parent, - beanRegistrations, configurations); + super(contextFactory, allowBeanDefinitionOverriding, initializers, environmentProperties, systemProperties, + classLoader, parent, beanRegistrations, configurations); } @Override protected WebApplicationContextRunner newInstance(Supplier contextFactory, + boolean allowBeanDefinitionOverriding, List> initializers, TestPropertyValues environmentProperties, TestPropertyValues systemProperties, ClassLoader classLoader, ApplicationContext parent, List> beanRegistrations, List configurations) { - return new WebApplicationContextRunner(contextFactory, initializers, environmentProperties, systemProperties, - classLoader, parent, beanRegistrations, configurations); + return new WebApplicationContextRunner(contextFactory, allowBeanDefinitionOverriding, initializers, + environmentProperties, systemProperties, classLoader, parent, beanRegistrations, configurations); } /** diff --git a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/runner/AbstractApplicationContextRunnerTests.java b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/runner/AbstractApplicationContextRunnerTests.java index f87e2c0a07..167adc44a7 100644 --- a/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/runner/AbstractApplicationContextRunnerTests.java +++ b/spring-boot-project/spring-boot-test/src/test/java/org/springframework/boot/test/context/runner/AbstractApplicationContextRunnerTests.java @@ -23,6 +23,7 @@ import java.util.concurrent.atomic.AtomicBoolean; import com.google.gson.Gson; import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.BeanDefinitionStoreException; import org.springframework.boot.context.annotation.UserConfigurations; import org.springframework.boot.test.context.FilteredClassLoader; import org.springframework.boot.test.context.assertj.ApplicationContextAssertProvider; @@ -139,24 +140,6 @@ abstract class AbstractApplicationContextRunnerTests "foo").run((context) -> assertThat(context).hasBean("string")); } - @Test - 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 - void runWithConfigurationsAndUserBeanShouldRegisterUserBeanLast() { - get().withUserConfiguration(FooConfig.class).withBean("foo", String.class, () -> "overridden") - .run((context) -> { - assertThat(context).hasBean("foo"); - assertThat(context.getBean("foo")).isEqualTo("overridden"); - }); - } - @Test void runWithMultipleConfigurationsShouldRegisterAllConfigurations() { get().withUserConfiguration(FooConfig.class).withConfiguration(UserConfigurations.of(BarConfig.class)) @@ -188,6 +171,34 @@ abstract class AbstractApplicationContextRunnerTests 42).run((context) -> { + assertThat(context).hasFailed(); + assertThat(context.getStartupFailure()).isInstanceOf(BeanDefinitionStoreException.class) + .hasMessageContaining("Invalid bean definition with name 'foo'") + .hasMessageContaining("@Bean definition illegally overridden by existing bean definition"); + }); + } + + @Test + void runWithUserBeanShouldBeRegisteredInOrder() { + get().withAllowBeanDefinitionOverriding(true).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 + void runWithConfigurationsAndUserBeanShouldRegisterUserBeanLast() { + get().withAllowBeanDefinitionOverriding(true).withUserConfiguration(FooConfig.class) + .withBean("foo", String.class, () -> "overridden").run((context) -> { + assertThat(context).hasBean("foo"); + assertThat(context.getBean("foo")).isEqualTo("overridden"); + }); + } + protected abstract T get(); private static void throwCheckedException(String message) throws IOException {