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:
Stephane Nicoll
2023-04-26 14:13:19 +02:00
parent f6875b11ff
commit 02132bd060
2 changed files with 44 additions and 7 deletions

View File

@@ -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) {