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 25d6498073..9c0d213685 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 7d81e97629..953aa1094f 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 4cc99d69a4..a06130c4ae 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 17336b18bb..e1dbb4d620 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 f57c086cfc..8c98de4e06 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 0000000000..bf32f4e94f
--- /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 0000000000..2da0577c23
--- /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 0000000000..e82ff54f1f
--- /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 extends AotContextLoader> 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/aot/TestPropertySourceRuntimeHintsTests.java b/spring-test/src/test/java/org/springframework/test/context/aot/TestPropertySourceRuntimeHintsTests.java
index b3daf35441..27b585b3ae 100644
--- a/spring-test/src/test/java/org/springframework/test/context/aot/TestPropertySourceRuntimeHintsTests.java
+++ b/spring-test/src/test/java/org/springframework/test/context/aot/TestPropertySourceRuntimeHintsTests.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.
@@ -38,7 +38,7 @@ import static org.assertj.core.api.Assertions.assertThatNoException;
* @author Sam Brannen
* @since 6.1
*/
-class TestPropertySourceRuntimeHintsTests extends AbstractAotTests {
+class TestPropertySourceRuntimeHintsTests {
private final RuntimeHints runtimeHints = new RuntimeHints();
@@ -93,7 +93,7 @@ class TestPropertySourceRuntimeHintsTests extends AbstractAotTests {
static class WildcardLocationPatternTestCase {
}
- @Configuration
+ @Configuration(proxyBeanMethods = false)
static class Config {
}
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 45dc4b47fa..81753a9537 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 4da0bd8a3c..9264e061a3 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();