Introduce RuntimeHintsUtils.registerResourceIfNecessary
This commit introduces a new registerResourceIfNecessary() method in RuntimeHintsUtils that simplifies the registration of hints for `classpath:` resources. Closes gh-29083
This commit is contained in:
parent
dd1e6b9412
commit
28c492cbdd
|
@ -19,11 +19,14 @@ package org.springframework.aot.hint.support;
|
|||
import java.util.function.Consumer;
|
||||
|
||||
import org.springframework.aot.hint.MemberCategory;
|
||||
import org.springframework.aot.hint.ResourceHints;
|
||||
import org.springframework.aot.hint.RuntimeHints;
|
||||
import org.springframework.aot.hint.TypeHint;
|
||||
import org.springframework.aot.hint.TypeHint.Builder;
|
||||
import org.springframework.core.annotation.AliasFor;
|
||||
import org.springframework.core.annotation.MergedAnnotation;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
|
||||
/**
|
||||
* Utility methods for runtime hints support code.
|
||||
|
@ -92,4 +95,18 @@ public abstract class RuntimeHintsUtils {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the supplied resource is a {@link ClassPathResource} that
|
||||
* {@linkplain Resource#exists() exists} and register the resource for run-time
|
||||
* availability accordingly.
|
||||
* @param hints the {@link RuntimeHints} instance to use
|
||||
* @param resource the resource to register
|
||||
* @see ResourceHints#registerPattern(String)
|
||||
*/
|
||||
public static void registerResourceIfNecessary(RuntimeHints hints, Resource resource) {
|
||||
if (resource instanceof ClassPathResource classPathResource && classPathResource.exists()) {
|
||||
hints.resources().registerPattern(classPathResource.getPath());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ import java.lang.annotation.Retention;
|
|||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.aot.hint.JdkProxyHint;
|
||||
|
@ -28,8 +29,11 @@ import org.springframework.aot.hint.TypeReference;
|
|||
import org.springframework.core.annotation.AliasFor;
|
||||
import org.springframework.core.annotation.MergedAnnotation;
|
||||
import org.springframework.core.annotation.MergedAnnotations;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.DescriptiveResource;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.springframework.aot.hint.predicate.RuntimeHintsPredicates.resource;
|
||||
|
||||
/**
|
||||
* Tests for {@link RuntimeHintsUtils}.
|
||||
|
@ -41,6 +45,39 @@ class RuntimeHintsUtilsTests {
|
|||
|
||||
private final RuntimeHints hints = new RuntimeHints();
|
||||
|
||||
@Test
|
||||
void registerResourceIfNecessaryWithUnsupportedResourceType() {
|
||||
DescriptiveResource resource = new DescriptiveResource("bogus");
|
||||
RuntimeHintsUtils.registerResourceIfNecessary(this.hints, resource);
|
||||
assertThat(this.hints.resources().resourcePatterns()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void registerResourceIfNecessaryWithNonexistentClassPathResource() {
|
||||
ClassPathResource resource = new ClassPathResource("bogus", getClass());
|
||||
RuntimeHintsUtils.registerResourceIfNecessary(this.hints, resource);
|
||||
assertThat(this.hints.resources().resourcePatterns()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void registerResourceIfNecessaryWithExistingClassPathResource() {
|
||||
String path = "org/springframework/aot/hint/support";
|
||||
ClassPathResource resource = new ClassPathResource(path);
|
||||
RuntimeHintsUtils.registerResourceIfNecessary(this.hints, resource);
|
||||
assertThat(resource().forResource(path)).accepts(this.hints);
|
||||
}
|
||||
|
||||
@Disabled("Disabled since ClassPathResource.getPath() does not honor its contract for relative resources")
|
||||
@Test
|
||||
void registerResourceIfNecessaryWithExistingRelativeClassPathResource() {
|
||||
String path = "org/springframework/aot/hint/support";
|
||||
ClassPathResource resource = new ClassPathResource("support", RuntimeHints.class);
|
||||
RuntimeHintsUtils.registerResourceIfNecessary(this.hints, resource);
|
||||
// This unfortunately fails since ClassPathResource.getPath() returns
|
||||
// "support" instead of "org/springframework/aot/hint/support".
|
||||
assertThat(resource().forResource(path)).accepts(this.hints);
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("deprecation")
|
||||
void registerSynthesizedAnnotation() {
|
||||
|
|
|
@ -20,7 +20,9 @@ import java.util.Arrays;
|
|||
import java.util.List;
|
||||
|
||||
import org.springframework.aot.hint.RuntimeHints;
|
||||
import org.springframework.aot.hint.support.RuntimeHintsUtils;
|
||||
import org.springframework.core.annotation.MergedAnnotations;
|
||||
import org.springframework.core.io.DefaultResourceLoader;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.context.ActiveProfilesResolver;
|
||||
import org.springframework.test.context.ContextLoader;
|
||||
|
@ -50,12 +52,12 @@ class StandardTestRuntimeHints implements TestRuntimeHintsRegistrar {
|
|||
public void registerHints(MergedContextConfiguration mergedConfig, List<Class<?>> testClasses,
|
||||
RuntimeHints runtimeHints, ClassLoader classLoader) {
|
||||
|
||||
registerHintsForMergedContextConfiguration(runtimeHints, mergedConfig);
|
||||
registerHintsForMergedContextConfiguration(runtimeHints, classLoader, mergedConfig);
|
||||
testClasses.forEach(testClass -> registerHintsForActiveProfilesResolvers(runtimeHints, testClass));
|
||||
}
|
||||
|
||||
private void registerHintsForMergedContextConfiguration(
|
||||
RuntimeHints runtimeHints, MergedContextConfiguration mergedConfig) {
|
||||
RuntimeHints runtimeHints, ClassLoader classLoader, MergedContextConfiguration mergedConfig) {
|
||||
|
||||
// @ContextConfiguration(loader = ...)
|
||||
ContextLoader contextLoader = mergedConfig.getContextLoader();
|
||||
|
@ -68,14 +70,14 @@ class StandardTestRuntimeHints implements TestRuntimeHintsRegistrar {
|
|||
.forEach(clazz -> registerDeclaredConstructors(runtimeHints, clazz));
|
||||
|
||||
// @ContextConfiguration(locations = ...)
|
||||
registerClasspathResources(runtimeHints, mergedConfig.getLocations());
|
||||
registerClasspathResources(mergedConfig.getLocations(), runtimeHints, classLoader);
|
||||
|
||||
// @TestPropertySource(locations = ... )
|
||||
registerClasspathResources(runtimeHints, mergedConfig.getPropertySourceLocations());
|
||||
registerClasspathResources(mergedConfig.getPropertySourceLocations(), runtimeHints, classLoader);
|
||||
|
||||
// @WebAppConfiguration(value = ...)
|
||||
if (mergedConfig instanceof WebMergedContextConfiguration webConfig) {
|
||||
registerClasspathResourceDirectoryStructure(runtimeHints, webConfig.getResourceBasePath());
|
||||
registerClasspathResourceDirectoryStructure(webConfig.getResourceBasePath(), runtimeHints);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -94,16 +96,20 @@ class StandardTestRuntimeHints implements TestRuntimeHintsRegistrar {
|
|||
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 registerClasspathResources(String[] paths, RuntimeHints runtimeHints, ClassLoader classLoader) {
|
||||
DefaultResourceLoader resourceLoader = new DefaultResourceLoader(classLoader);
|
||||
Arrays.stream(paths)
|
||||
.filter(path -> path.startsWith(CLASSPATH_URL_PREFIX))
|
||||
.map(resourceLoader::getResource)
|
||||
.forEach(resource -> RuntimeHintsUtils.registerResourceIfNecessary(runtimeHints, resource));
|
||||
}
|
||||
|
||||
private void registerClasspathResourceDirectoryStructure(RuntimeHints runtimeHints, String directory) {
|
||||
private void registerClasspathResourceDirectoryStructure(String directory, RuntimeHints runtimeHints) {
|
||||
if (directory.startsWith(CLASSPATH_URL_PREFIX)) {
|
||||
String pattern = cleanClasspathResource(directory);
|
||||
String pattern = directory.substring(CLASSPATH_URL_PREFIX.length());
|
||||
if (pattern.startsWith(SLASH)) {
|
||||
pattern = pattern.substring(1);
|
||||
}
|
||||
if (!pattern.endsWith(SLASH)) {
|
||||
pattern += SLASH;
|
||||
}
|
||||
|
@ -112,12 +118,4 @@ class StandardTestRuntimeHints implements TestRuntimeHintsRegistrar {
|
|||
}
|
||||
}
|
||||
|
||||
private String cleanClasspathResource(String location) {
|
||||
location = location.substring(CLASSPATH_URL_PREFIX.length());
|
||||
if (location.startsWith(SLASH)) {
|
||||
location = location.substring(1);
|
||||
}
|
||||
return location;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -28,10 +28,12 @@ import org.apache.commons.logging.Log;
|
|||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.aot.hint.RuntimeHints;
|
||||
import org.springframework.aot.hint.support.RuntimeHintsUtils;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||
import org.springframework.core.io.ByteArrayResource;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.DefaultResourceLoader;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
|
||||
import org.springframework.lang.NonNull;
|
||||
|
@ -148,10 +150,10 @@ public class SqlScriptsTestExecutionListener extends AbstractTestExecutionListen
|
|||
@Override
|
||||
public void processAheadOfTime(Class<?> testClass, RuntimeHints runtimeHints, ClassLoader classLoader) {
|
||||
getSqlAnnotationsFor(testClass).forEach(sql ->
|
||||
registerClasspathResources(runtimeHints, getScripts(sql, testClass, null, true)));
|
||||
registerClasspathResources(getScripts(sql, testClass, null, true), runtimeHints, classLoader));
|
||||
getSqlMethods(testClass).forEach(testMethod ->
|
||||
getSqlAnnotationsFor(testMethod).forEach(sql ->
|
||||
registerClasspathResources(runtimeHints, getScripts(sql, testClass, testMethod, false))));
|
||||
registerClasspathResources(getScripts(sql, testClass, testMethod, false), runtimeHints, classLoader)));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -390,19 +392,12 @@ public class SqlScriptsTestExecutionListener extends AbstractTestExecutionListen
|
|||
return Arrays.stream(ReflectionUtils.getUniqueDeclaredMethods(testClass, sqlMethodFilter));
|
||||
}
|
||||
|
||||
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 String cleanClasspathResource(String location) {
|
||||
location = location.substring(CLASSPATH_URL_PREFIX.length());
|
||||
if (location.startsWith(SLASH)) {
|
||||
location = location.substring(1);
|
||||
}
|
||||
return location;
|
||||
private void registerClasspathResources(String[] paths, RuntimeHints runtimeHints, ClassLoader classLoader) {
|
||||
DefaultResourceLoader resourceLoader = new DefaultResourceLoader(classLoader);
|
||||
Arrays.stream(paths)
|
||||
.filter(path -> path.startsWith(CLASSPATH_URL_PREFIX))
|
||||
.map(resourceLoader::getResource)
|
||||
.forEach(resource -> RuntimeHintsUtils.registerResourceIfNecessary(runtimeHints, resource));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue