Polish RegisterReflectionForBinding support
Implementation and Javadoc refinements. See gh-29279
This commit is contained in:
parent
1d052742d1
commit
bbe285dd42
|
@ -39,8 +39,8 @@ import org.springframework.util.ClassUtils;
|
||||||
* Register the necessary reflection hints so that the specified type can be
|
* Register the necessary reflection hints so that the specified type can be
|
||||||
* bound at runtime. Fields, constructors, properties and record components
|
* bound at runtime. Fields, constructors, properties and record components
|
||||||
* are registered, except for a set of types like those in the {@code java.}
|
* are registered, except for a set of types like those in the {@code java.}
|
||||||
* package where just the type is registered.
|
* package where just the type is registered. Types are discovered transitively
|
||||||
* Types are discovered transitively and generic type are registered as well.
|
* on properties and record components, and generic types are registered as well.
|
||||||
*
|
*
|
||||||
* @author Sebastien Deleuze
|
* @author Sebastien Deleuze
|
||||||
* @since 6.0
|
* @since 6.0
|
||||||
|
@ -54,7 +54,7 @@ public class BindingReflectionHintsRegistrar {
|
||||||
/**
|
/**
|
||||||
* Register the necessary reflection hints to bind the specified types.
|
* Register the necessary reflection hints to bind the specified types.
|
||||||
* @param hints the hints instance to use
|
* @param hints the hints instance to use
|
||||||
* @param types the types to bind
|
* @param types the types to register
|
||||||
*/
|
*/
|
||||||
public void registerReflectionHints(ReflectionHints hints, Type... types) {
|
public void registerReflectionHints(ReflectionHints hints, Type... types) {
|
||||||
Set<Type> seen = new LinkedHashSet<>();
|
Set<Type> seen = new LinkedHashSet<>();
|
||||||
|
@ -73,15 +73,15 @@ public class BindingReflectionHintsRegistrar {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void registerReflectionHints(ReflectionHints hints, Set<Type> seen, Type type) {
|
private void registerReflectionHints(ReflectionHints hints, Set<Type> seen, Type type) {
|
||||||
|
if (seen.contains(type)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
seen.add(type);
|
||||||
if (type instanceof Class<?> clazz) {
|
if (type instanceof Class<?> clazz) {
|
||||||
if (clazz.isPrimitive() || clazz == Object.class) {
|
if (clazz.isPrimitive() || clazz == Object.class) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
hints.registerType(clazz, typeHint -> {
|
hints.registerType(clazz, typeHint -> {
|
||||||
if (seen.contains(type)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
seen.add(type);
|
|
||||||
if (shouldRegisterMembers(clazz)) {
|
if (shouldRegisterMembers(clazz)) {
|
||||||
if (clazz.isRecord()) {
|
if (clazz.isRecord()) {
|
||||||
typeHint.withMembers(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS);
|
typeHint.withMembers(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS);
|
||||||
|
@ -114,7 +114,7 @@ public class BindingReflectionHintsRegistrar {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Set<Class<?>> referencedTypes = new LinkedHashSet<>();
|
Set<Class<?>> referencedTypes = new LinkedHashSet<>();
|
||||||
collectReferencedTypes(seen, referencedTypes, type);
|
collectReferencedTypes(referencedTypes, ResolvableType.forType(type));
|
||||||
referencedTypes.forEach(referencedType -> registerReflectionHints(hints, seen, referencedType));
|
referencedTypes.forEach(referencedType -> registerReflectionHints(hints, seen, referencedType));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,10 +122,8 @@ public class BindingReflectionHintsRegistrar {
|
||||||
hints.registerMethod(method, ExecutableMode.INVOKE);
|
hints.registerMethod(method, ExecutableMode.INVOKE);
|
||||||
MethodParameter methodParameter = MethodParameter.forExecutable(method, -1);
|
MethodParameter methodParameter = MethodParameter.forExecutable(method, -1);
|
||||||
Type methodParameterType = methodParameter.getGenericParameterType();
|
Type methodParameterType = methodParameter.getGenericParameterType();
|
||||||
if (!seen.contains(methodParameterType)) {
|
|
||||||
registerReflectionHints(hints, seen, methodParameterType);
|
registerReflectionHints(hints, seen, methodParameterType);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private void registerPropertyHints(ReflectionHints hints, Set<Type> seen, @Nullable Method method, int parameterIndex) {
|
private void registerPropertyHints(ReflectionHints hints, Set<Type> seen, @Nullable Method method, int parameterIndex) {
|
||||||
if (method != null && method.getDeclaringClass() != Object.class
|
if (method != null && method.getDeclaringClass() != Object.class
|
||||||
|
@ -133,11 +131,9 @@ public class BindingReflectionHintsRegistrar {
|
||||||
hints.registerMethod(method, ExecutableMode.INVOKE);
|
hints.registerMethod(method, ExecutableMode.INVOKE);
|
||||||
MethodParameter methodParameter = MethodParameter.forExecutable(method, parameterIndex);
|
MethodParameter methodParameter = MethodParameter.forExecutable(method, parameterIndex);
|
||||||
Type methodParameterType = methodParameter.getGenericParameterType();
|
Type methodParameterType = methodParameter.getGenericParameterType();
|
||||||
if (!seen.contains(methodParameterType)) {
|
|
||||||
registerReflectionHints(hints, seen, methodParameterType);
|
registerReflectionHints(hints, seen, methodParameterType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private void registerKotlinSerializationHints(ReflectionHints hints, Class<?> clazz) {
|
private void registerKotlinSerializationHints(ReflectionHints hints, Class<?> clazz) {
|
||||||
String companionClassName = clazz.getCanonicalName() + KOTLIN_COMPANION_SUFFIX;
|
String companionClassName = clazz.getCanonicalName() + KOTLIN_COMPANION_SUFFIX;
|
||||||
|
@ -150,16 +146,12 @@ public class BindingReflectionHintsRegistrar {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void collectReferencedTypes(Set<Type> seen, Set<Class<?>> types, Type type) {
|
private void collectReferencedTypes(Set<Class<?>> types, ResolvableType resolvableType) {
|
||||||
if (seen.contains(type)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ResolvableType resolvableType = ResolvableType.forType(type);
|
|
||||||
Class<?> clazz = resolvableType.resolve();
|
Class<?> clazz = resolvableType.resolve();
|
||||||
if (clazz != null && !types.contains(clazz)) {
|
if (clazz != null && !types.contains(clazz)) {
|
||||||
types.add(clazz);
|
types.add(clazz);
|
||||||
for (ResolvableType genericResolvableType : resolvableType.getGenerics()) {
|
for (ResolvableType genericResolvableType : resolvableType.getGenerics()) {
|
||||||
collectReferencedTypes(seen, types, genericResolvableType.getType());
|
collectReferencedTypes(types, genericResolvableType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,8 +26,8 @@ import org.springframework.core.annotation.AliasFor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates that one or more {@link Class} reflection hints should be registered for
|
* Indicates that one or more {@link Class} reflection hints should be registered for
|
||||||
* data binding purpose (class, fields, properties, record components for the whole
|
* data binding purpose (class, fields, properties, record components, including
|
||||||
* type hierarchy).
|
* types transitively used on properties and record components).
|
||||||
*
|
*
|
||||||
* <p>Typically used to annotate the bean class or bean method where the reflection hint
|
* <p>Typically used to annotate the bean class or bean method where the reflection hint
|
||||||
* is needed.
|
* is needed.
|
||||||
|
@ -42,16 +42,14 @@ import org.springframework.core.annotation.AliasFor;
|
||||||
public @interface RegisterReflectionForBinding {
|
public @interface RegisterReflectionForBinding {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Classes for which reflection hints should be registered to enable data binding
|
* Classes for which reflection hints should be registered.
|
||||||
* (class, fields, properties, record components for the whole type hierarchy).
|
|
||||||
* @see #classes()
|
* @see #classes()
|
||||||
*/
|
*/
|
||||||
@AliasFor("classes")
|
@AliasFor("classes")
|
||||||
Class<?>[] value() default {};
|
Class<?>[] value() default {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Classes for which reflection hints should be registered to enable data binding
|
* Classes for which reflection hints should be registered.
|
||||||
* (class, fields, properties, record components for the whole type hierarchy).
|
|
||||||
* @see #value()
|
* @see #value()
|
||||||
*/
|
*/
|
||||||
@AliasFor("value")
|
@AliasFor("value")
|
||||||
|
|
|
@ -25,7 +25,7 @@ import org.springframework.core.annotation.AnnotationUtils;
|
||||||
/**
|
/**
|
||||||
* A {@link ReflectiveProcessor} implementation that registers reflection hints
|
* A {@link ReflectiveProcessor} implementation that registers reflection hints
|
||||||
* for data binding purpose (class, constructors, fields, properties, record
|
* for data binding purpose (class, constructors, fields, properties, record
|
||||||
* components for the whole type hierarchy).
|
* components, including types transitively used on properties and record components).
|
||||||
*
|
*
|
||||||
* @author Sebastien Deleuze
|
* @author Sebastien Deleuze
|
||||||
* @since 6.0
|
* @since 6.0
|
||||||
|
|
Loading…
Reference in New Issue