Merge branch '6.0.x'

This commit is contained in:
Stephane Nicoll 2023-04-26 14:39:58 +02:00
commit 834e694e94
2 changed files with 74 additions and 3 deletions

View File

@ -28,6 +28,7 @@ import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.function.Function;
import java.util.function.Predicate; import java.util.function.Predicate;
import java.util.function.Supplier; import java.util.function.Supplier;
@ -40,6 +41,7 @@ import org.springframework.aop.framework.autoproxy.AutoProxyUtils;
import org.springframework.aot.generate.GeneratedMethod; import org.springframework.aot.generate.GeneratedMethod;
import org.springframework.aot.generate.GenerationContext; import org.springframework.aot.generate.GenerationContext;
import org.springframework.aot.hint.ExecutableMode; import org.springframework.aot.hint.ExecutableMode;
import org.springframework.aot.hint.MemberCategory;
import org.springframework.aot.hint.ResourceHints; import org.springframework.aot.hint.ResourceHints;
import org.springframework.aot.hint.RuntimeHints; import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.TypeReference; import org.springframework.aot.hint.TypeReference;
@ -82,7 +84,9 @@ import org.springframework.core.PriorityOrdered;
import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment; import org.springframework.core.env.Environment;
import org.springframework.core.env.StandardEnvironment; import org.springframework.core.env.StandardEnvironment;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.DefaultResourceLoader; import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader; import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.PropertySourceDescriptor; import org.springframework.core.io.support.PropertySourceDescriptor;
import org.springframework.core.io.support.PropertySourceProcessor; import org.springframework.core.io.support.PropertySourceProcessor;
@ -326,7 +330,8 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
if (hasPropertySourceDescriptors || hasImportRegistry) { if (hasPropertySourceDescriptors || hasImportRegistry) {
return (generationContext, code) -> { return (generationContext, code) -> {
if (hasPropertySourceDescriptors) { if (hasPropertySourceDescriptors) {
new PropertySourcesAotContribution(this.propertySourceDescriptors).applyTo(generationContext, code); new PropertySourcesAotContribution(this.propertySourceDescriptors, this::resolvePropertySourceLocation)
.applyTo(generationContext, code);
} }
if (hasImportRegistry) { if (hasImportRegistry) {
new ImportAwareAotContribution(beanFactory).applyTo(generationContext, code); new ImportAwareAotContribution(beanFactory).applyTo(generationContext, code);
@ -336,6 +341,18 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
return null; 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 * Build and validate a configuration model based on the registry of
* {@link Configuration} classes. * {@link Configuration} classes.
@ -644,12 +661,16 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
private final List<PropertySourceDescriptor> descriptors; 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.descriptors = descriptors;
this.resourceResolver = resourceResolver;
} }
@Override @Override
public void applyTo(GenerationContext generationContext, BeanFactoryInitializationCode beanFactoryInitializationCode) { public void applyTo(GenerationContext generationContext, BeanFactoryInitializationCode beanFactoryInitializationCode) {
registerRuntimeHints(generationContext.getRuntimeHints());
GeneratedMethod generatedMethod = beanFactoryInitializationCode GeneratedMethod generatedMethod = beanFactoryInitializationCode
.getMethods() .getMethods()
.add("processPropertySources", this::generateAddPropertySourceProcessorMethod); .add("processPropertySources", this::generateAddPropertySourceProcessorMethod);
@ -657,6 +678,21 @@ public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPo
.addInitializer(generatedMethod.toMethodReference()); .addInitializer(generatedMethod.toMethodReference());
} }
private void registerRuntimeHints(RuntimeHints hints) {
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) { private void generateAddPropertySourceProcessorMethod(MethodSpec.Builder method) {
method.addJavadoc("Apply known @PropertySources to the environment."); method.addJavadoc("Apply known @PropertySources to the environment.");
method.addModifiers(Modifier.PRIVATE); method.addModifiers(Modifier.PRIVATE);

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2022 the original author or authors. * Copyright 2002-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -20,6 +20,7 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Predicate;
import javax.lang.model.element.Modifier; import javax.lang.model.element.Modifier;
@ -29,7 +30,10 @@ import org.junit.jupiter.api.Test;
import org.springframework.aot.generate.MethodReference; import org.springframework.aot.generate.MethodReference;
import org.springframework.aot.generate.MethodReference.ArgumentCodeGenerator; import org.springframework.aot.generate.MethodReference.ArgumentCodeGenerator;
import org.springframework.aot.hint.MemberCategory;
import org.springframework.aot.hint.ResourcePatternHint; 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.aot.test.generate.TestGenerationContext;
import org.springframework.beans.BeansException; import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.InitializingBean;
@ -50,6 +54,7 @@ import org.springframework.context.testfixture.context.generator.SimpleComponent
import org.springframework.core.Ordered; import org.springframework.core.Ordered;
import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.io.ResourceLoader; import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.DefaultPropertySourceFactory;
import org.springframework.core.test.tools.Compiled; import org.springframework.core.test.tools.Compiled;
import org.springframework.core.test.tools.TestCompiler; import org.springframework.core.test.tools.TestCompiler;
import org.springframework.core.type.AnnotationMetadata; import org.springframework.core.type.AnnotationMetadata;
@ -246,6 +251,8 @@ class ConfigurationClassPostProcessorAotContributionTests {
BeanFactoryInitializationAotContribution contribution = getContribution( BeanFactoryInitializationAotContribution contribution = getContribution(
PropertySourceConfiguration.class); PropertySourceConfiguration.class);
contribution.applyTo(generationContext, beanFactoryInitializationCode); contribution.applyTo(generationContext, beanFactoryInitializationCode);
assertThat(resource("org/springframework/context/annotation/p1.properties"))
.accepts(generationContext.getRuntimeHints());
compile((initializer, compiled) -> { compile((initializer, compiled) -> {
GenericApplicationContext freshContext = new GenericApplicationContext(); GenericApplicationContext freshContext = new GenericApplicationContext();
ConfigurableEnvironment environment = freshContext.getEnvironment(); ConfigurableEnvironment environment = freshContext.getEnvironment();
@ -262,6 +269,9 @@ class ConfigurationClassPostProcessorAotContributionTests {
BeanFactoryInitializationAotContribution contribution = getContribution( BeanFactoryInitializationAotContribution contribution = getContribution(
PropertySourceConfiguration.class, PropertySourceDependentConfiguration.class); PropertySourceConfiguration.class, PropertySourceDependentConfiguration.class);
contribution.applyTo(generationContext, beanFactoryInitializationCode); 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) -> { compile((initializer, compiled) -> {
GenericApplicationContext freshContext = new GenericApplicationContext(); GenericApplicationContext freshContext = new GenericApplicationContext();
ConfigurableEnvironment environment = freshContext.getEnvironment(); ConfigurableEnvironment environment = freshContext.getEnvironment();
@ -291,6 +301,20 @@ class ConfigurationClassPostProcessorAotContributionTests {
}); });
} }
@Test
void applyToWhenHasCustomFactoryRegistersHints() {
BeanFactoryInitializationAotContribution contribution = getContribution(
PropertySourceWithCustomFactoryConfiguration.class);
contribution.applyTo(generationContext, beanFactoryInitializationCode);
assertThat(RuntimeHintsPredicates.reflection().onType(CustomPropertySourcesFactory.class)
.withMemberCategories(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS))
.accepts(generationContext.getRuntimeHints());
}
private Predicate<RuntimeHints> resource(String location) {
return RuntimeHintsPredicates.resource().forResource(location);
}
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private void compile(BiConsumer<Consumer<GenericApplicationContext>, Compiled> result) { private void compile(BiConsumer<Consumer<GenericApplicationContext>, Compiled> result) {
MethodReference methodReference = beanFactoryInitializationCode.getInitializers().get(0); MethodReference methodReference = beanFactoryInitializationCode.getInitializers().get(0);
@ -332,6 +356,13 @@ class ConfigurationClassPostProcessorAotContributionTests {
} }
@Configuration(proxyBeanMethods = false)
@PropertySource(value = "classpath:org/springframework/context/annotation/p1.properties",
factory = CustomPropertySourcesFactory.class)
static class PropertySourceWithCustomFactoryConfiguration {
}
} }
@Nested @Nested
@ -379,4 +410,8 @@ class ConfigurationClassPostProcessorAotContributionTests {
.containsExactly(entry(key.getName(), value.getName())); .containsExactly(entry(key.getName(), value.getName()));
} }
static class CustomPropertySourcesFactory extends DefaultPropertySourceFactory {
}
} }