diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanDefinitionPropertiesCodeGenerator.java b/spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanDefinitionPropertiesCodeGenerator.java index 614cc32abf..dbd44b1b0a 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanDefinitionPropertiesCodeGenerator.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanDefinitionPropertiesCodeGenerator.java @@ -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 { 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); } } } diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/aot/BeanDefinitionPropertiesCodeGeneratorTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/aot/BeanDefinitionPropertiesCodeGeneratorTests.java index aa1f663b8b..8cdf923bb6 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/aot/BeanDefinitionPropertiesCodeGeneratorTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/aot/BeanDefinitionPropertiesCodeGeneratorTests.java @@ -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 { 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 { assertThat(actual.getPropertyValues().get("name")).isEqualTo("World"); }); assertHasMethodInvokeHints(PropertyValuesFactoryBean.class, "setPrefix", "setName" ); + assertHasDecalredFieldsHint(PropertyValuesFactoryBean.class); } @Test @@ -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 result) { compile(attribute -> true, result); } @@ -524,6 +547,10 @@ class BeanDefinitionPropertiesCodeGeneratorTests { } + static class ExtendedPropertyValuesBean extends PropertyValuesBean { + + } + static class PropertyValuesFactoryBean implements FactoryBean { private String prefix;