From f145ca0c3c3a5a1cdb97fdcd05e77f163eecd016 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Wed, 19 Jul 2023 14:36:58 +0100 Subject: [PATCH] Fix reflection hint generation for properties nested in superclass Fixes gh-36406 --- .../bind/BindableRuntimeHintsRegistrar.java | 3 +- .../BindableRuntimeHintsRegistrarTests.java | 58 +++++++++++++++++++ 2 files changed, 60 insertions(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/BindableRuntimeHintsRegistrar.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/BindableRuntimeHintsRegistrar.java index ebb002a1516..40fbba7d7a9 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/BindableRuntimeHintsRegistrar.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/bind/BindableRuntimeHintsRegistrar.java @@ -317,7 +317,8 @@ public class BindableRuntimeHintsRegistrar implements RuntimeHintsRegistrar { * @return whether the specified {@code propertyType} is a nested type */ private boolean isNestedType(String propertyName, Class propertyType) { - if (this.type.equals(propertyType.getDeclaringClass())) { + Class declaringClass = propertyType.getDeclaringClass(); + if (declaringClass != null && declaringClass.isAssignableFrom(this.type)) { return true; } Field field = ReflectionUtils.findField(this.type, propertyName); diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/BindableRuntimeHintsRegistrarTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/BindableRuntimeHintsRegistrarTests.java index e42cba58407..b1b4f8bbfbf 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/BindableRuntimeHintsRegistrarTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/bind/BindableRuntimeHintsRegistrarTests.java @@ -34,6 +34,7 @@ import org.springframework.aot.hint.predicate.RuntimeHintsPredicates; import org.springframework.boot.context.properties.BoundConfigurationProperties; import org.springframework.boot.context.properties.ConfigurationPropertiesBean; import org.springframework.boot.context.properties.NestedConfigurationProperty; +import org.springframework.boot.context.properties.bind.BindableRuntimeHintsRegistrarTests.BaseProperties.InheritedNested; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.context.EnvironmentAware; @@ -243,6 +244,21 @@ class BindableRuntimeHintsRegistrarTests { "setBravo")); } + @Test + void registerHintsWhenHasInheritedNestedProperties() { + RuntimeHints runtimeHints = registerHints(ExtendingProperties.class); + assertThat(runtimeHints.reflection().typeHints()).hasSize(3); + assertThat(runtimeHints.reflection().getTypeHint(BaseProperties.class)).satisfies((entry) -> { + assertThat(entry.getMemberCategories()).isEmpty(); + assertThat(entry.methods()).extracting(ExecutableHint::getName) + .containsExactlyInAnyOrder("getInheritedNested", "setInheritedNested"); + }); + assertThat(runtimeHints.reflection().getTypeHint(ExtendingProperties.class)) + .satisfies(javaBeanBinding(ExtendingProperties.class, "getBravo", "setBravo")); + assertThat(runtimeHints.reflection().getTypeHint(InheritedNested.class)) + .satisfies(javaBeanBinding(InheritedNested.class, "getAlpha", "setAlpha")); + } + private Consumer javaBeanBinding(Class type, String... expectedMethods) { return javaBeanBinding(type, type.getDeclaredConstructors()[0], expectedMethods); } @@ -665,4 +681,46 @@ class BindableRuntimeHintsRegistrarTests { } + public abstract static class BaseProperties { + + private InheritedNested inheritedNested; + + public InheritedNested getInheritedNested() { + return this.inheritedNested; + } + + public void setInheritedNested(InheritedNested inheritedNested) { + this.inheritedNested = inheritedNested; + } + + public static class InheritedNested { + + private String alpha; + + public String getAlpha() { + return this.alpha; + } + + public void setAlpha(String alpha) { + this.alpha = alpha; + } + + } + + } + + public static class ExtendingProperties extends BaseProperties { + + private String bravo; + + public String getBravo() { + return this.bravo; + } + + public void setBravo(String bravo) { + this.bravo = bravo; + } + + } + }