Skip to content

Commit cfbacfd

Browse files
committed
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
1 parent 5051850 commit cfbacfd

File tree

5 files changed

+24
-82
lines changed

5 files changed

+24
-82
lines changed

spring-beans/src/main/java/org/springframework/beans/factory/config/DependencyDescriptor.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ public class DependencyDescriptor extends InjectionPoint implements Serializable
7575
private Class<?> containingClass;
7676

7777
@Nullable
78-
private volatile ResolvableType resolvableType;
78+
private transient volatile ResolvableType resolvableType;
7979

8080

8181
/**

spring-core/src/main/java/org/springframework/core/ResolvableType.java

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -430,7 +430,8 @@ public ResolvableType as(Class<?> type) {
430430
if (this == NONE) {
431431
return NONE;
432432
}
433-
if (ObjectUtils.nullSafeEquals(resolve(), type)) {
433+
Class<?> resolved = resolve();
434+
if (resolved == null || resolved == type) {
434435
return this;
435436
}
436437
for (ResolvableType interfaceType : getInterfaces()) {
@@ -445,6 +446,7 @@ public ResolvableType as(Class<?> type) {
445446
/**
446447
* Return a {@link ResolvableType} representing the direct supertype of this type.
447448
* If no supertype is available this method returns {@link #NONE}.
449+
* <p>Note: The resulting {@link ResolvableType} instance may not be {@link Serializable}.
448450
* @see #getInterfaces()
449451
*/
450452
public ResolvableType getSuperType() {
@@ -454,7 +456,7 @@ public ResolvableType getSuperType() {
454456
}
455457
ResolvableType superType = this.superType;
456458
if (superType == null) {
457-
superType = forType(SerializableTypeWrapper.forGenericSuperclass(resolved), asVariableResolver());
459+
superType = forType(resolved.getGenericSuperclass(), this);
458460
this.superType = superType;
459461
}
460462
return superType;
@@ -464,16 +466,21 @@ public ResolvableType getSuperType() {
464466
* Return a {@link ResolvableType} array representing the direct interfaces
465467
* implemented by this type. If this type does not implement any interfaces an
466468
* empty array is returned.
469+
* <p>Note: The resulting {@link ResolvableType} instances may not be {@link Serializable}.
467470
* @see #getSuperType()
468471
*/
469472
public ResolvableType[] getInterfaces() {
470473
Class<?> resolved = resolve();
471-
if (resolved == null || ObjectUtils.isEmpty(resolved.getGenericInterfaces())) {
474+
if (resolved == null) {
472475
return EMPTY_TYPES_ARRAY;
473476
}
474477
ResolvableType[] interfaces = this.interfaces;
475478
if (interfaces == null) {
476-
interfaces = forTypes(SerializableTypeWrapper.forGenericInterfaces(resolved), asVariableResolver());
479+
Type[] genericIfcs = resolved.getGenericInterfaces();
480+
interfaces = new ResolvableType[genericIfcs.length];
481+
for (int i = 0; i < genericIfcs.length; i++) {
482+
interfaces[i] = forType(genericIfcs[i], this);
483+
}
477484
this.interfaces = interfaces;
478485
}
479486
return interfaces;
@@ -673,8 +680,11 @@ public ResolvableType[] getGenerics() {
673680
ResolvableType[] generics = this.generics;
674681
if (generics == null) {
675682
if (this.type instanceof Class) {
676-
Class<?> typeClass = (Class<?>) this.type;
677-
generics = forTypes(SerializableTypeWrapper.forTypeParameters(typeClass), this.variableResolver);
683+
Type[] typeParams = ((Class<?>) this.type).getTypeParameters();
684+
generics = new ResolvableType[typeParams.length];
685+
for (int i = 0; i < generics.length; i++) {
686+
generics[i] = ResolvableType.forType(typeParams[i], this);
687+
}
678688
}
679689
else if (this.type instanceof ParameterizedType) {
680690
Type[] actualTypeArguments = ((ParameterizedType) this.type).getActualTypeArguments();
@@ -818,7 +828,7 @@ ResolvableType resolveType() {
818828

819829
@Nullable
820830
private Type resolveBounds(Type[] bounds) {
821-
if (ObjectUtils.isEmpty(bounds) || Object.class == bounds[0]) {
831+
if (bounds.length == 0 || bounds[0] == Object.class) {
822832
return null;
823833
}
824834
return bounds[0];
@@ -1309,17 +1319,9 @@ public static ResolvableType forArrayComponent(ResolvableType componentType) {
13091319
return new ResolvableType(arrayClass, null, null, componentType);
13101320
}
13111321

1312-
private static ResolvableType[] forTypes(Type[] types, @Nullable VariableResolver owner) {
1313-
ResolvableType[] result = new ResolvableType[types.length];
1314-
for (int i = 0; i < types.length; i++) {
1315-
result[i] = forType(types[i], owner);
1316-
}
1317-
return result;
1318-
}
1319-
13201322
/**
13211323
* Return a {@link ResolvableType} for the specified {@link Type}.
1322-
* Note: The resulting {@link ResolvableType} may not be {@link Serializable}.
1324+
* <p>Note: The resulting {@link ResolvableType} instance may not be {@link Serializable}.
13231325
* @param type the source type (potentially {@code null})
13241326
* @return a {@link ResolvableType} for the specified {@link Type}
13251327
* @see #forType(Type, ResolvableType)
@@ -1330,7 +1332,8 @@ public static ResolvableType forType(@Nullable Type type) {
13301332

13311333
/**
13321334
* Return a {@link ResolvableType} for the specified {@link Type} backed by the given
1333-
* owner type. Note: The resulting {@link ResolvableType} may not be {@link Serializable}.
1335+
* owner type.
1336+
* <p>Note: The resulting {@link ResolvableType} instance may not be {@link Serializable}.
13341337
* @param type the source type or {@code null}
13351338
* @param owner the owner type used to resolve variables
13361339
* @return a {@link ResolvableType} for the specified {@link Type} and owner
@@ -1347,7 +1350,7 @@ public static ResolvableType forType(@Nullable Type type, @Nullable ResolvableTy
13471350

13481351
/**
13491352
* Return a {@link ResolvableType} for the specified {@link ParameterizedTypeReference}.
1350-
* Note: The resulting {@link ResolvableType} may not be {@link Serializable}.
1353+
* <p>Note: The resulting {@link ResolvableType} instance may not be {@link Serializable}.
13511354
* @param typeReference the reference to obtain the source type from
13521355
* @return a {@link ResolvableType} for the specified {@link ParameterizedTypeReference}
13531356
* @since 4.3.12

spring-core/src/main/java/org/springframework/core/SerializableTypeWrapper.java

Lines changed: 1 addition & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,7 @@
4141
*
4242
* <p>{@link #forField(Field) Fields} or {@link #forMethodParameter(MethodParameter)
4343
* MethodParameters} can be used as the root source for a serializable type.
44-
* Alternatively the {@link #forGenericSuperclass(Class) superclass},
45-
* {@link #forGenericInterfaces(Class) interfaces} or {@link #forTypeParameters(Class)
46-
* type parameters} or a regular {@link Class} can also be used as source.
44+
* Alternatively, a regular {@link Class} can also be used as source.
4745
*
4846
* <p>The returned type will either be a {@link Class} or a serializable proxy of
4947
* {@link GenericArrayType}, {@link ParameterizedType}, {@link TypeVariable} or
@@ -84,41 +82,6 @@ public static Type forMethodParameter(MethodParameter methodParameter) {
8482
return forTypeProvider(new MethodParameterTypeProvider(methodParameter));
8583
}
8684

87-
/**
88-
* Return a {@link Serializable} variant of {@link Class#getGenericSuperclass()}.
89-
*/
90-
@SuppressWarnings("serial")
91-
@Nullable
92-
public static Type forGenericSuperclass(final Class<?> type) {
93-
return forTypeProvider(type::getGenericSuperclass);
94-
}
95-
96-
/**
97-
* Return a {@link Serializable} variant of {@link Class#getGenericInterfaces()}.
98-
*/
99-
@SuppressWarnings("serial")
100-
public static Type[] forGenericInterfaces(final Class<?> type) {
101-
Type[] result = new Type[type.getGenericInterfaces().length];
102-
for (int i = 0; i < result.length; i++) {
103-
final int index = i;
104-
result[i] = forTypeProvider(() -> type.getGenericInterfaces()[index]);
105-
}
106-
return result;
107-
}
108-
109-
/**
110-
* Return a {@link Serializable} variant of {@link Class#getTypeParameters()}.
111-
*/
112-
@SuppressWarnings("serial")
113-
public static Type[] forTypeParameters(final Class<?> type) {
114-
Type[] result = new Type[type.getTypeParameters().length];
115-
for (int i = 0; i < result.length; i++) {
116-
final int index = i;
117-
result[i] = forTypeProvider(() -> type.getTypeParameters()[index]);
118-
}
119-
return result;
120-
}
121-
12285
/**
12386
* Unwrap the given type, effectively returning the original non-serializable type.
12487
* @param type the type to unwrap

spring-core/src/test/java/org/springframework/core/ResolvableTypeTests.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1246,8 +1246,6 @@ public void serialize() throws Exception {
12461246
testSerialization(ResolvableType.forMethodReturnType(Methods.class.getMethod("charSequenceReturn")));
12471247
testSerialization(ResolvableType.forConstructorParameter(Constructors.class.getConstructor(List.class), 0));
12481248
testSerialization(ResolvableType.forField(Fields.class.getField("charSequenceList")).getGeneric());
1249-
testSerialization(ResolvableType.forField(Fields.class.getField("charSequenceList")).asCollection());
1250-
testSerialization(ResolvableType.forClass(ExtendsMap.class).getSuperType());
12511249
ResolvableType deserializedNone = testSerialization(ResolvableType.NONE);
12521250
assertThat(deserializedNone, sameInstance(ResolvableType.NONE));
12531251
}

spring-core/src/test/java/org/springframework/core/SerializableTypeWrapperTests.java

Lines changed: 1 addition & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2016 the original author or authors.
2+
* Copyright 2002-2018 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.
@@ -27,7 +27,6 @@
2727
import java.lang.reflect.Type;
2828
import java.lang.reflect.TypeVariable;
2929
import java.lang.reflect.WildcardType;
30-
import java.util.ArrayList;
3130
import java.util.List;
3231

3332
import org.junit.Test;
@@ -65,27 +64,6 @@ public void forConstructor() throws Exception {
6564
assertSerializable(type);
6665
}
6766

68-
@Test
69-
public void forGenericSuperClass() throws Exception {
70-
Type type = SerializableTypeWrapper.forGenericSuperclass(ArrayList.class);
71-
assertThat(type.toString(), equalTo("java.util.AbstractList<E>"));
72-
assertSerializable(type);
73-
}
74-
75-
@Test
76-
public void forGenericInterfaces() throws Exception {
77-
Type type = SerializableTypeWrapper.forGenericInterfaces(List.class)[0];
78-
assertThat(type.toString(), equalTo("java.util.Collection<E>"));
79-
assertSerializable(type);
80-
}
81-
82-
@Test
83-
public void forTypeParameters() throws Exception {
84-
Type type = SerializableTypeWrapper.forTypeParameters(List.class)[0];
85-
assertThat(type.toString(), equalTo("E"));
86-
assertSerializable(type);
87-
}
88-
8967
@Test
9068
public void classType() throws Exception {
9169
Type type = SerializableTypeWrapper.forField(Fields.class.getField("classType"));

0 commit comments

Comments
 (0)