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
This commit is contained in:
parent
a86612a254
commit
f7a6a7b814
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2023 the original author or authors.
|
||||
* Copyright 2002-2024 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -33,7 +33,6 @@ import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
|||
import org.springframework.javapoet.ClassName;
|
||||
import org.springframework.javapoet.CodeBlock;
|
||||
import org.springframework.javapoet.MethodSpec;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* AOT contribution from a {@link BeanRegistrationsAotProcessor} used to
|
||||
|
|
@ -115,23 +114,10 @@ class BeanRegistrationsAotContribution
|
|||
ReflectionHints hints = runtimeHints.reflection();
|
||||
Class<?> beanClass = beanRegistrationKey.beanClass();
|
||||
hints.registerType(beanClass, MemberCategory.INTROSPECT_PUBLIC_METHODS, MemberCategory.INTROSPECT_DECLARED_METHODS);
|
||||
introspectPublicMethodsOnAllInterfaces(hints, beanClass);
|
||||
hints.registerForInterfaces(beanClass, typeHint -> typeHint.withMembers(MemberCategory.INTROSPECT_PUBLIC_METHODS));
|
||||
});
|
||||
}
|
||||
|
||||
private void introspectPublicMethodsOnAllInterfaces(ReflectionHints hints, Class<?> type) {
|
||||
Class<?> currentClass = type;
|
||||
while (currentClass != null && currentClass != Object.class) {
|
||||
for (Class<?> interfaceType : currentClass.getInterfaces()) {
|
||||
if (!ClassUtils.isJavaLanguageInterface(interfaceType)) {
|
||||
hints.registerType(interfaceType, MemberCategory.INTROSPECT_PUBLIC_METHODS);
|
||||
introspectPublicMethodsOnAllInterfaces(hints, interfaceType);
|
||||
}
|
||||
}
|
||||
currentClass = currentClass.getSuperclass();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gather the necessary information to register a particular bean.
|
||||
* @param methodGenerator the {@link BeanDefinitionMethodGenerator} to use
|
||||
|
|
|
|||
|
|
@ -175,6 +175,28 @@ public class ReflectionHints {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register or customize reflection hints for all the interfaces implemented by
|
||||
* the given type and its parent classes, ignoring the common Java language interfaces.
|
||||
* The specified {@code typeHint} consumer is invoked for each type.
|
||||
* @param type the type to consider
|
||||
* @param typeHint a builder to further customize hints for each type
|
||||
* @return {@code this}, to facilitate method chaining
|
||||
*/
|
||||
public ReflectionHints registerForInterfaces(Class<?> type, Consumer<TypeHint.Builder> typeHint) {
|
||||
Class<?> currentClass = type;
|
||||
while (currentClass != null && currentClass != Object.class) {
|
||||
for (Class<?> interfaceType : currentClass.getInterfaces()) {
|
||||
if (!ClassUtils.isJavaLanguageInterface(interfaceType)) {
|
||||
this.registerType(interfaceType, typeHint);
|
||||
registerForInterfaces(interfaceType, typeHint);
|
||||
}
|
||||
}
|
||||
currentClass = currentClass.getSuperclass();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register the need for reflection on the specified {@link Field}.
|
||||
* @param field the field that requires reflection
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
package org.springframework.aot.hint;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
|
|
@ -209,6 +210,18 @@ class ReflectionHintsTests {
|
|||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void registerOnInterfaces() {
|
||||
this.reflectionHints.registerForInterfaces(ChildType.class,
|
||||
typeHint -> typeHint.withMembers(MemberCategory.INTROSPECT_PUBLIC_METHODS));
|
||||
assertThat(this.reflectionHints.typeHints()).hasSize(2)
|
||||
.noneMatch(typeHint -> typeHint.getType().getCanonicalName().equals(Serializable.class.getCanonicalName()))
|
||||
.anyMatch(typeHint -> typeHint.getType().getCanonicalName().equals(SecondInterface.class.getCanonicalName())
|
||||
&& typeHint.getMemberCategories().contains(MemberCategory.INTROSPECT_PUBLIC_METHODS))
|
||||
.anyMatch(typeHint -> typeHint.getType().getCanonicalName().equals(FirstInterface.class.getCanonicalName())
|
||||
&& typeHint.getMemberCategories().contains(MemberCategory.INTROSPECT_PUBLIC_METHODS));
|
||||
}
|
||||
|
||||
private void assertTestTypeMethodHints(Consumer<ExecutableHint> methodHint) {
|
||||
assertThat(this.reflectionHints.typeHints()).singleElement().satisfies(typeHint -> {
|
||||
assertThat(typeHint.getType().getCanonicalName()).isEqualTo(TestType.class.getCanonicalName());
|
||||
|
|
@ -241,4 +254,28 @@ class ReflectionHintsTests {
|
|||
|
||||
}
|
||||
|
||||
interface FirstInterface {
|
||||
void first();
|
||||
}
|
||||
|
||||
interface SecondInterface {
|
||||
void second();
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
static class ParentType implements Serializable, FirstInterface {
|
||||
@Override
|
||||
public void first() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
static class ChildType extends ParentType implements SecondInterface {
|
||||
@Override
|
||||
public void second() {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue