Skip to content

Commit 02132bd

Browse files
committed
Infer resource hints for PropertySource#value
This commit adds a resource hints for the target(s) of a @propertysource declaration. Closes gh-30376
1 parent f6875b1 commit 02132bd

File tree

2 files changed

+44
-7
lines changed

2 files changed

+44
-7
lines changed

spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassPostProcessor.java

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@
2727
import java.util.LinkedHashSet;
2828
import java.util.List;
2929
import java.util.Map;
30-
import java.util.Objects;
3130
import java.util.Set;
31+
import java.util.function.Function;
3232
import java.util.function.Predicate;
3333
import java.util.function.Supplier;
3434

@@ -84,7 +84,9 @@
8484
import org.springframework.core.env.ConfigurableEnvironment;
8585
import org.springframework.core.env.Environment;
8686
import org.springframework.core.env.StandardEnvironment;
87+
import org.springframework.core.io.ClassPathResource;
8788
import org.springframework.core.io.DefaultResourceLoader;
89+
import org.springframework.core.io.Resource;
8890
import org.springframework.core.io.ResourceLoader;
8991
import org.springframework.core.io.support.PropertySourceDescriptor;
9092
import org.springframework.core.io.support.PropertySourceProcessor;
@@ -328,7 +330,8 @@ public BeanFactoryInitializationAotContribution processAheadOfTime(ConfigurableL
328330
if (hasPropertySourceDescriptors || hasImportRegistry) {
329331
return (generationContext, code) -> {
330332
if (hasPropertySourceDescriptors) {
331-
new PropertySourcesAotContribution(this.propertySourceDescriptors).applyTo(generationContext, code);
333+
new PropertySourcesAotContribution(this.propertySourceDescriptors, this::resolvePropertySourceLocation)
334+
.applyTo(generationContext, code);
332335
}
333336
if (hasImportRegistry) {
334337
new ImportAwareAotContribution(beanFactory).applyTo(generationContext, code);
@@ -338,6 +341,18 @@ public BeanFactoryInitializationAotContribution processAheadOfTime(ConfigurableL
338341
return null;
339342
}
340343

344+
@Nullable
345+
private Resource resolvePropertySourceLocation(String location) {
346+
try {
347+
String resolvedLocation = (this.environment != null
348+
? this.environment.resolveRequiredPlaceholders(location) : location);
349+
return this.resourceLoader.getResource(resolvedLocation);
350+
}
351+
catch (Exception ex) {
352+
return null;
353+
}
354+
}
355+
341356
/**
342357
* Build and validate a configuration model based on the registry of
343358
* {@link Configuration} classes.
@@ -646,8 +661,11 @@ private static class PropertySourcesAotContribution implements BeanFactoryInitia
646661

647662
private final List<PropertySourceDescriptor> descriptors;
648663

649-
PropertySourcesAotContribution(List<PropertySourceDescriptor> descriptors) {
664+
private final Function<String, Resource> resourceResolver;
665+
666+
PropertySourcesAotContribution(List<PropertySourceDescriptor> descriptors, Function<String, Resource> resourceResolver) {
650667
this.descriptors = descriptors;
668+
this.resourceResolver = resourceResolver;
651669
}
652670

653671
@Override
@@ -661,10 +679,18 @@ public void applyTo(GenerationContext generationContext, BeanFactoryInitializati
661679
}
662680

663681
private void registerRuntimeHints(RuntimeHints hints) {
664-
this.descriptors.stream().map(PropertySourceDescriptor::propertySourceFactory)
665-
.filter(Objects::nonNull).distinct()
666-
.forEach(factory -> hints.reflection()
667-
.registerType(factory, MemberCategory.INVOKE_DECLARED_CONSTRUCTORS));
682+
for (PropertySourceDescriptor descriptor : this.descriptors) {
683+
Class<?> factory = descriptor.propertySourceFactory();
684+
if (factory != null) {
685+
hints.reflection().registerType(factory, MemberCategory.INVOKE_DECLARED_CONSTRUCTORS);
686+
}
687+
for (String location : descriptor.locations()) {
688+
Resource resource = this.resourceResolver.apply(location);
689+
if (resource != null && resource.exists() && resource instanceof ClassPathResource classpathResource) {
690+
hints.resources().registerPattern(classpathResource.getPath());
691+
}
692+
}
693+
}
668694
}
669695

670696
private void generateAddPropertySourceProcessorMethod(MethodSpec.Builder method) {

spring-context/src/test/java/org/springframework/context/annotation/ConfigurationClassPostProcessorAotContributionTests.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import java.util.List;
2121
import java.util.function.BiConsumer;
2222
import java.util.function.Consumer;
23+
import java.util.function.Predicate;
2324

2425
import javax.lang.model.element.Modifier;
2526

@@ -31,6 +32,7 @@
3132
import org.springframework.aot.generate.MethodReference.ArgumentCodeGenerator;
3233
import org.springframework.aot.hint.MemberCategory;
3334
import org.springframework.aot.hint.ResourcePatternHint;
35+
import org.springframework.aot.hint.RuntimeHints;
3436
import org.springframework.aot.hint.predicate.RuntimeHintsPredicates;
3537
import org.springframework.aot.test.generate.TestGenerationContext;
3638
import org.springframework.beans.BeansException;
@@ -249,6 +251,8 @@ void applyToWhenHasPropertySourceInvokePropertySourceProcessor() {
249251
BeanFactoryInitializationAotContribution contribution = getContribution(
250252
PropertySourceConfiguration.class);
251253
contribution.applyTo(generationContext, beanFactoryInitializationCode);
254+
assertThat(resource("org/springframework/context/annotation/p1.properties"))
255+
.accepts(generationContext.getRuntimeHints());
252256
compile((initializer, compiled) -> {
253257
GenericApplicationContext freshContext = new GenericApplicationContext();
254258
ConfigurableEnvironment environment = freshContext.getEnvironment();
@@ -265,6 +269,9 @@ void applyToWhenHasPropertySourcesInvokesPropertySourceProcessorInOrder() {
265269
BeanFactoryInitializationAotContribution contribution = getContribution(
266270
PropertySourceConfiguration.class, PropertySourceDependentConfiguration.class);
267271
contribution.applyTo(generationContext, beanFactoryInitializationCode);
272+
assertThat(resource("org/springframework/context/annotation/p1.properties")
273+
.and(resource("org/springframework/context/annotation/p2.properties")))
274+
.accepts(generationContext.getRuntimeHints());
268275
compile((initializer, compiled) -> {
269276
GenericApplicationContext freshContext = new GenericApplicationContext();
270277
ConfigurableEnvironment environment = freshContext.getEnvironment();
@@ -304,6 +311,10 @@ void applyToWhenHasCustomFactoryRegistersHints() {
304311
.accepts(generationContext.getRuntimeHints());
305312
}
306313

314+
private Predicate<RuntimeHints> resource(String location) {
315+
return RuntimeHintsPredicates.resource().forResource(location);
316+
}
317+
307318
@SuppressWarnings("unchecked")
308319
private void compile(BiConsumer<Consumer<GenericApplicationContext>, Compiled> result) {
309320
MethodReference methodReference = beanFactoryInitializationCode.getInitializers().get(0);

0 commit comments

Comments
 (0)