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 dc7c7ac22a
.
See gh-29026, gh-29069
This commit is contained in:
parent
bf0ac84a05
commit
cbb30153fb
|
@ -16,7 +16,6 @@
|
|||
|
||||
package org.springframework.test.context.aot;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.stream.Stream;
|
||||
|
@ -44,14 +43,12 @@ import org.springframework.test.context.ContextLoader;
|
|||
import org.springframework.test.context.MergedContextConfiguration;
|
||||
import org.springframework.test.context.SmartContextLoader;
|
||||
import org.springframework.test.context.TestContextBootstrapper;
|
||||
import org.springframework.test.context.web.WebMergedContextConfiguration;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
import static org.springframework.aot.hint.MemberCategory.INVOKE_DECLARED_CONSTRUCTORS;
|
||||
import static org.springframework.aot.hint.MemberCategory.INVOKE_PUBLIC_METHODS;
|
||||
import static org.springframework.util.ResourceUtils.CLASSPATH_URL_PREFIX;
|
||||
|
||||
/**
|
||||
* {@code TestContextAotGenerator} generates AOT artifacts for integration tests
|
||||
|
@ -63,8 +60,6 @@ import static org.springframework.util.ResourceUtils.CLASSPATH_URL_PREFIX;
|
|||
*/
|
||||
public class TestContextAotGenerator {
|
||||
|
||||
private static final String SLASH = "/";
|
||||
|
||||
private static final Log logger = LogFactory.getLog(TestContextAotGenerator.class);
|
||||
|
||||
private final ApplicationContextAotGenerator aotGenerator = new ApplicationContextAotGenerator();
|
||||
|
@ -124,7 +119,6 @@ public class TestContextAotGenerator {
|
|||
mergedConfigMappings.forEach((mergedConfig, testClasses) -> {
|
||||
logger.debug(LogMessage.format("Generating AOT artifacts for test classes %s",
|
||||
testClasses.stream().map(Class::getName).toList()));
|
||||
registerHintsForMergedConfig(mergedConfig);
|
||||
try {
|
||||
this.testRuntimeHintsRegistrars.forEach(registrar -> registrar.registerHints(this.runtimeHints,
|
||||
mergedConfig, Collections.unmodifiableList(testClasses), getClass().getClassLoader()));
|
||||
|
@ -247,51 +241,6 @@ public class TestContextAotGenerator {
|
|||
.registerType(TypeReference.of(className), INVOKE_PUBLIC_METHODS);
|
||||
}
|
||||
|
||||
private void registerHintsForMergedConfig(MergedContextConfiguration mergedConfig) {
|
||||
// @ContextConfiguration(loader = ...)
|
||||
ContextLoader contextLoader = mergedConfig.getContextLoader();
|
||||
if (contextLoader != null) {
|
||||
registerDeclaredConstructors(contextLoader.getClass());
|
||||
}
|
||||
|
||||
// @ContextConfiguration(initializers = ...)
|
||||
mergedConfig.getContextInitializerClasses().forEach(this::registerDeclaredConstructors);
|
||||
|
||||
// @ContextConfiguration(locations = ...)
|
||||
registerHintsForClasspathResources(mergedConfig.getLocations());
|
||||
|
||||
// @TestPropertySource(locations = ... )
|
||||
registerHintsForClasspathResources(mergedConfig.getPropertySourceLocations());
|
||||
|
||||
if (mergedConfig instanceof WebMergedContextConfiguration webMergedConfig) {
|
||||
String resourceBasePath = webMergedConfig.getResourceBasePath();
|
||||
if (resourceBasePath.startsWith(CLASSPATH_URL_PREFIX)) {
|
||||
String pattern = resourceBasePath.substring(CLASSPATH_URL_PREFIX.length());
|
||||
if (!pattern.startsWith(SLASH)) {
|
||||
pattern = SLASH + pattern;
|
||||
}
|
||||
if (!pattern.endsWith(SLASH)) {
|
||||
pattern += SLASH;
|
||||
}
|
||||
pattern += "*";
|
||||
this.runtimeHints.resources().registerPattern(pattern);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void registerHintsForClasspathResources(String... locations) {
|
||||
Arrays.stream(locations)
|
||||
.filter(location -> location.startsWith(CLASSPATH_URL_PREFIX))
|
||||
.map(location -> {
|
||||
location = location.substring(CLASSPATH_URL_PREFIX.length());
|
||||
if (!location.startsWith(SLASH)) {
|
||||
location = SLASH + location;
|
||||
}
|
||||
return location;
|
||||
})
|
||||
.forEach(this.runtimeHints.resources()::registerPattern);
|
||||
}
|
||||
|
||||
private void registerDeclaredConstructors(Class<?> type) {
|
||||
ReflectionHints reflectionHints = this.runtimeHints.reflection();
|
||||
reflectionHints.registerType(type, INVOKE_DECLARED_CONSTRUCTORS);
|
||||
|
|
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* Copyright 2002-2022 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.hint;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.aot.hint.RuntimeHints;
|
||||
import org.springframework.test.context.ContextLoader;
|
||||
import org.springframework.test.context.MergedContextConfiguration;
|
||||
import org.springframework.test.context.aot.TestRuntimeHintsRegistrar;
|
||||
import org.springframework.test.context.web.WebMergedContextConfiguration;
|
||||
|
||||
import static org.springframework.aot.hint.MemberCategory.INVOKE_DECLARED_CONSTRUCTORS;
|
||||
import static org.springframework.util.ResourceUtils.CLASSPATH_URL_PREFIX;
|
||||
|
||||
/**
|
||||
* {@link TestRuntimeHintsRegistrar} implementation that registers run-time hints
|
||||
* for standard functionality in the <em>Spring TestContext Framework</em>.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @since 6.0
|
||||
* @see TestContextRuntimeHints
|
||||
*/
|
||||
class StandardTestRuntimeHints implements TestRuntimeHintsRegistrar {
|
||||
|
||||
private static final String SLASH = "/";
|
||||
|
||||
|
||||
@Override
|
||||
public void registerHints(RuntimeHints runtimeHints, MergedContextConfiguration mergedConfig,
|
||||
List<Class<?>> testClasses, ClassLoader classLoader) {
|
||||
|
||||
registerHintsForMergedContextConfiguration(runtimeHints, mergedConfig);
|
||||
}
|
||||
|
||||
private void registerHintsForMergedContextConfiguration(
|
||||
RuntimeHints runtimeHints, MergedContextConfiguration mergedConfig) {
|
||||
|
||||
// @ContextConfiguration(loader = ...)
|
||||
ContextLoader contextLoader = mergedConfig.getContextLoader();
|
||||
if (contextLoader != null) {
|
||||
registerDeclaredConstructors(runtimeHints, contextLoader.getClass());
|
||||
}
|
||||
|
||||
// @ContextConfiguration(initializers = ...)
|
||||
mergedConfig.getContextInitializerClasses()
|
||||
.forEach(clazz -> registerDeclaredConstructors(runtimeHints, clazz));
|
||||
|
||||
// @ContextConfiguration(locations = ...)
|
||||
registerClasspathResources(runtimeHints, mergedConfig.getLocations());
|
||||
|
||||
// @TestPropertySource(locations = ... )
|
||||
registerClasspathResources(runtimeHints, mergedConfig.getPropertySourceLocations());
|
||||
|
||||
// @WebAppConfiguration(value = ...)
|
||||
if (mergedConfig instanceof WebMergedContextConfiguration webConfig) {
|
||||
registerClasspathResourceDirectoryStructure(runtimeHints, webConfig.getResourceBasePath());
|
||||
}
|
||||
}
|
||||
|
||||
private void registerDeclaredConstructors(RuntimeHints runtimeHints, Class<?> type) {
|
||||
runtimeHints.reflection().registerType(type, INVOKE_DECLARED_CONSTRUCTORS);
|
||||
}
|
||||
|
||||
private void registerClasspathResources(RuntimeHints runtimeHints, String... locations) {
|
||||
Arrays.stream(locations)
|
||||
.filter(location -> location.startsWith(CLASSPATH_URL_PREFIX))
|
||||
.map(this::cleanClasspathResource)
|
||||
.forEach(runtimeHints.resources()::registerPattern);
|
||||
}
|
||||
|
||||
private void registerClasspathResourceDirectoryStructure(RuntimeHints runtimeHints, String directory) {
|
||||
if (directory.startsWith(CLASSPATH_URL_PREFIX)) {
|
||||
String pattern = cleanClasspathResource(directory);
|
||||
if (!pattern.endsWith(SLASH)) {
|
||||
pattern += SLASH;
|
||||
}
|
||||
pattern += "*";
|
||||
runtimeHints.resources().registerPattern(pattern);
|
||||
}
|
||||
}
|
||||
|
||||
private String cleanClasspathResource(String location) {
|
||||
location = location.substring(CLASSPATH_URL_PREFIX.length());
|
||||
if (!location.startsWith(SLASH)) {
|
||||
location = SLASH + location;
|
||||
}
|
||||
return location;
|
||||
}
|
||||
|
||||
}
|
|
@ -34,6 +34,7 @@ import org.springframework.util.ClassUtils;
|
|||
*
|
||||
* @author Sam Brannen
|
||||
* @since 6.0
|
||||
* @see StandardTestRuntimeHints
|
||||
*/
|
||||
class TestContextRuntimeHints implements RuntimeHintsRegistrar {
|
||||
|
||||
|
|
|
@ -1,2 +1,5 @@
|
|||
org.springframework.aot.hint.RuntimeHintsRegistrar=\
|
||||
org.springframework.test.context.aot.hint.TestContextRuntimeHints
|
||||
|
||||
org.springframework.test.context.aot.TestRuntimeHintsRegistrar=\
|
||||
org.springframework.test.context.aot.hint.StandardTestRuntimeHints
|
Loading…
Reference in New Issue