Skip to content

Commit cbb3015

Browse files
committed
Introduce StandardTestRuntimeHints in the TestContext framework
This commit introduces StandardTestRuntimeHints and migrates existing hint registration from TestContextAotGenerator to this new class. In addition, this commit removes a package cycle between context.aot and context.web that was introduced in commit dc7c7ac. See gh-29026, gh-29069
1 parent bf0ac84 commit cbb3015

File tree

4 files changed

+110
-51
lines changed

4 files changed

+110
-51
lines changed

spring-test/src/main/java/org/springframework/test/context/aot/TestContextAotGenerator.java

Lines changed: 0 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616

1717
package org.springframework.test.context.aot;
1818

19-
import java.util.Arrays;
2019
import java.util.Collections;
2120
import java.util.concurrent.atomic.AtomicInteger;
2221
import java.util.stream.Stream;
@@ -44,14 +43,12 @@
4443
import org.springframework.test.context.MergedContextConfiguration;
4544
import org.springframework.test.context.SmartContextLoader;
4645
import org.springframework.test.context.TestContextBootstrapper;
47-
import org.springframework.test.context.web.WebMergedContextConfiguration;
4846
import org.springframework.util.Assert;
4947
import org.springframework.util.LinkedMultiValueMap;
5048
import org.springframework.util.MultiValueMap;
5149

5250
import static org.springframework.aot.hint.MemberCategory.INVOKE_DECLARED_CONSTRUCTORS;
5351
import static org.springframework.aot.hint.MemberCategory.INVOKE_PUBLIC_METHODS;
54-
import static org.springframework.util.ResourceUtils.CLASSPATH_URL_PREFIX;
5552

5653
/**
5754
* {@code TestContextAotGenerator} generates AOT artifacts for integration tests
@@ -63,8 +60,6 @@
6360
*/
6461
public class TestContextAotGenerator {
6562

66-
private static final String SLASH = "/";
67-
6863
private static final Log logger = LogFactory.getLog(TestContextAotGenerator.class);
6964

7065
private final ApplicationContextAotGenerator aotGenerator = new ApplicationContextAotGenerator();
@@ -124,7 +119,6 @@ private void processAheadOfTime(MultiValueMap<MergedContextConfiguration, Class<
124119
mergedConfigMappings.forEach((mergedConfig, testClasses) -> {
125120
logger.debug(LogMessage.format("Generating AOT artifacts for test classes %s",
126121
testClasses.stream().map(Class::getName).toList()));
127-
registerHintsForMergedConfig(mergedConfig);
128122
try {
129123
this.testRuntimeHintsRegistrars.forEach(registrar -> registrar.registerHints(this.runtimeHints,
130124
mergedConfig, Collections.unmodifiableList(testClasses), getClass().getClassLoader()));
@@ -247,51 +241,6 @@ private void generateAotTestMappings(MultiValueMap<ClassName, Class<?>> initiali
247241
.registerType(TypeReference.of(className), INVOKE_PUBLIC_METHODS);
248242
}
249243

250-
private void registerHintsForMergedConfig(MergedContextConfiguration mergedConfig) {
251-
// @ContextConfiguration(loader = ...)
252-
ContextLoader contextLoader = mergedConfig.getContextLoader();
253-
if (contextLoader != null) {
254-
registerDeclaredConstructors(contextLoader.getClass());
255-
}
256-
257-
// @ContextConfiguration(initializers = ...)
258-
mergedConfig.getContextInitializerClasses().forEach(this::registerDeclaredConstructors);
259-
260-
// @ContextConfiguration(locations = ...)
261-
registerHintsForClasspathResources(mergedConfig.getLocations());
262-
263-
// @TestPropertySource(locations = ... )
264-
registerHintsForClasspathResources(mergedConfig.getPropertySourceLocations());
265-
266-
if (mergedConfig instanceof WebMergedContextConfiguration webMergedConfig) {
267-
String resourceBasePath = webMergedConfig.getResourceBasePath();
268-
if (resourceBasePath.startsWith(CLASSPATH_URL_PREFIX)) {
269-
String pattern = resourceBasePath.substring(CLASSPATH_URL_PREFIX.length());
270-
if (!pattern.startsWith(SLASH)) {
271-
pattern = SLASH + pattern;
272-
}
273-
if (!pattern.endsWith(SLASH)) {
274-
pattern += SLASH;
275-
}
276-
pattern += "*";
277-
this.runtimeHints.resources().registerPattern(pattern);
278-
}
279-
}
280-
}
281-
282-
private void registerHintsForClasspathResources(String... locations) {
283-
Arrays.stream(locations)
284-
.filter(location -> location.startsWith(CLASSPATH_URL_PREFIX))
285-
.map(location -> {
286-
location = location.substring(CLASSPATH_URL_PREFIX.length());
287-
if (!location.startsWith(SLASH)) {
288-
location = SLASH + location;
289-
}
290-
return location;
291-
})
292-
.forEach(this.runtimeHints.resources()::registerPattern);
293-
}
294-
295244
private void registerDeclaredConstructors(Class<?> type) {
296245
ReflectionHints reflectionHints = this.runtimeHints.reflection();
297246
reflectionHints.registerType(type, INVOKE_DECLARED_CONSTRUCTORS);
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
/*
2+
* Copyright 2002-2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.test.context.aot.hint;
18+
19+
import java.util.Arrays;
20+
import java.util.List;
21+
22+
import org.springframework.aot.hint.RuntimeHints;
23+
import org.springframework.test.context.ContextLoader;
24+
import org.springframework.test.context.MergedContextConfiguration;
25+
import org.springframework.test.context.aot.TestRuntimeHintsRegistrar;
26+
import org.springframework.test.context.web.WebMergedContextConfiguration;
27+
28+
import static org.springframework.aot.hint.MemberCategory.INVOKE_DECLARED_CONSTRUCTORS;
29+
import static org.springframework.util.ResourceUtils.CLASSPATH_URL_PREFIX;
30+
31+
/**
32+
* {@link TestRuntimeHintsRegistrar} implementation that registers run-time hints
33+
* for standard functionality in the <em>Spring TestContext Framework</em>.
34+
*
35+
* @author Sam Brannen
36+
* @since 6.0
37+
* @see TestContextRuntimeHints
38+
*/
39+
class StandardTestRuntimeHints implements TestRuntimeHintsRegistrar {
40+
41+
private static final String SLASH = "/";
42+
43+
44+
@Override
45+
public void registerHints(RuntimeHints runtimeHints, MergedContextConfiguration mergedConfig,
46+
List<Class<?>> testClasses, ClassLoader classLoader) {
47+
48+
registerHintsForMergedContextConfiguration(runtimeHints, mergedConfig);
49+
}
50+
51+
private void registerHintsForMergedContextConfiguration(
52+
RuntimeHints runtimeHints, MergedContextConfiguration mergedConfig) {
53+
54+
// @ContextConfiguration(loader = ...)
55+
ContextLoader contextLoader = mergedConfig.getContextLoader();
56+
if (contextLoader != null) {
57+
registerDeclaredConstructors(runtimeHints, contextLoader.getClass());
58+
}
59+
60+
// @ContextConfiguration(initializers = ...)
61+
mergedConfig.getContextInitializerClasses()
62+
.forEach(clazz -> registerDeclaredConstructors(runtimeHints, clazz));
63+
64+
// @ContextConfiguration(locations = ...)
65+
registerClasspathResources(runtimeHints, mergedConfig.getLocations());
66+
67+
// @TestPropertySource(locations = ... )
68+
registerClasspathResources(runtimeHints, mergedConfig.getPropertySourceLocations());
69+
70+
// @WebAppConfiguration(value = ...)
71+
if (mergedConfig instanceof WebMergedContextConfiguration webConfig) {
72+
registerClasspathResourceDirectoryStructure(runtimeHints, webConfig.getResourceBasePath());
73+
}
74+
}
75+
76+
private void registerDeclaredConstructors(RuntimeHints runtimeHints, Class<?> type) {
77+
runtimeHints.reflection().registerType(type, INVOKE_DECLARED_CONSTRUCTORS);
78+
}
79+
80+
private void registerClasspathResources(RuntimeHints runtimeHints, String... locations) {
81+
Arrays.stream(locations)
82+
.filter(location -> location.startsWith(CLASSPATH_URL_PREFIX))
83+
.map(this::cleanClasspathResource)
84+
.forEach(runtimeHints.resources()::registerPattern);
85+
}
86+
87+
private void registerClasspathResourceDirectoryStructure(RuntimeHints runtimeHints, String directory) {
88+
if (directory.startsWith(CLASSPATH_URL_PREFIX)) {
89+
String pattern = cleanClasspathResource(directory);
90+
if (!pattern.endsWith(SLASH)) {
91+
pattern += SLASH;
92+
}
93+
pattern += "*";
94+
runtimeHints.resources().registerPattern(pattern);
95+
}
96+
}
97+
98+
private String cleanClasspathResource(String location) {
99+
location = location.substring(CLASSPATH_URL_PREFIX.length());
100+
if (!location.startsWith(SLASH)) {
101+
location = SLASH + location;
102+
}
103+
return location;
104+
}
105+
106+
}

spring-test/src/main/java/org/springframework/test/context/aot/hint/TestContextRuntimeHints.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
*
3535
* @author Sam Brannen
3636
* @since 6.0
37+
* @see StandardTestRuntimeHints
3738
*/
3839
class TestContextRuntimeHints implements RuntimeHintsRegistrar {
3940

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,5 @@
11
org.springframework.aot.hint.RuntimeHintsRegistrar=\
22
org.springframework.test.context.aot.hint.TestContextRuntimeHints
3+
4+
org.springframework.test.context.aot.TestRuntimeHintsRegistrar=\
5+
org.springframework.test.context.aot.hint.StandardTestRuntimeHints

0 commit comments

Comments
 (0)