Add custom code generation for bean definition property values
This commits allows ValueCodeGenerator$Delegate implementations to be loaded from `META-INF/spring/aot.factories` and considered for code generation of bean definition property values. This default behavior in DefaultBeanRegistrationCodeFragments can be customized as usual. Closes gh-31427
This commit is contained in:
@@ -45,6 +45,8 @@ import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.testfixture.beans.AnnotatedBean;
|
||||
import org.springframework.beans.testfixture.beans.GenericBean;
|
||||
import org.springframework.beans.testfixture.beans.TestBean;
|
||||
import org.springframework.beans.testfixture.beans.factory.aot.CustomBean;
|
||||
import org.springframework.beans.testfixture.beans.factory.aot.CustomPropertyValue;
|
||||
import org.springframework.beans.testfixture.beans.factory.aot.InnerBeanConfiguration;
|
||||
import org.springframework.beans.testfixture.beans.factory.aot.MockBeanRegistrationsCode;
|
||||
import org.springframework.beans.testfixture.beans.factory.aot.SimpleBean;
|
||||
@@ -605,6 +607,23 @@ class BeanDefinitionMethodGeneratorTests {
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void generateBeanDefinitionMethodWhenCustomPropertyValueUsesCustomDelegate() {
|
||||
RootBeanDefinition beanDefinition = new RootBeanDefinition(CustomBean.class);
|
||||
beanDefinition.getPropertyValues().addPropertyValue(
|
||||
"customPropertyValue", new CustomPropertyValue("test"));
|
||||
RegisteredBean bean = registerBean(beanDefinition);
|
||||
BeanDefinitionMethodGenerator generator = new BeanDefinitionMethodGenerator(
|
||||
this.methodGeneratorFactory, bean, "test",
|
||||
Collections.emptyList());
|
||||
MethodReference method = generator.generateBeanDefinitionMethod(
|
||||
this.generationContext, this.beanRegistrationsCode);
|
||||
compile(method, (actual, compiled) ->
|
||||
assertThat(actual.getPropertyValues().get("customPropertyValue"))
|
||||
.isInstanceOfSatisfying(CustomPropertyValue.class, customPropertyValue
|
||||
-> assertThat(customPropertyValue.value()).isEqualTo("test")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void generateBeanDefinitionMethodWhenHasAotContributionsAppliesContributions() {
|
||||
RegisteredBean registeredBean = registerBean(
|
||||
|
||||
@@ -18,6 +18,7 @@ package org.springframework.beans.factory.aot;
|
||||
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@@ -33,6 +34,7 @@ import org.junit.jupiter.api.Test;
|
||||
import org.reactivestreams.Publisher;
|
||||
|
||||
import org.springframework.aot.generate.GeneratedClass;
|
||||
import org.springframework.aot.generate.ValueCodeGenerator.Delegate;
|
||||
import org.springframework.aot.hint.MemberCategory;
|
||||
import org.springframework.aot.hint.predicate.RuntimeHintsPredicates;
|
||||
import org.springframework.aot.test.generate.TestGenerationContext;
|
||||
@@ -49,6 +51,7 @@ import org.springframework.beans.factory.support.ManagedList;
|
||||
import org.springframework.beans.factory.support.ManagedMap;
|
||||
import org.springframework.beans.factory.support.ManagedSet;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.testfixture.beans.factory.aot.CustomPropertyValue;
|
||||
import org.springframework.beans.testfixture.beans.factory.aot.DeferredTypeBuilder;
|
||||
import org.springframework.core.test.tools.Compiled;
|
||||
import org.springframework.core.test.tools.TestCompiler;
|
||||
@@ -364,6 +367,21 @@ class BeanDefinitionPropertiesCodeGeneratorTests {
|
||||
assertHasDeclaredFieldsHint(PropertyValuesFactoryBean.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void propertyValuesWhenCustomValuesUsingDelegate() {
|
||||
this.beanDefinition.setTargetType(PropertyValuesBean.class);
|
||||
this.beanDefinition.getPropertyValues().add("test", new CustomPropertyValue("test"));
|
||||
this.beanDefinition.getPropertyValues().add("spring", new CustomPropertyValue("framework"));
|
||||
compile(value -> true, List.of(new CustomPropertyValue.ValueCodeGeneratorDelegate()), (actual, compiled) -> {
|
||||
assertThat(actual.getPropertyValues().get("test")).isInstanceOfSatisfying(CustomPropertyValue.class,
|
||||
customPropertyValue -> assertThat(customPropertyValue.value()).isEqualTo("test"));
|
||||
assertThat(actual.getPropertyValues().get("spring")).isInstanceOfSatisfying(CustomPropertyValue.class,
|
||||
customPropertyValue -> assertThat(customPropertyValue.value()).isEqualTo("framework"));
|
||||
});
|
||||
assertHasMethodInvokeHints(PropertyValuesBean.class, "setTest", "setSpring");
|
||||
assertHasDeclaredFieldsHint(PropertyValuesBean.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void attributesWhenAllFiltered() {
|
||||
this.beanDefinition.setAttribute("a", "A");
|
||||
@@ -548,12 +566,18 @@ class BeanDefinitionPropertiesCodeGeneratorTests {
|
||||
compile(attribute -> true, result);
|
||||
}
|
||||
|
||||
private void compile(Predicate<String> attributeFilter, BiConsumer<RootBeanDefinition, Compiled> result) {
|
||||
private void compile(Predicate<String> attributeFilter,
|
||||
BiConsumer<RootBeanDefinition, Compiled> result) {
|
||||
compile(attributeFilter, Collections.emptyList(), result);
|
||||
}
|
||||
|
||||
private void compile(Predicate<String> attributeFilter, List<Delegate> additionalDelegates,
|
||||
BiConsumer<RootBeanDefinition, Compiled> result) {
|
||||
DeferredTypeBuilder typeBuilder = new DeferredTypeBuilder();
|
||||
GeneratedClass generatedClass = this.generationContext.getGeneratedClasses().addForFeature("TestCode", typeBuilder);
|
||||
BeanDefinitionPropertiesCodeGenerator codeGenerator = new BeanDefinitionPropertiesCodeGenerator(
|
||||
this.generationContext.getRuntimeHints(), attributeFilter,
|
||||
generatedClass.getMethods(), (name, value) -> null);
|
||||
generatedClass.getMethods(), additionalDelegates, (name, value) -> null);
|
||||
CodeBlock generatedCode = codeGenerator.generateCode(this.beanDefinition);
|
||||
typeBuilder.set(type -> {
|
||||
type.addModifiers(Modifier.PUBLIC);
|
||||
|
||||
Reference in New Issue
Block a user