Skip to content

Commit f29092d

Browse files
author
Phillip Webb
committed
Polish ResolvableType & SerializableTypeWrapper
Fix 'missing serialVersionUID' warnings, support for void.class types and refine resolve() algorithm to support narrowed types. Issue: SPR-10973
1 parent f4a66a4 commit f29092d

File tree

3 files changed

+67
-15
lines changed

3 files changed

+67
-15
lines changed

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

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@
7272
*/
7373
public final class ResolvableType implements Serializable {
7474

75+
private static final long serialVersionUID = 1L;
76+
77+
7578
private static ConcurrentReferenceHashMap<ResolvableType, ResolvableType> cache =
7679
new ConcurrentReferenceHashMap<ResolvableType, ResolvableType>();
7780

@@ -97,8 +100,13 @@ public final class ResolvableType implements Serializable {
97100
private final VariableResolver variableResolver;
98101

99102
/**
100-
* Stored copy of the resolved value or {@code null} if the resolve method has not
101-
* yet been called. {@code void.class} is used when the resolve method failed.
103+
* If resolution has happened and {@link #resolved} contains a valid result.
104+
*/
105+
private boolean isResolved = false;
106+
107+
/**
108+
* Late binding stored copy of the resolved value (valid when {@link #isResolved} is
109+
* true).
102110
*/
103111
private Class<?> resolved;
104112

@@ -484,11 +492,11 @@ public Class<?> resolve() {
484492
* @see #resolveGenerics()
485493
*/
486494
public Class<?> resolve(Class<?> fallback) {
487-
if (this.resolved == null) {
488-
Class<?> resolvedClass = resolveClass();
489-
this.resolved = (resolvedClass == null ? void.class : resolvedClass);
495+
if (!this.isResolved) {
496+
this.resolved = resolveClass();
497+
this.isResolved = true;
490498
}
491-
return (this.resolved == void.class ? fallback : this.resolved);
499+
return (this.resolved == null ? fallback : this.resolved);
492500
}
493501

494502
private Class<?> resolveClass() {
@@ -553,15 +561,12 @@ private ResolvableType resolveVariable(TypeVariable<?> variable) {
553561
}
554562

555563
if (this.type instanceof ParameterizedType) {
556-
557564
ParameterizedType parameterizedType = (ParameterizedType) this.type;
558-
if (parameterizedType.getRawType().equals(variable.getGenericDeclaration())) {
559-
TypeVariable<?>[] variables = resolve().getTypeParameters();
560-
for (int i = 0; i < variables.length; i++) {
561-
if (ObjectUtils.nullSafeEquals(variables[i].getName(), variable.getName())) {
562-
Type actualType = parameterizedType.getActualTypeArguments()[i];
563-
return forType(actualType, this.variableResolver);
564-
}
565+
TypeVariable<?>[] variables = resolve().getTypeParameters();
566+
for (int i = 0; i < variables.length; i++) {
567+
if (ObjectUtils.nullSafeEquals(variables[i].getName(), variable.getName())) {
568+
Type actualType = parameterizedType.getActualTypeArguments()[i];
569+
return forType(actualType, this.variableResolver);
565570
}
566571
}
567572

@@ -637,6 +642,10 @@ VariableResolver asVariableResolver() {
637642
}
638643

639644
return new VariableResolver() {
645+
646+
private static final long serialVersionUID = 1L;
647+
648+
640649
@Override
641650
public ResolvableType resolveVariable(TypeVariable<?> variable) {
642651
return ResolvableType.this.resolveVariable(variable);
@@ -901,7 +910,13 @@ public static ResolvableType forClassWithGenerics(Class<?> sourceClass,
901910
final TypeVariable<?>[] typeVariables = sourceClass.getTypeParameters();
902911
Assert.isTrue(typeVariables.length == generics.length,
903912
"Missmatched number of generics specified");
913+
914+
904915
VariableResolver variableResolver = new VariableResolver() {
916+
917+
private static final long serialVersionUID = 1L;
918+
919+
905920
@Override
906921
public ResolvableType resolveVariable(TypeVariable<?> variable) {
907922
for (int i = 0; i < typeVariables.length; i++) {

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

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,10 @@ public static Type forMethodParameter(MethodParameter methodParameter) {
7878
*/
7979
public static Type forGenericSuperclass(final Class<?> type) {
8080
return forTypeProvider(new TypeProvider() {
81+
82+
private static final long serialVersionUID = 1L;
83+
84+
8185
@Override
8286
public Type getType() {
8387
return type.getGenericSuperclass();
@@ -93,6 +97,10 @@ public static Type[] forGenericInterfaces(final Class<?> type) {
9397
for (int i = 0; i < result.length; i++) {
9498
final int index = i;
9599
result[i] = forTypeProvider(new TypeProvider() {
100+
101+
private static final long serialVersionUID = 1L;
102+
103+
96104
@Override
97105
public Type getType() {
98106
return type.getGenericInterfaces()[index];
@@ -110,6 +118,10 @@ public static Type[] forTypeParameters(final Class<?> type) {
110118
for (int i = 0; i < result.length; i++) {
111119
final int index = i;
112120
result[i] = forTypeProvider(new TypeProvider() {
121+
122+
private static final long serialVersionUID = 1L;
123+
124+
113125
@Override
114126
public Type getType() {
115127
return type.getTypeParameters()[index];
@@ -162,6 +174,9 @@ private static interface TypeProvider extends Serializable {
162174
private static class TypeProxyInvocationHandler implements InvocationHandler,
163175
Serializable {
164176

177+
private static final long serialVersionUID = 1L;
178+
179+
165180
private final TypeProvider provider;
166181

167182

@@ -194,6 +209,9 @@ public Object invoke(Object proxy, Method method, Object[] args) throws Throwabl
194209
*/
195210
private static class FieldTypeProvider implements TypeProvider {
196211

212+
private static final long serialVersionUID = 1L;
213+
214+
197215
private final String fieldName;
198216

199217
private final Class<?> declaringClass;
@@ -233,6 +251,9 @@ private void readObject(ObjectInputStream inputStream) throws IOException,
233251
*/
234252
private static class MethodParameterTypeProvider implements TypeProvider {
235253

254+
private static final long serialVersionUID = 1L;
255+
256+
236257
private final String methodName;
237258

238259
private final Class<?>[] parameterTypes;
@@ -293,6 +314,9 @@ private void readObject(ObjectInputStream inputStream) throws IOException,
293314
*/
294315
private static class MethodInvokeTypeProvider implements TypeProvider {
295316

317+
private static final long serialVersionUID = 1L;
318+
319+
296320
private final TypeProvider provider;
297321

298322
private final String methodName;

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

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@
5252
import org.springframework.util.MultiValueMap;
5353

5454
import static org.mockito.BDDMockito.*;
55-
5655
import static org.mockito.Mockito.*;
5756
import static org.hamcrest.Matchers.*;
5857
import static org.junit.Assert.*;
@@ -1097,6 +1096,20 @@ public void serialize() throws Exception {
10971096
assertThat(deserializedNone, sameInstance(ResolvableType.NONE));
10981097
}
10991098

1099+
@Test
1100+
public void canResolveVoid() throws Exception {
1101+
ResolvableType type = ResolvableType.forClass(void.class);
1102+
assertThat(type.resolve(), equalTo((Class) void.class));
1103+
}
1104+
1105+
@Test
1106+
public void narrow() throws Exception {
1107+
ResolvableType type = ResolvableType.forField(Fields.class.getField("stringList"));
1108+
ResolvableType narrow = ResolvableType.forType(ArrayList.class, type);
1109+
assertThat(narrow.getGeneric().resolve(), equalTo((Class) String.class));
1110+
}
1111+
1112+
11001113
private ResolvableType testSerialization(ResolvableType type) throws Exception {
11011114
ByteArrayOutputStream bos = new ByteArrayOutputStream();
11021115
ObjectOutputStream oos = new ObjectOutputStream(bos);

0 commit comments

Comments
 (0)