diff --git a/spring-test/src/main/java/org/springframework/test/context/bean/override/BeanOverrideTestExecutionListener.java b/spring-test/src/main/java/org/springframework/test/context/bean/override/BeanOverrideTestExecutionListener.java index 7e117c4b182..1fba7c75a13 100644 --- a/spring-test/src/main/java/org/springframework/test/context/bean/override/BeanOverrideTestExecutionListener.java +++ b/spring-test/src/main/java/org/springframework/test/context/bean/override/BeanOverrideTestExecutionListener.java @@ -18,7 +18,6 @@ package org.springframework.test.context.bean.override; import java.lang.reflect.Field; import java.util.List; -import java.util.function.BiConsumer; import org.springframework.test.context.TestContext; import org.springframework.test.context.support.AbstractTestExecutionListener; @@ -26,10 +25,12 @@ import org.springframework.test.context.support.DependencyInjectionTestExecution import org.springframework.util.ReflectionUtils; /** - * {@code TestExecutionListener} that enables Bean Override support in tests, - * injecting overridden beans in appropriate fields of the test instance. + * {@code TestExecutionListener} that enables {@link BeanOverride @BeanOverride} + * support in tests, by injecting overridden beans in appropriate fields of the + * test instance. * * @author Simon Baslé + * @author Sam Brannen * @since 6.2 */ public class BeanOverrideTestExecutionListener extends AbstractTestExecutionListener { @@ -42,64 +43,57 @@ public class BeanOverrideTestExecutionListener extends AbstractTestExecutionList return LOWEST_PRECEDENCE - 50; } + /** + * Inject each {@link BeanOverride @BeanOverride} field in the + * {@linkplain Object test instance} of the supplied {@linkplain TestContext + * test context} with a corresponding bean override instance. + */ @Override public void prepareTestInstance(TestContext testContext) throws Exception { - injectFields(testContext); + injectFields(testContext, false); } + /** + * Re-inject each {@link BeanOverride @BeanOverride} field in the + * {@linkplain Object test instance} of the supplied {@linkplain TestContext + * test context} with a corresponding bean override instance. + *

This method does nothing if the + * {@link DependencyInjectionTestExecutionListener#REINJECT_DEPENDENCIES_ATTRIBUTE + * REINJECT_DEPENDENCIES_ATTRIBUTE} attribute is not present in the + * {@code TestContext} with a value of {@link Boolean#TRUE}. + */ @Override public void beforeTestMethod(TestContext testContext) throws Exception { - reinjectFieldsIfNecessary(testContext); - } - - /** - * Process the test instance and make sure that fields flagged for bean - * overriding are injected with the overridden bean instance. - */ - protected void injectFields(TestContext testContext) { - postProcessFields(testContext, (testMetadata, registrar) -> - registrar.inject(testMetadata.testInstance, testMetadata.overrideMetadata)); - } - - /** - * Process the test instance and make sure that fields flagged for bean - * overriding are injected with the overridden bean instance, if necessary. - *

If a fresh instance is required, the field is nulled out and then - * re-injected with the overridden bean instance. - *

This method does nothing if the - * {@link DependencyInjectionTestExecutionListener#REINJECT_DEPENDENCIES_ATTRIBUTE} - * attribute is not present in the {@code TestContext} with a value of {@link Boolean#TRUE}. - */ - protected void reinjectFieldsIfNecessary(TestContext testContext) throws Exception { - if (Boolean.TRUE.equals( - testContext.getAttribute(DependencyInjectionTestExecutionListener.REINJECT_DEPENDENCIES_ATTRIBUTE))) { - - postProcessFields(testContext, (testMetadata, registrar) -> { - Object testInstance = testMetadata.testInstance; - Field field = testMetadata.overrideMetadata.getField(); - ReflectionUtils.makeAccessible(field); - ReflectionUtils.setField(field, testInstance, null); - registrar.inject(testInstance, testMetadata.overrideMetadata); - }); + Object reinjectDependenciesAttribute = testContext.getAttribute( + DependencyInjectionTestExecutionListener.REINJECT_DEPENDENCIES_ATTRIBUTE); + if (Boolean.TRUE.equals(reinjectDependenciesAttribute)) { + injectFields(testContext, true); } } - private void postProcessFields(TestContext testContext, BiConsumer consumer) { - - Class testClass = testContext.getTestClass(); - Object testInstance = testContext.getTestInstance(); - - List metadataForFields = OverrideMetadata.forTestClass(testClass); - if (!metadataForFields.isEmpty()) { + /** + * Inject each {@link BeanOverride @BeanOverride} field in the test instance with + * a corresponding bean override instance. + *

If the {@code reinjectFields} flag is {@code true} (which indicates that + * a fresh instance is required), the field is nulled out before injecting + * the overridden bean instance. + */ + private static void injectFields(TestContext testContext, boolean reinjectFields) { + List overrideMetadataList = OverrideMetadata.forTestClass(testContext.getTestClass()); + if (!overrideMetadataList.isEmpty()) { + Object testInstance = testContext.getTestInstance(); BeanOverrideRegistrar registrar = testContext.getApplicationContext() .getBean(BeanOverrideContextCustomizer.REGISTRAR_BEAN_NAME, BeanOverrideRegistrar.class); - for (OverrideMetadata metadata : metadataForFields) { - consumer.accept(new TestContextOverrideMetadata(testInstance, metadata), registrar); + + for (OverrideMetadata overrideMetadata : overrideMetadataList) { + if (reinjectFields) { + Field field = overrideMetadata.getField(); + ReflectionUtils.makeAccessible(field); + ReflectionUtils.setField(field, testInstance, null); + } + registrar.inject(testInstance, overrideMetadata); } } } - private record TestContextOverrideMetadata(Object testInstance, OverrideMetadata overrideMetadata) {} - }