Browse Source

Register bean reflection hint for property fields

Prior to this commit, the bean definition properties code generator
would register hints for invoking the setter methods of registered
property values defined for the bean definition.
The internal algorithm is also reflecting on the Field to discover
annotations. Doing so actually calls `getDeclaredFields` to iterate on
the available fields. This is done recursively up the type hierarchy
until the field is found.

This commit registers the required reflection metadata.

Closes gh-31390
pull/31396/head
Brian Clozel 1 year ago
parent
commit
8064659136
  1. 8
      spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanDefinitionPropertiesCodeGenerator.java
  2. 27
      spring-beans/src/test/java/org/springframework/beans/factory/aot/BeanDefinitionPropertiesCodeGeneratorTests.java

8
spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanDefinitionPropertiesCodeGenerator.java

@ -34,6 +34,7 @@ import java.util.function.Predicate; @@ -34,6 +34,7 @@ import java.util.function.Predicate;
import org.springframework.aot.generate.GeneratedMethods;
import org.springframework.aot.hint.ExecutableMode;
import org.springframework.aot.hint.MemberCategory;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.TypeReference;
import org.springframework.beans.BeanUtils;
@ -195,6 +196,13 @@ class BeanDefinitionPropertiesCodeGenerator { @@ -195,6 +196,13 @@ class BeanDefinitionPropertiesCodeGenerator {
Method writeMethod = writeMethods.get(propertyValue.getName());
if (writeMethod != null) {
this.hints.reflection().registerMethod(writeMethod, ExecutableMode.INVOKE);
// ReflectionUtils#findField searches recursively in the type hierarchy
Class<?> searchType = beanDefinition.getTargetType();
while (searchType != null && searchType != writeMethod.getDeclaringClass()) {
this.hints.reflection().registerType(searchType, MemberCategory.DECLARED_FIELDS);
searchType = searchType.getSuperclass();
}
this.hints.reflection().registerType(writeMethod.getDeclaringClass(), MemberCategory.DECLARED_FIELDS);
}
}
}

27
spring-beans/src/test/java/org/springframework/beans/factory/aot/BeanDefinitionPropertiesCodeGeneratorTests.java

@ -34,6 +34,7 @@ import org.junit.jupiter.api.Test; @@ -34,6 +34,7 @@ import org.junit.jupiter.api.Test;
import org.reactivestreams.Publisher;
import org.springframework.aot.generate.GeneratedClass;
import org.springframework.aot.hint.MemberCategory;
import org.springframework.aot.hint.predicate.RuntimeHintsPredicates;
import org.springframework.aot.test.generate.TestGenerationContext;
import org.springframework.beans.factory.FactoryBean;
@ -240,6 +241,21 @@ class BeanDefinitionPropertiesCodeGeneratorTests { @@ -240,6 +241,21 @@ class BeanDefinitionPropertiesCodeGeneratorTests {
assertThat(actual.getPropertyValues().get("spring")).isEqualTo("framework");
});
assertHasMethodInvokeHints(PropertyValuesBean.class, "setTest", "setSpring");
assertHasDecalredFieldsHint(PropertyValuesBean.class);
}
@Test
void propertyValuesWhenValuesOnParentClass() {
this.beanDefinition.setTargetType(ExtendedPropertyValuesBean.class);
this.beanDefinition.getPropertyValues().add("test", String.class);
this.beanDefinition.getPropertyValues().add("spring", "framework");
compile((actual, compiled) -> {
assertThat(actual.getPropertyValues().get("test")).isEqualTo(String.class);
assertThat(actual.getPropertyValues().get("spring")).isEqualTo("framework");
});
assertHasMethodInvokeHints(PropertyValuesBean.class, "setTest", "setSpring");
assertHasDecalredFieldsHint(ExtendedPropertyValuesBean.class);
assertHasDecalredFieldsHint(PropertyValuesBean.class);
}
@Test
@ -300,6 +316,7 @@ class BeanDefinitionPropertiesCodeGeneratorTests { @@ -300,6 +316,7 @@ class BeanDefinitionPropertiesCodeGeneratorTests {
assertThat(actual.getPropertyValues().get("name")).isEqualTo("World");
});
assertHasMethodInvokeHints(PropertyValuesFactoryBean.class, "setPrefix", "setName" );
assertHasDecalredFieldsHint(PropertyValuesFactoryBean.class);
}
@Test
@ -453,6 +470,12 @@ class BeanDefinitionPropertiesCodeGeneratorTests { @@ -453,6 +470,12 @@ class BeanDefinitionPropertiesCodeGeneratorTests {
.test(this.generationContext.getRuntimeHints()));
}
private void assertHasDecalredFieldsHint(Class<?> beanType) {
assertThat(RuntimeHintsPredicates.reflection()
.onType(beanType).withMemberCategory(MemberCategory.DECLARED_FIELDS))
.accepts(this.generationContext.getRuntimeHints());
}
private void compile(BiConsumer<RootBeanDefinition, Compiled> result) {
compile(attribute -> true, result);
}
@ -524,6 +547,10 @@ class BeanDefinitionPropertiesCodeGeneratorTests { @@ -524,6 +547,10 @@ class BeanDefinitionPropertiesCodeGeneratorTests {
}
static class ExtendedPropertyValuesBean extends PropertyValuesBean {
}
static class PropertyValuesFactoryBean implements FactoryBean<String> {
private String prefix;

Loading…
Cancel
Save