Skip to content

Commit 8064659

Browse files
committed
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
1 parent 30a94b0 commit 8064659

File tree

2 files changed

+35
-0
lines changed

2 files changed

+35
-0
lines changed

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

+8
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434

3535
import org.springframework.aot.generate.GeneratedMethods;
3636
import org.springframework.aot.hint.ExecutableMode;
37+
import org.springframework.aot.hint.MemberCategory;
3738
import org.springframework.aot.hint.RuntimeHints;
3839
import org.springframework.aot.hint.TypeReference;
3940
import org.springframework.beans.BeanUtils;
@@ -195,6 +196,13 @@ private void addPropertyValues(CodeBlock.Builder code, RootBeanDefinition beanDe
195196
Method writeMethod = writeMethods.get(propertyValue.getName());
196197
if (writeMethod != null) {
197198
this.hints.reflection().registerMethod(writeMethod, ExecutableMode.INVOKE);
199+
// ReflectionUtils#findField searches recursively in the type hierarchy
200+
Class<?> searchType = beanDefinition.getTargetType();
201+
while (searchType != null && searchType != writeMethod.getDeclaringClass()) {
202+
this.hints.reflection().registerType(searchType, MemberCategory.DECLARED_FIELDS);
203+
searchType = searchType.getSuperclass();
204+
}
205+
this.hints.reflection().registerType(writeMethod.getDeclaringClass(), MemberCategory.DECLARED_FIELDS);
198206
}
199207
}
200208
}

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

+27
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import org.reactivestreams.Publisher;
3535

3636
import org.springframework.aot.generate.GeneratedClass;
37+
import org.springframework.aot.hint.MemberCategory;
3738
import org.springframework.aot.hint.predicate.RuntimeHintsPredicates;
3839
import org.springframework.aot.test.generate.TestGenerationContext;
3940
import org.springframework.beans.factory.FactoryBean;
@@ -240,6 +241,21 @@ void propertyValuesWhenValues() {
240241
assertThat(actual.getPropertyValues().get("spring")).isEqualTo("framework");
241242
});
242243
assertHasMethodInvokeHints(PropertyValuesBean.class, "setTest", "setSpring");
244+
assertHasDecalredFieldsHint(PropertyValuesBean.class);
245+
}
246+
247+
@Test
248+
void propertyValuesWhenValuesOnParentClass() {
249+
this.beanDefinition.setTargetType(ExtendedPropertyValuesBean.class);
250+
this.beanDefinition.getPropertyValues().add("test", String.class);
251+
this.beanDefinition.getPropertyValues().add("spring", "framework");
252+
compile((actual, compiled) -> {
253+
assertThat(actual.getPropertyValues().get("test")).isEqualTo(String.class);
254+
assertThat(actual.getPropertyValues().get("spring")).isEqualTo("framework");
255+
});
256+
assertHasMethodInvokeHints(PropertyValuesBean.class, "setTest", "setSpring");
257+
assertHasDecalredFieldsHint(ExtendedPropertyValuesBean.class);
258+
assertHasDecalredFieldsHint(PropertyValuesBean.class);
243259
}
244260

245261
@Test
@@ -300,6 +316,7 @@ void propertyValuesWhenValuesOnFactoryBeanClass() {
300316
assertThat(actual.getPropertyValues().get("name")).isEqualTo("World");
301317
});
302318
assertHasMethodInvokeHints(PropertyValuesFactoryBean.class, "setPrefix", "setName" );
319+
assertHasDecalredFieldsHint(PropertyValuesFactoryBean.class);
303320
}
304321

305322
@Test
@@ -453,6 +470,12 @@ private void assertHasMethodInvokeHints(Class<?> beanType, String... methodNames
453470
.test(this.generationContext.getRuntimeHints()));
454471
}
455472

473+
private void assertHasDecalredFieldsHint(Class<?> beanType) {
474+
assertThat(RuntimeHintsPredicates.reflection()
475+
.onType(beanType).withMemberCategory(MemberCategory.DECLARED_FIELDS))
476+
.accepts(this.generationContext.getRuntimeHints());
477+
}
478+
456479
private void compile(BiConsumer<RootBeanDefinition, Compiled> result) {
457480
compile(attribute -> true, result);
458481
}
@@ -524,6 +547,10 @@ public void setSpring(String spring) {
524547

525548
}
526549

550+
static class ExtendedPropertyValuesBean extends PropertyValuesBean {
551+
552+
}
553+
527554
static class PropertyValuesFactoryBean implements FactoryBean<String> {
528555

529556
private String prefix;

0 commit comments

Comments
 (0)