Revise ResolvableType.as for introspection performance
This revision limits serializability of derived interfaces, superclasses and type parameters, optimizing for introspection performance instead. Issue: SPR-17070
This commit is contained in:
parent
5051850fa9
commit
cfbacfd89b
|
|
@ -75,7 +75,7 @@ public class DependencyDescriptor extends InjectionPoint implements Serializable
|
|||
private Class<?> containingClass;
|
||||
|
||||
@Nullable
|
||||
private volatile ResolvableType resolvableType;
|
||||
private transient volatile ResolvableType resolvableType;
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -430,7 +430,8 @@ public class ResolvableType implements Serializable {
|
|||
if (this == NONE) {
|
||||
return NONE;
|
||||
}
|
||||
if (ObjectUtils.nullSafeEquals(resolve(), type)) {
|
||||
Class<?> resolved = resolve();
|
||||
if (resolved == null || resolved == type) {
|
||||
return this;
|
||||
}
|
||||
for (ResolvableType interfaceType : getInterfaces()) {
|
||||
|
|
@ -445,6 +446,7 @@ public class ResolvableType implements Serializable {
|
|||
/**
|
||||
* Return a {@link ResolvableType} representing the direct supertype of this type.
|
||||
* If no supertype is available this method returns {@link #NONE}.
|
||||
* <p>Note: The resulting {@link ResolvableType} instance may not be {@link Serializable}.
|
||||
* @see #getInterfaces()
|
||||
*/
|
||||
public ResolvableType getSuperType() {
|
||||
|
|
@ -454,7 +456,7 @@ public class ResolvableType implements Serializable {
|
|||
}
|
||||
ResolvableType superType = this.superType;
|
||||
if (superType == null) {
|
||||
superType = forType(SerializableTypeWrapper.forGenericSuperclass(resolved), asVariableResolver());
|
||||
superType = forType(resolved.getGenericSuperclass(), this);
|
||||
this.superType = superType;
|
||||
}
|
||||
return superType;
|
||||
|
|
@ -464,16 +466,21 @@ public class ResolvableType implements Serializable {
|
|||
* Return a {@link ResolvableType} array representing the direct interfaces
|
||||
* implemented by this type. If this type does not implement any interfaces an
|
||||
* empty array is returned.
|
||||
* <p>Note: The resulting {@link ResolvableType} instances may not be {@link Serializable}.
|
||||
* @see #getSuperType()
|
||||
*/
|
||||
public ResolvableType[] getInterfaces() {
|
||||
Class<?> resolved = resolve();
|
||||
if (resolved == null || ObjectUtils.isEmpty(resolved.getGenericInterfaces())) {
|
||||
if (resolved == null) {
|
||||
return EMPTY_TYPES_ARRAY;
|
||||
}
|
||||
ResolvableType[] interfaces = this.interfaces;
|
||||
if (interfaces == null) {
|
||||
interfaces = forTypes(SerializableTypeWrapper.forGenericInterfaces(resolved), asVariableResolver());
|
||||
Type[] genericIfcs = resolved.getGenericInterfaces();
|
||||
interfaces = new ResolvableType[genericIfcs.length];
|
||||
for (int i = 0; i < genericIfcs.length; i++) {
|
||||
interfaces[i] = forType(genericIfcs[i], this);
|
||||
}
|
||||
this.interfaces = interfaces;
|
||||
}
|
||||
return interfaces;
|
||||
|
|
@ -673,8 +680,11 @@ public class ResolvableType implements Serializable {
|
|||
ResolvableType[] generics = this.generics;
|
||||
if (generics == null) {
|
||||
if (this.type instanceof Class) {
|
||||
Class<?> typeClass = (Class<?>) this.type;
|
||||
generics = forTypes(SerializableTypeWrapper.forTypeParameters(typeClass), this.variableResolver);
|
||||
Type[] typeParams = ((Class<?>) this.type).getTypeParameters();
|
||||
generics = new ResolvableType[typeParams.length];
|
||||
for (int i = 0; i < generics.length; i++) {
|
||||
generics[i] = ResolvableType.forType(typeParams[i], this);
|
||||
}
|
||||
}
|
||||
else if (this.type instanceof ParameterizedType) {
|
||||
Type[] actualTypeArguments = ((ParameterizedType) this.type).getActualTypeArguments();
|
||||
|
|
@ -818,7 +828,7 @@ public class ResolvableType implements Serializable {
|
|||
|
||||
@Nullable
|
||||
private Type resolveBounds(Type[] bounds) {
|
||||
if (ObjectUtils.isEmpty(bounds) || Object.class == bounds[0]) {
|
||||
if (bounds.length == 0 || bounds[0] == Object.class) {
|
||||
return null;
|
||||
}
|
||||
return bounds[0];
|
||||
|
|
@ -1309,17 +1319,9 @@ public class ResolvableType implements Serializable {
|
|||
return new ResolvableType(arrayClass, null, null, componentType);
|
||||
}
|
||||
|
||||
private static ResolvableType[] forTypes(Type[] types, @Nullable VariableResolver owner) {
|
||||
ResolvableType[] result = new ResolvableType[types.length];
|
||||
for (int i = 0; i < types.length; i++) {
|
||||
result[i] = forType(types[i], owner);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@link ResolvableType} for the specified {@link Type}.
|
||||
* Note: The resulting {@link ResolvableType} may not be {@link Serializable}.
|
||||
* <p>Note: The resulting {@link ResolvableType} instance may not be {@link Serializable}.
|
||||
* @param type the source type (potentially {@code null})
|
||||
* @return a {@link ResolvableType} for the specified {@link Type}
|
||||
* @see #forType(Type, ResolvableType)
|
||||
|
|
@ -1330,7 +1332,8 @@ public class ResolvableType implements Serializable {
|
|||
|
||||
/**
|
||||
* Return a {@link ResolvableType} for the specified {@link Type} backed by the given
|
||||
* owner type. Note: The resulting {@link ResolvableType} may not be {@link Serializable}.
|
||||
* owner type.
|
||||
* <p>Note: The resulting {@link ResolvableType} instance may not be {@link Serializable}.
|
||||
* @param type the source type or {@code null}
|
||||
* @param owner the owner type used to resolve variables
|
||||
* @return a {@link ResolvableType} for the specified {@link Type} and owner
|
||||
|
|
@ -1347,7 +1350,7 @@ public class ResolvableType implements Serializable {
|
|||
|
||||
/**
|
||||
* Return a {@link ResolvableType} for the specified {@link ParameterizedTypeReference}.
|
||||
* Note: The resulting {@link ResolvableType} may not be {@link Serializable}.
|
||||
* <p>Note: The resulting {@link ResolvableType} instance may not be {@link Serializable}.
|
||||
* @param typeReference the reference to obtain the source type from
|
||||
* @return a {@link ResolvableType} for the specified {@link ParameterizedTypeReference}
|
||||
* @since 4.3.12
|
||||
|
|
|
|||
|
|
@ -41,9 +41,7 @@ import org.springframework.util.ReflectionUtils;
|
|||
*
|
||||
* <p>{@link #forField(Field) Fields} or {@link #forMethodParameter(MethodParameter)
|
||||
* MethodParameters} can be used as the root source for a serializable type.
|
||||
* Alternatively the {@link #forGenericSuperclass(Class) superclass},
|
||||
* {@link #forGenericInterfaces(Class) interfaces} or {@link #forTypeParameters(Class)
|
||||
* type parameters} or a regular {@link Class} can also be used as source.
|
||||
* Alternatively, a regular {@link Class} can also be used as source.
|
||||
*
|
||||
* <p>The returned type will either be a {@link Class} or a serializable proxy of
|
||||
* {@link GenericArrayType}, {@link ParameterizedType}, {@link TypeVariable} or
|
||||
|
|
@ -84,41 +82,6 @@ final class SerializableTypeWrapper {
|
|||
return forTypeProvider(new MethodParameterTypeProvider(methodParameter));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@link Serializable} variant of {@link Class#getGenericSuperclass()}.
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
@Nullable
|
||||
public static Type forGenericSuperclass(final Class<?> type) {
|
||||
return forTypeProvider(type::getGenericSuperclass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@link Serializable} variant of {@link Class#getGenericInterfaces()}.
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public static Type[] forGenericInterfaces(final Class<?> type) {
|
||||
Type[] result = new Type[type.getGenericInterfaces().length];
|
||||
for (int i = 0; i < result.length; i++) {
|
||||
final int index = i;
|
||||
result[i] = forTypeProvider(() -> type.getGenericInterfaces()[index]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@link Serializable} variant of {@link Class#getTypeParameters()}.
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public static Type[] forTypeParameters(final Class<?> type) {
|
||||
Type[] result = new Type[type.getTypeParameters().length];
|
||||
for (int i = 0; i < result.length; i++) {
|
||||
final int index = i;
|
||||
result[i] = forTypeProvider(() -> type.getTypeParameters()[index]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unwrap the given type, effectively returning the original non-serializable type.
|
||||
* @param type the type to unwrap
|
||||
|
|
|
|||
|
|
@ -1246,8 +1246,6 @@ public class ResolvableTypeTests {
|
|||
testSerialization(ResolvableType.forMethodReturnType(Methods.class.getMethod("charSequenceReturn")));
|
||||
testSerialization(ResolvableType.forConstructorParameter(Constructors.class.getConstructor(List.class), 0));
|
||||
testSerialization(ResolvableType.forField(Fields.class.getField("charSequenceList")).getGeneric());
|
||||
testSerialization(ResolvableType.forField(Fields.class.getField("charSequenceList")).asCollection());
|
||||
testSerialization(ResolvableType.forClass(ExtendsMap.class).getSuperType());
|
||||
ResolvableType deserializedNone = testSerialization(ResolvableType.NONE);
|
||||
assertThat(deserializedNone, sameInstance(ResolvableType.NONE));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2018 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.
|
||||
|
|
@ -27,7 +27,6 @@ import java.lang.reflect.ParameterizedType;
|
|||
import java.lang.reflect.Type;
|
||||
import java.lang.reflect.TypeVariable;
|
||||
import java.lang.reflect.WildcardType;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Test;
|
||||
|
|
@ -65,27 +64,6 @@ public class SerializableTypeWrapperTests {
|
|||
assertSerializable(type);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void forGenericSuperClass() throws Exception {
|
||||
Type type = SerializableTypeWrapper.forGenericSuperclass(ArrayList.class);
|
||||
assertThat(type.toString(), equalTo("java.util.AbstractList<E>"));
|
||||
assertSerializable(type);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void forGenericInterfaces() throws Exception {
|
||||
Type type = SerializableTypeWrapper.forGenericInterfaces(List.class)[0];
|
||||
assertThat(type.toString(), equalTo("java.util.Collection<E>"));
|
||||
assertSerializable(type);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void forTypeParameters() throws Exception {
|
||||
Type type = SerializableTypeWrapper.forTypeParameters(List.class)[0];
|
||||
assertThat(type.toString(), equalTo("E"));
|
||||
assertSerializable(type);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void classType() throws Exception {
|
||||
Type type = SerializableTypeWrapper.forField(Fields.class.getField("classType"));
|
||||
|
|
|
|||
Loading…
Reference in New Issue