Skip to content

Commit f7a6a7b

Browse files
committed
Allow ReflectionHints to register hints on interface hierarchies
This commit promotes a previously private method in `BeanRegistrationsAotContribution` to a top-level method in `ReflectionHints`. This helps to register hints on all interfaces implemented in the class hierarchy of the given type. Closes gh-32824
1 parent a86612a commit f7a6a7b

File tree

3 files changed

+61
-16
lines changed

3 files changed

+61
-16
lines changed

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

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2023 the original author or authors.
2+
* Copyright 2002-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -33,7 +33,6 @@
3333
import org.springframework.javapoet.ClassName;
3434
import org.springframework.javapoet.CodeBlock;
3535
import org.springframework.javapoet.MethodSpec;
36-
import org.springframework.util.ClassUtils;
3736

3837
/**
3938
* AOT contribution from a {@link BeanRegistrationsAotProcessor} used to
@@ -115,23 +114,10 @@ private void generateRegisterHints(RuntimeHints runtimeHints, Map<BeanRegistrati
115114
ReflectionHints hints = runtimeHints.reflection();
116115
Class<?> beanClass = beanRegistrationKey.beanClass();
117116
hints.registerType(beanClass, MemberCategory.INTROSPECT_PUBLIC_METHODS, MemberCategory.INTROSPECT_DECLARED_METHODS);
118-
introspectPublicMethodsOnAllInterfaces(hints, beanClass);
117+
hints.registerForInterfaces(beanClass, typeHint -> typeHint.withMembers(MemberCategory.INTROSPECT_PUBLIC_METHODS));
119118
});
120119
}
121120

122-
private void introspectPublicMethodsOnAllInterfaces(ReflectionHints hints, Class<?> type) {
123-
Class<?> currentClass = type;
124-
while (currentClass != null && currentClass != Object.class) {
125-
for (Class<?> interfaceType : currentClass.getInterfaces()) {
126-
if (!ClassUtils.isJavaLanguageInterface(interfaceType)) {
127-
hints.registerType(interfaceType, MemberCategory.INTROSPECT_PUBLIC_METHODS);
128-
introspectPublicMethodsOnAllInterfaces(hints, interfaceType);
129-
}
130-
}
131-
currentClass = currentClass.getSuperclass();
132-
}
133-
}
134-
135121
/**
136122
* Gather the necessary information to register a particular bean.
137123
* @param methodGenerator the {@link BeanDefinitionMethodGenerator} to use

spring-core/src/main/java/org/springframework/aot/hint/ReflectionHints.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,28 @@ public ReflectionHints registerTypes(Iterable<TypeReference> types, Consumer<Typ
175175
return this;
176176
}
177177

178+
/**
179+
* Register or customize reflection hints for all the interfaces implemented by
180+
* the given type and its parent classes, ignoring the common Java language interfaces.
181+
* The specified {@code typeHint} consumer is invoked for each type.
182+
* @param type the type to consider
183+
* @param typeHint a builder to further customize hints for each type
184+
* @return {@code this}, to facilitate method chaining
185+
*/
186+
public ReflectionHints registerForInterfaces(Class<?> type, Consumer<TypeHint.Builder> typeHint) {
187+
Class<?> currentClass = type;
188+
while (currentClass != null && currentClass != Object.class) {
189+
for (Class<?> interfaceType : currentClass.getInterfaces()) {
190+
if (!ClassUtils.isJavaLanguageInterface(interfaceType)) {
191+
this.registerType(interfaceType, typeHint);
192+
registerForInterfaces(interfaceType, typeHint);
193+
}
194+
}
195+
currentClass = currentClass.getSuperclass();
196+
}
197+
return this;
198+
}
199+
178200
/**
179201
* Register the need for reflection on the specified {@link Field}.
180202
* @param field the field that requires reflection

spring-core/src/test/java/org/springframework/aot/hint/ReflectionHintsTests.java

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package org.springframework.aot.hint;
1818

19+
import java.io.Serializable;
1920
import java.lang.reflect.Constructor;
2021
import java.lang.reflect.Field;
2122
import java.lang.reflect.Method;
@@ -209,6 +210,18 @@ void registerMethodTwiceUpdatesExistingEntry() {
209210
});
210211
}
211212

213+
@Test
214+
void registerOnInterfaces() {
215+
this.reflectionHints.registerForInterfaces(ChildType.class,
216+
typeHint -> typeHint.withMembers(MemberCategory.INTROSPECT_PUBLIC_METHODS));
217+
assertThat(this.reflectionHints.typeHints()).hasSize(2)
218+
.noneMatch(typeHint -> typeHint.getType().getCanonicalName().equals(Serializable.class.getCanonicalName()))
219+
.anyMatch(typeHint -> typeHint.getType().getCanonicalName().equals(SecondInterface.class.getCanonicalName())
220+
&& typeHint.getMemberCategories().contains(MemberCategory.INTROSPECT_PUBLIC_METHODS))
221+
.anyMatch(typeHint -> typeHint.getType().getCanonicalName().equals(FirstInterface.class.getCanonicalName())
222+
&& typeHint.getMemberCategories().contains(MemberCategory.INTROSPECT_PUBLIC_METHODS));
223+
}
224+
212225
private void assertTestTypeMethodHints(Consumer<ExecutableHint> methodHint) {
213226
assertThat(this.reflectionHints.typeHints()).singleElement().satisfies(typeHint -> {
214227
assertThat(typeHint.getType().getCanonicalName()).isEqualTo(TestType.class.getCanonicalName());
@@ -241,4 +254,28 @@ void setName(String name) {
241254

242255
}
243256

257+
interface FirstInterface {
258+
void first();
259+
}
260+
261+
interface SecondInterface {
262+
void second();
263+
}
264+
265+
@SuppressWarnings("serial")
266+
static class ParentType implements Serializable, FirstInterface {
267+
@Override
268+
public void first() {
269+
270+
}
271+
}
272+
273+
@SuppressWarnings("serial")
274+
static class ChildType extends ParentType implements SecondInterface {
275+
@Override
276+
public void second() {
277+
278+
}
279+
}
280+
244281
}

0 commit comments

Comments
 (0)