diff --git a/spring-test/src/main/java/org/springframework/test/context/aot/AotContextLoader.java b/spring-test/src/main/java/org/springframework/test/context/aot/AotContextLoader.java index 25d64980732..9c0d2136858 100644 --- a/spring-test/src/main/java/org/springframework/test/context/aot/AotContextLoader.java +++ b/spring-test/src/main/java/org/springframework/test/context/aot/AotContextLoader.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2025 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. @@ -16,6 +16,7 @@ package org.springframework.test.context.aot; +import org.springframework.aot.hint.RuntimeHints; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextInitializer; import org.springframework.context.ConfigurableApplicationContext; @@ -25,9 +26,9 @@ import org.springframework.test.context.SmartContextLoader; /** * Strategy interface for loading an {@link ApplicationContext} for build-time - * {@linkplain #loadContextForAotProcessing AOT processing} as well as run-time - * {@linkplain #loadContextForAotRuntime AOT execution} for an integration test - * managed by the Spring TestContext Framework. + * {@linkplain #loadContextForAotProcessing(MergedContextConfiguration, RuntimeHints) + * AOT processing} as well as run-time {@linkplain #loadContextForAotRuntime + * AOT execution} for an integration test managed by the Spring TestContext Framework. * *

{@code AotContextLoader} is an extension of the {@link SmartContextLoader} * SPI that allows a context loader to optionally provide ahead-of-time (AOT) @@ -42,6 +43,30 @@ import org.springframework.test.context.SmartContextLoader; */ public interface AotContextLoader extends SmartContextLoader { + /** + * Load a new {@link ApplicationContext} for AOT build-time processing based + * on the supplied {@link MergedContextConfiguration}, configure the context, + * and return the context. + *

The default implementation of this method throws an + * {@link UnsupportedOperationException}. Note, however, that the framework + * invokes {@link #loadContextForAotProcessing(MergedContextConfiguration, RuntimeHints)} + * as of Spring Framework 6.2.4. + * @param mergedConfig the merged context configuration to use to load the + * application context + * @return a new {@code GenericApplicationContext} + * @throws ContextLoadException if context loading failed + * @see #loadContextForAotProcessing(MergedContextConfiguration, RuntimeHints) + * @see #loadContextForAotRuntime(MergedContextConfiguration, ApplicationContextInitializer) + * @deprecated as of Spring Framework 6.2.4, in favor of + * {@link #loadContextForAotProcessing(MergedContextConfiguration, RuntimeHints)}; + * to be removed in Spring Framework 8.0 + */ + @Deprecated(since = "6.2.4", forRemoval = true) + default ApplicationContext loadContextForAotProcessing(MergedContextConfiguration mergedConfig) throws Exception { + throw new UnsupportedOperationException( + "Invoke loadContextForAotProcessing(MergedContextConfiguration, RuntimeHints) instead"); + } + /** * Load a new {@link ApplicationContext} for AOT build-time processing based * on the supplied {@link MergedContextConfiguration}, configure the context, @@ -65,13 +90,23 @@ public interface AotContextLoader extends SmartContextLoader { * throw new ContextLoadException(context, ex); * } * + *

For backward compatibility, the default implementation of this method + * delegates to {@link #loadContextForAotProcessing(MergedContextConfiguration)}. + * Note, however, that the framework only invokes this method as of Spring + * Framework 6.2.4. * @param mergedConfig the merged context configuration to use to load the * application context + * @param runtimeHints the runtime hints * @return a new {@code GenericApplicationContext} * @throws ContextLoadException if context loading failed + * @since 6.2.4 * @see #loadContextForAotRuntime(MergedContextConfiguration, ApplicationContextInitializer) */ - ApplicationContext loadContextForAotProcessing(MergedContextConfiguration mergedConfig) throws Exception; + default ApplicationContext loadContextForAotProcessing(MergedContextConfiguration mergedConfig, + RuntimeHints runtimeHints) throws Exception { + + return loadContextForAotProcessing(mergedConfig); + } /** * Load a new {@link ApplicationContext} for AOT run-time execution based on @@ -98,7 +133,7 @@ public interface AotContextLoader extends SmartContextLoader { * be applied to the context in order to recreate bean definitions * @return a new {@code GenericApplicationContext} * @throws ContextLoadException if context loading failed - * @see #loadContextForAotProcessing(MergedContextConfiguration) + * @see #loadContextForAotProcessing(MergedContextConfiguration, RuntimeHints) */ ApplicationContext loadContextForAotRuntime(MergedContextConfiguration mergedConfig, ApplicationContextInitializer initializer) throws Exception; diff --git a/spring-test/src/main/java/org/springframework/test/context/aot/TestContextAotGenerator.java b/spring-test/src/main/java/org/springframework/test/context/aot/TestContextAotGenerator.java index 7d81e97629d..953aa1094ff 100644 --- a/spring-test/src/main/java/org/springframework/test/context/aot/TestContextAotGenerator.java +++ b/spring-test/src/main/java/org/springframework/test/context/aot/TestContextAotGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 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. @@ -331,7 +331,7 @@ public class TestContextAotGenerator { * create {@link GenericApplicationContext GenericApplicationContexts}. * @throws TestContextAotException if an error occurs while loading the application * context or if one of the prerequisites is not met - * @see AotContextLoader#loadContextForAotProcessing(MergedContextConfiguration) + * @see AotContextLoader#loadContextForAotProcessing(MergedContextConfiguration, RuntimeHints) */ private GenericApplicationContext loadContextForAotProcessing( MergedContextConfiguration mergedConfig) throws TestContextAotException { @@ -345,7 +345,7 @@ public class TestContextAotGenerator { if (contextLoader instanceof AotContextLoader aotContextLoader) { try { - ApplicationContext context = aotContextLoader.loadContextForAotProcessing(mergedConfig); + ApplicationContext context = aotContextLoader.loadContextForAotProcessing(mergedConfig, this.runtimeHints); if (context instanceof GenericApplicationContext gac) { return gac; } diff --git a/spring-test/src/main/java/org/springframework/test/context/support/AbstractDelegatingSmartContextLoader.java b/spring-test/src/main/java/org/springframework/test/context/support/AbstractDelegatingSmartContextLoader.java index 4cc99d69a42..a06130c4ae8 100644 --- a/spring-test/src/main/java/org/springframework/test/context/support/AbstractDelegatingSmartContextLoader.java +++ b/spring-test/src/main/java/org/springframework/test/context/support/AbstractDelegatingSmartContextLoader.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2023 the original author or authors. + * Copyright 2002-2025 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,6 +19,7 @@ package org.springframework.test.context.support; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.springframework.aot.hint.RuntimeHints; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextInitializer; import org.springframework.context.ConfigurableApplicationContext; @@ -225,8 +226,13 @@ public abstract class AbstractDelegatingSmartContextLoader implements AotContext * {@code ApplicationContext} from the supplied merged context configuration * @since 6.0 * @see AotContextLoader#loadContextForAotProcessing(MergedContextConfiguration) + * @deprecated as of Spring Framework 6.2.4, in favor of + * {@link #loadContextForAotProcessing(MergedContextConfiguration, RuntimeHints)}; + * to be removed in Spring Framework 8.0 */ + @Deprecated(since = "6.2.4", forRemoval = true) @Override + @SuppressWarnings("removal") public final ApplicationContext loadContextForAotProcessing(MergedContextConfiguration mergedConfig) throws Exception { AotContextLoader loader = getAotContextLoader(mergedConfig); if (logger.isTraceEnabled()) { @@ -236,6 +242,33 @@ public abstract class AbstractDelegatingSmartContextLoader implements AotContext return loader.loadContextForAotProcessing(mergedConfig); } + /** + * Delegates to an appropriate candidate {@code SmartContextLoader} to load + * an {@link ApplicationContext} for AOT processing. + *

Delegation is based on explicit knowledge of the implementations of the + * default loaders. See {@link #loadContext(MergedContextConfiguration)} for + * details. + * @param mergedConfig the merged context configuration to use to load the application context + * @param runtimeHints the runtime hints + * @return a new application context + * @throws IllegalArgumentException if the supplied merged configuration is {@code null} + * @throws IllegalStateException if neither candidate loader is capable of loading an + * {@code ApplicationContext} from the supplied merged context configuration + * @since 6.2.4 + * @see AotContextLoader#loadContextForAotProcessing(MergedContextConfiguration, RuntimeHints) + */ + @Override + public final ApplicationContext loadContextForAotProcessing(MergedContextConfiguration mergedConfig, + RuntimeHints runtimeHints) throws Exception { + + AotContextLoader loader = getAotContextLoader(mergedConfig); + if (logger.isTraceEnabled()) { + logger.trace("Delegating to %s to load context for AOT processing for %s" + .formatted(name(loader), mergedConfig)); + } + return loader.loadContextForAotProcessing(mergedConfig, runtimeHints); + } + /** * Delegates to an appropriate candidate {@code SmartContextLoader} to load * an {@link ApplicationContext} for AOT run-time execution. diff --git a/spring-test/src/main/java/org/springframework/test/context/support/AbstractGenericContextLoader.java b/spring-test/src/main/java/org/springframework/test/context/support/AbstractGenericContextLoader.java index 17336b18bbd..e1dbb4d6204 100644 --- a/spring-test/src/main/java/org/springframework/test/context/support/AbstractGenericContextLoader.java +++ b/spring-test/src/main/java/org/springframework/test/context/support/AbstractGenericContextLoader.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2025 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. @@ -21,6 +21,7 @@ import java.util.Arrays; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.springframework.aot.hint.RuntimeHints; import org.springframework.beans.factory.support.BeanDefinitionReader; import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.context.ApplicationContext; @@ -126,10 +127,41 @@ public abstract class AbstractGenericContextLoader extends AbstractContextLoader * @throws Exception if context loading failed * @since 6.0 * @see AotContextLoader#loadContextForAotProcessing(MergedContextConfiguration) + * @deprecated as of Spring Framework 6.2.4, in favor of + * {@link #loadContextForAotProcessing(MergedContextConfiguration, RuntimeHints)}; + * to be removed in Spring Framework 8.0 */ + @Deprecated(since = "6.2.4", forRemoval = true) @Override + @SuppressWarnings("removal") public final GenericApplicationContext loadContextForAotProcessing(MergedContextConfiguration mergedConfig) throws Exception { + + return loadContext(mergedConfig, true); + } + + /** + * Load a {@link GenericApplicationContext} for AOT build-time processing based + * on the supplied {@link MergedContextConfiguration}. + *

In contrast to {@link #loadContext(MergedContextConfiguration)}, this + * method does not + * {@linkplain org.springframework.context.ConfigurableApplicationContext#refresh() + * refresh} the {@code ApplicationContext} or + * {@linkplain org.springframework.context.ConfigurableApplicationContext#registerShutdownHook() + * register a JVM shutdown hook} for it. Otherwise, this method implements + * behavior identical to {@link #loadContext(MergedContextConfiguration)}. + * @param mergedConfig the merged context configuration to use to load the + * application context + * @param runtimeHints the runtime hints + * @return a new application context + * @throws Exception if context loading failed + * @since 6.2.4 + * @see AotContextLoader#loadContextForAotProcessing(MergedContextConfiguration, RuntimeHints) + */ + @Override + public final GenericApplicationContext loadContextForAotProcessing(MergedContextConfiguration mergedConfig, + RuntimeHints runtimeHints) throws Exception { + return loadContext(mergedConfig, true); } diff --git a/spring-test/src/main/java/org/springframework/test/context/web/AbstractGenericWebContextLoader.java b/spring-test/src/main/java/org/springframework/test/context/web/AbstractGenericWebContextLoader.java index f57c086cfc8..8c98de4e06d 100644 --- a/spring-test/src/main/java/org/springframework/test/context/web/AbstractGenericWebContextLoader.java +++ b/spring-test/src/main/java/org/springframework/test/context/web/AbstractGenericWebContextLoader.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2023 the original author or authors. + * Copyright 2002-2025 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. @@ -20,6 +20,7 @@ import jakarta.servlet.ServletContext; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.springframework.aot.hint.RuntimeHints; import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextInitializer; @@ -120,10 +121,41 @@ public abstract class AbstractGenericWebContextLoader extends AbstractContextLoa * @throws Exception if context loading failed * @since 6.0 * @see AotContextLoader#loadContextForAotProcessing(MergedContextConfiguration) + * @deprecated as of Spring Framework 6.2.4, in favor of + * {@link #loadContextForAotProcessing(MergedContextConfiguration, RuntimeHints)}; + * to be removed in Spring Framework 8.0 */ + @Deprecated(since = "6.2.4", forRemoval = true) @Override + @SuppressWarnings("removal") public final GenericWebApplicationContext loadContextForAotProcessing(MergedContextConfiguration mergedConfig) throws Exception { + + return loadContext(mergedConfig, true); + } + + /** + * Load a {@link GenericWebApplicationContext} for AOT build-time processing based + * on the supplied {@link MergedContextConfiguration}. + *

In contrast to {@link #loadContext(MergedContextConfiguration)}, this + * method does not + * {@linkplain org.springframework.context.ConfigurableApplicationContext#refresh() + * refresh} the {@code ApplicationContext} or + * {@linkplain org.springframework.context.ConfigurableApplicationContext#registerShutdownHook() + * register a JVM shutdown hook} for it. Otherwise, this method implements + * behavior identical to {@link #loadContext(MergedContextConfiguration)}. + * @param mergedConfig the merged context configuration to use to load the + * application context + * @param runtimeHints the runtime hints + * @return a new web application context + * @throws Exception if context loading failed + * @since 6.2.4 + * @see AotContextLoader#loadContextForAotProcessing(MergedContextConfiguration, RuntimeHints) + */ + @Override + public final GenericWebApplicationContext loadContextForAotProcessing(MergedContextConfiguration mergedConfig, + RuntimeHints runtimeHints) throws Exception { + return loadContext(mergedConfig, true); } @@ -187,7 +219,7 @@ public abstract class AbstractGenericWebContextLoader extends AbstractContextLoa * register a JVM shutdown hook for it * @return a new web application context * @see org.springframework.test.context.SmartContextLoader#loadContext(MergedContextConfiguration) - * @see org.springframework.test.context.aot.AotContextLoader#loadContextForAotProcessing(MergedContextConfiguration) + * @see org.springframework.test.context.aot.AotContextLoader#loadContextForAotProcessing(MergedContextConfiguration, RuntimeHints) */ private GenericWebApplicationContext loadContext( MergedContextConfiguration mergedConfig, boolean forAotProcessing) throws Exception { diff --git a/spring-test/src/test/java/org/springframework/test/context/aot/AbstractAotContextLoader.java b/spring-test/src/test/java/org/springframework/test/context/aot/AbstractAotContextLoader.java new file mode 100644 index 00000000000..bf32f4e94f9 --- /dev/null +++ b/spring-test/src/test/java/org/springframework/test/context/aot/AbstractAotContextLoader.java @@ -0,0 +1,49 @@ +/* + * Copyright 2002-2025 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.aot; + +import org.springframework.context.ApplicationContextInitializer; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.support.GenericApplicationContext; +import org.springframework.context.support.StaticApplicationContext; +import org.springframework.test.context.MergedContextConfiguration; +import org.springframework.test.context.support.AbstractContextLoader; + +/** + * @author Sam Brannen + * @since 6.2.4 + */ +class AbstractAotContextLoader extends AbstractContextLoader implements AotContextLoader { + + @Override + public final GenericApplicationContext loadContext(MergedContextConfiguration mergedConfig) { + return new StaticApplicationContext(); + } + + @Override + public final GenericApplicationContext loadContextForAotRuntime(MergedContextConfiguration mergedConfig, + ApplicationContextInitializer initializer) { + + return loadContext(mergedConfig); + } + + @Override + protected final String getResourceSuffix() { + throw new UnsupportedOperationException(); + } + +} diff --git a/spring-test/src/test/java/org/springframework/test/context/aot/AotContextLoaderRuntimeHintsTests.java b/spring-test/src/test/java/org/springframework/test/context/aot/AotContextLoaderRuntimeHintsTests.java new file mode 100644 index 00000000000..2da0577c23f --- /dev/null +++ b/spring-test/src/test/java/org/springframework/test/context/aot/AotContextLoaderRuntimeHintsTests.java @@ -0,0 +1,87 @@ +/* + * Copyright 2002-2025 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.aot; + +import java.lang.reflect.Method; +import java.util.stream.Stream; + +import org.junit.jupiter.api.Test; + +import org.springframework.aot.generate.InMemoryGeneratedFiles; +import org.springframework.aot.hint.ExecutableMode; +import org.springframework.aot.hint.RuntimeHints; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.support.GenericApplicationContext; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.ContextConfigurationAttributes; +import org.springframework.test.context.MergedContextConfiguration; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.aot.hint.predicate.RuntimeHintsPredicates.reflection; + +/** + * Tests for registering run-time hints within an {@link AotContextLoader}, tested + * via the {@link TestContextAotGenerator}. + * + * @author Sam Brannen + * @since 6.2.4 + */ +class AotContextLoaderRuntimeHintsTests { + + @Test // gh-34513 + void aotContextLoaderCanRegisterRuntimeHints() { + RuntimeHints runtimeHints = new RuntimeHints(); + TestContextAotGenerator generator = new TestContextAotGenerator(new InMemoryGeneratedFiles(), runtimeHints); + + generator.processAheadOfTime(Stream.of(TestCase.class)); + + assertThat(reflection().onMethod(ConfigWithMain.class, "main").invoke()).accepts(runtimeHints); + } + + + @ContextConfiguration(classes = ConfigWithMain.class, loader = RuntimeHintsAwareAotContextLoader.class) + static class TestCase { + } + + @Configuration(proxyBeanMethods = false) + static class ConfigWithMain { + + public static void main(String[] args) { + // Mimics main() method for Spring Boot app + } + } + + static class RuntimeHintsAwareAotContextLoader extends AbstractAotContextLoader { + + @Override + public void processContextConfiguration(ContextConfigurationAttributes configAttributes) { + /* no-op */ + } + + @Override + public GenericApplicationContext loadContextForAotProcessing(MergedContextConfiguration mergedConfig, + RuntimeHints runtimeHints) throws Exception { + + // Mimics SpringBootContextLoader + Method mainMethod = mergedConfig.getClasses()[0].getMethod("main", String[].class); + runtimeHints.reflection().registerMethod(mainMethod, ExecutableMode.INVOKE); + + return loadContext(mergedConfig); + } + } + +} diff --git a/spring-test/src/test/java/org/springframework/test/context/aot/AotContextLoaderTests.java b/spring-test/src/test/java/org/springframework/test/context/aot/AotContextLoaderTests.java new file mode 100644 index 00000000000..e82ff54f1f8 --- /dev/null +++ b/spring-test/src/test/java/org/springframework/test/context/aot/AotContextLoaderTests.java @@ -0,0 +1,109 @@ +/* + * Copyright 2002-2025 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.test.context.aot; + +import java.lang.reflect.Method; + +import org.junit.jupiter.api.Test; + +import org.springframework.aot.hint.RuntimeHints; +import org.springframework.context.support.GenericApplicationContext; +import org.springframework.test.context.MergedContextConfiguration; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.BDDMockito.never; +import static org.mockito.BDDMockito.spy; +import static org.mockito.BDDMockito.then; + +/** + * Unit tests for {@link AotContextLoader}. + * + * @author Sam Brannen + * @since 6.2.4 + */ +class AotContextLoaderTests { + + /** + * Verifies that a legacy {@link AotContextLoader} which only overrides + * {@link AotContextLoader#loadContextForAotProcessing(MergedContextConfiguration) + * is still supported. + */ + @Test // gh-34513 + @SuppressWarnings("removal") + void legacyAotContextLoader() throws Exception { + // Prerequisites + assertDeclaringClasses(LegacyAotContextLoader.class, LegacyAotContextLoader.class, AotContextLoader.class); + + AotContextLoader loader = spy(new LegacyAotContextLoader()); + MergedContextConfiguration mergedConfig = new MergedContextConfiguration(getClass(), null, null, null, loader); + + loader.loadContextForAotProcessing(mergedConfig, new RuntimeHints()); + + then(loader).should().loadContextForAotProcessing(mergedConfig); + } + + /** + * Verifies that a modern {@link AotContextLoader} which only overrides + * {@link AotContextLoader#loadContextForAotProcessing(MergedContextConfiguration, RuntimeHints) + * is supported. + */ + @Test // gh-34513 + @SuppressWarnings("removal") + void runtimeHintsAwareAotContextLoader() throws Exception { + // Prerequisites + assertDeclaringClasses(RuntimeHintsAwareAotContextLoader.class, AotContextLoader.class, RuntimeHintsAwareAotContextLoader.class); + + AotContextLoader loader = spy(new RuntimeHintsAwareAotContextLoader()); + MergedContextConfiguration mergedConfig = new MergedContextConfiguration(getClass(), null, null, null, loader); + + loader.loadContextForAotProcessing(mergedConfig, new RuntimeHints()); + + then(loader).should(never()).loadContextForAotProcessing(mergedConfig); + } + + + private static void assertDeclaringClasses(Class loaderClass, + Class declaringClassForLegacyMethod, Class declaringClassForNewMethod) throws Exception { + + Method legacyMethod = loaderClass.getMethod("loadContextForAotProcessing", MergedContextConfiguration.class); + Method newMethod = loaderClass.getMethod("loadContextForAotProcessing", MergedContextConfiguration.class, RuntimeHints.class); + + assertThat(legacyMethod.getDeclaringClass()).isEqualTo(declaringClassForLegacyMethod); + assertThat(newMethod.getDeclaringClass()).isEqualTo(declaringClassForNewMethod); + } + + + private static class LegacyAotContextLoader extends AbstractAotContextLoader { + + @Override + @SuppressWarnings("removal") + public GenericApplicationContext loadContextForAotProcessing(MergedContextConfiguration mergedConfig) { + return loadContext(mergedConfig); + } + } + + private static class RuntimeHintsAwareAotContextLoader extends AbstractAotContextLoader { + + @Override + public GenericApplicationContext loadContextForAotProcessing(MergedContextConfiguration mergedConfig, + RuntimeHints runtimeHints) { + + return loadContext(mergedConfig); + } + } + +} diff --git a/spring-test/src/test/java/org/springframework/test/context/support/AnnotationConfigContextLoaderTests.java b/spring-test/src/test/java/org/springframework/test/context/support/AnnotationConfigContextLoaderTests.java index 45dc4b47fab..81753a95374 100644 --- a/spring-test/src/test/java/org/springframework/test/context/support/AnnotationConfigContextLoaderTests.java +++ b/spring-test/src/test/java/org/springframework/test/context/support/AnnotationConfigContextLoaderTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 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. @@ -20,6 +20,7 @@ import java.util.Arrays; import org.junit.jupiter.api.Test; +import org.springframework.aot.hint.RuntimeHints; import org.springframework.context.ApplicationContext; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.test.context.MergedContextConfiguration; @@ -79,7 +80,7 @@ class AnnotationConfigContextLoaderTests { AnnotatedFooConfigInnerClassTestCase.class, EMPTY_STRING_ARRAY, new Class[] {AnnotatedFooConfigInnerClassTestCase.FooConfig.class}, EMPTY_STRING_ARRAY, contextLoader); - ConfigurableApplicationContext context = contextLoader.loadContextForAotProcessing(mergedConfig); + ConfigurableApplicationContext context = contextLoader.loadContextForAotProcessing(mergedConfig, new RuntimeHints()); assertThat(context.isActive()).as("ApplicationContext is active").isFalse(); assertThat(Arrays.stream(context.getBeanDefinitionNames())).anyMatch(name -> name.contains("FooConfig")); context.close(); diff --git a/spring-test/src/test/java/org/springframework/test/context/support/DelegatingSmartContextLoaderTests.java b/spring-test/src/test/java/org/springframework/test/context/support/DelegatingSmartContextLoaderTests.java index 4da0bd8a3cd..9264e061a36 100644 --- a/spring-test/src/test/java/org/springframework/test/context/support/DelegatingSmartContextLoaderTests.java +++ b/spring-test/src/test/java/org/springframework/test/context/support/DelegatingSmartContextLoaderTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 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. @@ -21,6 +21,7 @@ import java.util.Arrays; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import org.springframework.aot.hint.RuntimeHints; import org.springframework.context.ApplicationContext; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.Bean; @@ -181,7 +182,7 @@ class DelegatingSmartContextLoaderTests { private void assertApplicationContextLoadsForAotProcessing(MergedContextConfiguration mergedConfig, String expectedBeanDefName) throws Exception { - ApplicationContext context = loader.loadContextForAotProcessing(mergedConfig); + ApplicationContext context = loader.loadContextForAotProcessing(mergedConfig, new RuntimeHints()); assertThat(context).isInstanceOf(ConfigurableApplicationContext.class); ConfigurableApplicationContext cac = (ConfigurableApplicationContext) context; assertThat(cac.isActive()).as("ApplicationContext is active").isFalse();