Infer resource hints for PropertySource#value
This commit adds a resource hints for the target(s) of a @PropertySource declaration. Closes gh-30376
This commit is contained in:
@@ -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<PropertySourceDescriptor> descriptors;
|
||||
|
||||
PropertySourcesAotContribution(List<PropertySourceDescriptor> descriptors) {
|
||||
private final Function<String, Resource> resourceResolver;
|
||||
|
||||
PropertySourcesAotContribution(List<PropertySourceDescriptor> descriptors, Function<String, Resource> 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) {
|
||||
|
||||
@@ -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<RuntimeHints> resource(String location) {
|
||||
return RuntimeHintsPredicates.resource().forResource(location);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void compile(BiConsumer<Consumer<GenericApplicationContext>, Compiled> result) {
|
||||
MethodReference methodReference = beanFactoryInitializationCode.getInitializers().get(0);
|
||||
|
||||
Reference in New Issue
Block a user