Add AOT processing of bean aliases

This commit adds AOT processing of bean aliases.

Closes gh-29391
This commit is contained in:
Sébastien Deleuze
2022-11-02 08:27:30 +01:00
parent bfe37c290e
commit 403cfefc28
4 changed files with 85 additions and 15 deletions

View File

@@ -42,9 +42,12 @@ import org.springframework.core.test.io.support.MockSpringFactoriesLoader;
import org.springframework.core.test.tools.Compiled;
import org.springframework.core.test.tools.SourceFile;
import org.springframework.core.test.tools.TestCompiler;
import org.springframework.javapoet.ClassName;
import org.springframework.javapoet.CodeBlock;
import org.springframework.javapoet.MethodSpec;
import org.springframework.javapoet.ParameterizedTypeName;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import static org.assertj.core.api.Assertions.assertThat;
@@ -52,6 +55,7 @@ import static org.assertj.core.api.Assertions.assertThat;
* Tests for {@link BeanRegistrationsAotContribution}.
*
* @author Phillip Webb
* @author Sebastien Deleuze
*/
class BeanRegistrationsAotContributionTests {
@@ -84,7 +88,7 @@ class BeanRegistrationsAotContributionTests {
Collections.emptyList());
registrations.put("testBean", generator);
BeanRegistrationsAotContribution contribution = new BeanRegistrationsAotContribution(
registrations);
registrations, new LinkedMultiValueMap<>());
contribution.applyTo(this.generationContext, this.beanFactoryInitializationCode);
compile((consumer, compiled) -> {
DefaultListableBeanFactory freshBeanFactory = new DefaultListableBeanFactory();
@@ -93,6 +97,27 @@ class BeanRegistrationsAotContributionTests {
});
}
@Test
void applyToAppliesContributionWithAliases() {
Map<String, BeanDefinitionMethodGenerator> registrations = new LinkedHashMap<>();
RegisteredBean registeredBean = registerBean(
new RootBeanDefinition(TestBean.class));
BeanDefinitionMethodGenerator generator = new BeanDefinitionMethodGenerator(
this.methodGeneratorFactory, registeredBean, null,
Collections.emptyList());
registrations.put("testBean", generator);
MultiValueMap<String, String> aliases = new LinkedMultiValueMap<>();
aliases.add("testBean", "testAlias");
BeanRegistrationsAotContribution contribution = new BeanRegistrationsAotContribution(
registrations, aliases);
contribution.applyTo(this.generationContext, this.beanFactoryInitializationCode);
compile((consumer, compiled) -> {
DefaultListableBeanFactory freshBeanFactory = new DefaultListableBeanFactory();
consumer.accept(freshBeanFactory);
assertThat(freshBeanFactory.getAliases("testBean")).containsExactly("testAlias");
});
}
@Test
void applyToWhenHasNameGeneratesPrefixedFeatureName() {
this.generationContext = new TestGenerationContext(
@@ -106,7 +131,7 @@ class BeanRegistrationsAotContributionTests {
Collections.emptyList());
registrations.put("testBean", generator);
BeanRegistrationsAotContribution contribution = new BeanRegistrationsAotContribution(
registrations);
registrations, new LinkedMultiValueMap<>());
contribution.applyTo(this.generationContext, this.beanFactoryInitializationCode);
compile((consumer, compiled) -> {
SourceFile sourceFile = compiled.getSourceFile(".*BeanDefinitions");
@@ -136,7 +161,7 @@ class BeanRegistrationsAotContributionTests {
};
registrations.put("testBean", generator);
BeanRegistrationsAotContribution contribution = new BeanRegistrationsAotContribution(
registrations);
registrations, new LinkedMultiValueMap<>());
contribution.applyTo(this.generationContext, this.beanFactoryInitializationCode);
assertThat(beanRegistrationsCodes).hasSize(1);
BeanRegistrationsCode actual = beanRegistrationsCodes.get(0);
@@ -152,17 +177,21 @@ class BeanRegistrationsAotContributionTests {
@SuppressWarnings({ "unchecked", "cast" })
private void compile(
BiConsumer<Consumer<DefaultListableBeanFactory>, Compiled> result) {
MethodReference methodReference = this.beanFactoryInitializationCode
MethodReference beanRegistrationsMethodReference = this.beanFactoryInitializationCode
.getInitializers().get(0);
MethodReference aliasesMethodReference = this.beanFactoryInitializationCode
.getInitializers().get(1);
this.beanFactoryInitializationCode.getTypeBuilder().set(type -> {
CodeBlock methodInvocation = methodReference.toInvokeCodeBlock(
ArgumentCodeGenerator.of(DefaultListableBeanFactory.class, "beanFactory"),
this.beanFactoryInitializationCode.getClassName());
ArgumentCodeGenerator beanFactory = ArgumentCodeGenerator.of(DefaultListableBeanFactory.class, "beanFactory");
ClassName className = this.beanFactoryInitializationCode.getClassName();
CodeBlock beanRegistrationsMethodInvocation = beanRegistrationsMethodReference.toInvokeCodeBlock(beanFactory, className);
CodeBlock aliasesMethodInvocation = aliasesMethodReference.toInvokeCodeBlock(beanFactory, className);
type.addModifiers(Modifier.PUBLIC);
type.addSuperinterface(ParameterizedTypeName.get(Consumer.class, DefaultListableBeanFactory.class));
type.addMethod(MethodSpec.methodBuilder("accept").addModifiers(Modifier.PUBLIC)
.addParameter(DefaultListableBeanFactory.class, "beanFactory")
.addStatement(methodInvocation)
.addStatement(beanRegistrationsMethodInvocation)
.addStatement(aliasesMethodInvocation)
.build());
});
this.generationContext.writeGeneratedContent();

View File

@@ -30,6 +30,7 @@ import static org.assertj.core.api.Assertions.assertThat;
* Tests for {@link BeanRegistrationsAotProcessor}.
*
* @author Phillip Webb
* @author Sebastien Deleuze
*/
class BeanRegistrationsAotProcessorTests {
@@ -53,4 +54,17 @@ class BeanRegistrationsAotProcessorTests {
.asInstanceOf(InstanceOfAssertFactories.MAP).containsKeys("b1", "b2");
}
@Test
void processAheadOfTimeReturnsBeanRegistrationsAotContributionWithAliases() {
BeanRegistrationsAotProcessor processor = new BeanRegistrationsAotProcessor();
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
beanFactory.registerBeanDefinition("test", new RootBeanDefinition(TestBean.class));
beanFactory.registerAlias("test", "testAlias");
BeanRegistrationsAotContribution contribution = processor
.processAheadOfTime(beanFactory);
assertThat(contribution).extracting("aliases")
.asInstanceOf(InstanceOfAssertFactories.MAP).hasEntrySatisfying("test", value ->
assertThat(value).asList().singleElement().isEqualTo("testAlias"));
}
}