diff --git a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java index 65305db42c..f68c34ef0c 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java @@ -27,8 +27,8 @@ import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.Set; +import java.util.function.Function; import java.util.function.Predicate; import java.util.function.Supplier; @@ -84,7 +84,9 @@ import org.springframework.core.PriorityOrdered; import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.Environment; import org.springframework.core.env.StandardEnvironment; +import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.DefaultResourceLoader; +import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; import org.springframework.core.io.support.PropertySourceDescriptor; import org.springframework.core.io.support.PropertySourceProcessor; @@ -328,7 +330,8 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo if (hasPropertySourceDescriptors || hasImportRegistry) { return (generationContext, code) -> { if (hasPropertySourceDescriptors) { - new PropertySourcesAotContribution(this.propertySourceDescriptors).applyTo(generationContext, code); + new PropertySourcesAotContribution(this.propertySourceDescriptors, this::resolvePropertySourceLocation) + .applyTo(generationContext, code); } if (hasImportRegistry) { new ImportAwareAotContribution(beanFactory).applyTo(generationContext, code); @@ -338,6 +341,18 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo return null; } + @Nullable + private Resource resolvePropertySourceLocation(String location) { + try { + String resolvedLocation = (this.environment != null + ? this.environment.resolveRequiredPlaceholders(location) : location); + return this.resourceLoader.getResource(resolvedLocation); + } + catch (Exception ex) { + return null; + } + } + /** * Build and validate a configuration model based on the registry of * {@link Configuration} classes. @@ -646,8 +661,11 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo private final List descriptors; - PropertySourcesAotContribution(List descriptors) { + private final Function resourceResolver; + + PropertySourcesAotContribution(List descriptors, Function resourceResolver) { this.descriptors = descriptors; + this.resourceResolver = resourceResolver; } @Override @@ -661,10 +679,18 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo } private void registerRuntimeHints(RuntimeHints hints) { - this.descriptors.stream().map(PropertySourceDescriptor::propertySourceFactory) - .filter(Objects::nonNull).distinct() - .forEach(factory -> hints.reflection() - .registerType(factory, MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)); + for (PropertySourceDescriptor descriptor : this.descriptors) { + Class factory = descriptor.propertySourceFactory(); + if (factory != null) { + hints.reflection().registerType(factory, MemberCategory.INVOKE_DECLARED_CONSTRUCTORS); + } + for (String location : descriptor.locations()) { + Resource resource = this.resourceResolver.apply(location); + if (resource != null && resource.exists() && resource instanceof ClassPathResource classpathResource) { + hints.resources().registerPattern(classpathResource.getPath()); + } + } + } } private void generateAddPropertySourceProcessorMethod(MethodSpec.Builder method) { diff --git a/spring-context/src/test/java/org/springframework/context/annotation/ConfigurationClassPostProcessorAotContributionTests.java b/spring-context/src/test/java/org/springframework/context/annotation/ConfigurationClassPostProcessorAotContributionTests.java index efd9a97cb4..13cb21a2f3 100644 --- a/spring-context/src/test/java/org/springframework/context/annotation/ConfigurationClassPostProcessorAotContributionTests.java +++ b/spring-context/src/test/java/org/springframework/context/annotation/ConfigurationClassPostProcessorAotContributionTests.java @@ -20,6 +20,7 @@ import java.util.ArrayList; import java.util.List; import java.util.function.BiConsumer; import java.util.function.Consumer; +import java.util.function.Predicate; import javax.lang.model.element.Modifier; @@ -31,6 +32,7 @@ import org.springframework.aot.generate.MethodReference; import org.springframework.aot.generate.MethodReference.ArgumentCodeGenerator; import org.springframework.aot.hint.MemberCategory; import org.springframework.aot.hint.ResourcePatternHint; +import org.springframework.aot.hint.RuntimeHints; import org.springframework.aot.hint.predicate.RuntimeHintsPredicates; import org.springframework.aot.test.generate.TestGenerationContext; import org.springframework.beans.BeansException; @@ -249,6 +251,8 @@ class ConfigurationClassPostProcessorAotContributionTests { BeanFactoryInitializationAotContribution contribution = getContribution( PropertySourceConfiguration.class); contribution.applyTo(generationContext, beanFactoryInitializationCode); + assertThat(resource("org/springframework/context/annotation/p1.properties")) + .accepts(generationContext.getRuntimeHints()); compile((initializer, compiled) -> { GenericApplicationContext freshContext = new GenericApplicationContext(); ConfigurableEnvironment environment = freshContext.getEnvironment(); @@ -265,6 +269,9 @@ class ConfigurationClassPostProcessorAotContributionTests { BeanFactoryInitializationAotContribution contribution = getContribution( PropertySourceConfiguration.class, PropertySourceDependentConfiguration.class); contribution.applyTo(generationContext, beanFactoryInitializationCode); + assertThat(resource("org/springframework/context/annotation/p1.properties") + .and(resource("org/springframework/context/annotation/p2.properties"))) + .accepts(generationContext.getRuntimeHints()); compile((initializer, compiled) -> { GenericApplicationContext freshContext = new GenericApplicationContext(); ConfigurableEnvironment environment = freshContext.getEnvironment(); @@ -304,6 +311,10 @@ class ConfigurationClassPostProcessorAotContributionTests { .accepts(generationContext.getRuntimeHints()); } + private Predicate resource(String location) { + return RuntimeHintsPredicates.resource().forResource(location); + } + @SuppressWarnings("unchecked") private void compile(BiConsumer, Compiled> result) { MethodReference methodReference = beanFactoryInitializationCode.getInitializers().get(0);