Skip to content

Commit 25e29b8

Browse files
jhoellerunknown
authored and
unknown
committed
GenericTypeResolver defensively calls Class.getGenericSuperclass() and consistently uses Class<?>
Issue: SPR-10559
1 parent 23737a4 commit 25e29b8

File tree

5 files changed

+85
-70
lines changed

5 files changed

+85
-70
lines changed

spring-context/src/main/java/org/springframework/context/event/GenericApplicationListenerAdapter.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2012 the original author or authors.
2+
* Copyright 2002-2013 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.
@@ -54,9 +54,9 @@ public void onApplicationEvent(ApplicationEvent event) {
5454

5555
@Override
5656
public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
57-
Class typeArg = GenericTypeResolver.resolveTypeArgument(this.delegate.getClass(), ApplicationListener.class);
57+
Class<?> typeArg = GenericTypeResolver.resolveTypeArgument(this.delegate.getClass(), ApplicationListener.class);
5858
if (typeArg == null || typeArg.equals(ApplicationEvent.class)) {
59-
Class targetClass = AopUtils.getTargetClass(this.delegate);
59+
Class<?> targetClass = AopUtils.getTargetClass(this.delegate);
6060
if (targetClass != this.delegate.getClass()) {
6161
typeArg = GenericTypeResolver.resolveTypeArgument(targetClass, ApplicationListener.class);
6262
}

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

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2012 the original author or authors.
2+
* Copyright 2002-2013 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.
@@ -19,6 +19,7 @@
1919
import java.lang.reflect.Array;
2020
import java.lang.reflect.Field;
2121
import java.lang.reflect.GenericArrayType;
22+
import java.lang.reflect.MalformedParameterizedTypeException;
2223
import java.lang.reflect.Method;
2324
import java.lang.reflect.ParameterizedType;
2425
import java.lang.reflect.Type;
@@ -446,8 +447,13 @@ private static Class<?> extractTypeFromClass(Class<?> clazz, Class<?> source, in
446447
return null;
447448
}
448449
if (clazz.getSuperclass() != null && isIntrospectionCandidate(clazz.getSuperclass())) {
449-
return extractType(clazz.getGenericSuperclass(), source, typeIndex, typeVariableMap, typeIndexesPerLevel,
450-
nestingLevel, currentLevel);
450+
try {
451+
return extractType(clazz.getGenericSuperclass(), source, typeIndex, typeVariableMap,
452+
typeIndexesPerLevel, nestingLevel, currentLevel);
453+
}
454+
catch (MalformedParameterizedTypeException ex) {
455+
// from getGenericSuperclass() - ignore and continue with interface introspection
456+
}
451457
}
452458
Type[] ifcs = clazz.getGenericInterfaces();
453459
if (ifcs != null) {

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

Lines changed: 45 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import java.lang.reflect.Array;
2020
import java.lang.reflect.GenericArrayType;
21+
import java.lang.reflect.MalformedParameterizedTypeException;
2122
import java.lang.reflect.Method;
2223
import java.lang.reflect.ParameterizedType;
2324
import java.lang.reflect.Type;
@@ -74,12 +75,12 @@ public static Type getTargetType(MethodParameter methodParam) {
7475
* @param clazz the class to resolve type variables against
7576
* @return the corresponding generic parameter or return type
7677
*/
77-
public static Class<?> resolveParameterType(MethodParameter methodParam, Class clazz) {
78+
public static Class<?> resolveParameterType(MethodParameter methodParam, Class<?> clazz) {
7879
Type genericType = getTargetType(methodParam);
7980
Assert.notNull(clazz, "Class must not be null");
8081
Map<TypeVariable, Type> typeVariableMap = getTypeVariableMap(clazz);
8182
Type rawType = getRawType(genericType, typeVariableMap);
82-
Class result = (rawType instanceof Class ? (Class) rawType : methodParam.getParameterType());
83+
Class<?> result = (rawType instanceof Class ? (Class) rawType : methodParam.getParameterType());
8384
methodParam.setParameterType(result);
8485
methodParam.typeVariableMap = typeVariableMap;
8586
return result;
@@ -227,7 +228,7 @@ public static Class<?> resolveReturnTypeArgument(Method method, Class<?> generic
227228
* @param genericIfc the generic interface or superclass to resolve the type argument from
228229
* @return the resolved type of the argument, or {@code null} if not resolvable
229230
*/
230-
public static Class<?> resolveTypeArgument(Class clazz, Class genericIfc) {
231+
public static Class<?> resolveTypeArgument(Class<?> clazz, Class<?> genericIfc) {
231232
Class[] typeArgs = resolveTypeArguments(clazz, genericIfc);
232233
if (typeArgs == null) {
233234
return null;
@@ -248,11 +249,11 @@ public static Class<?> resolveTypeArgument(Class clazz, Class genericIfc) {
248249
* @return the resolved type of each argument, with the array size matching the
249250
* number of actual type arguments, or {@code null} if not resolvable
250251
*/
251-
public static Class[] resolveTypeArguments(Class clazz, Class genericIfc) {
252+
public static Class[] resolveTypeArguments(Class<?> clazz, Class<?> genericIfc) {
252253
return doResolveTypeArguments(clazz, clazz, genericIfc);
253254
}
254255

255-
private static Class[] doResolveTypeArguments(Class ownerClass, Class classToIntrospect, Class genericIfc) {
256+
private static Class[] doResolveTypeArguments(Class<?> ownerClass, Class<?> classToIntrospect, Class<?> genericIfc) {
256257
while (classToIntrospect != null) {
257258
if (genericIfc.isInterface()) {
258259
Type[] ifcs = classToIntrospect.getGenericInterfaces();
@@ -264,18 +265,23 @@ private static Class[] doResolveTypeArguments(Class ownerClass, Class classToInt
264265
}
265266
}
266267
else {
267-
Class[] result = doResolveTypeArguments(
268-
ownerClass, classToIntrospect.getGenericSuperclass(), genericIfc);
269-
if (result != null) {
270-
return result;
268+
try {
269+
Class[] result = doResolveTypeArguments(ownerClass, classToIntrospect.getGenericSuperclass(), genericIfc);
270+
if (result != null) {
271+
return result;
272+
}
273+
}
274+
catch (MalformedParameterizedTypeException ex) {
275+
// from getGenericSuperclass() - return null to skip further superclass traversal
276+
return null;
271277
}
272278
}
273279
classToIntrospect = classToIntrospect.getSuperclass();
274280
}
275281
return null;
276282
}
277283

278-
private static Class[] doResolveTypeArguments(Class ownerClass, Type ifc, Class genericIfc) {
284+
private static Class[] doResolveTypeArguments(Class<?> ownerClass, Type ifc, Class<?> genericIfc) {
279285
if (ifc instanceof ParameterizedType) {
280286
ParameterizedType paramIfc = (ParameterizedType) ifc;
281287
Type rawType = paramIfc.getRawType();
@@ -301,7 +307,7 @@ else if (ifc != null && genericIfc.isAssignableFrom((Class) ifc)) {
301307
/**
302308
* Extract a class instance from given Type.
303309
*/
304-
private static Class extractClass(Class ownerClass, Type arg) {
310+
private static Class<?> extractClass(Class<?> ownerClass, Type arg) {
305311
if (arg instanceof ParameterizedType) {
306312
return extractClass(ownerClass, ((ParameterizedType) arg).getRawType());
307313
}
@@ -368,7 +374,7 @@ static Type getRawType(Type genericType, Map<TypeVariable, Type> typeVariableMap
368374
* {@link Class concrete classes} for the specified {@link Class}. Searches
369375
* all super types, enclosing types and interfaces.
370376
*/
371-
public static Map<TypeVariable, Type> getTypeVariableMap(Class clazz) {
377+
public static Map<TypeVariable, Type> getTypeVariableMap(Class<?> clazz) {
372378
Map<TypeVariable, Type> typeVariableMap = typeVariableCache.get(clazz);
373379

374380
if (typeVariableMap == null) {
@@ -377,28 +383,37 @@ public static Map<TypeVariable, Type> getTypeVariableMap(Class clazz) {
377383
// interfaces
378384
extractTypeVariablesFromGenericInterfaces(clazz.getGenericInterfaces(), typeVariableMap);
379385

380-
// super class
381-
Type genericType = clazz.getGenericSuperclass();
382-
Class type = clazz.getSuperclass();
383-
while (type != null && !Object.class.equals(type)) {
384-
if (genericType instanceof ParameterizedType) {
385-
ParameterizedType pt = (ParameterizedType) genericType;
386-
populateTypeMapFromParameterizedType(pt, typeVariableMap);
386+
try {
387+
// super class
388+
Class<?> type = clazz;
389+
while (type.getSuperclass() != null && !Object.class.equals(type.getSuperclass())) {
390+
Type genericType = type.getGenericSuperclass();
391+
if (genericType instanceof ParameterizedType) {
392+
ParameterizedType pt = (ParameterizedType) genericType;
393+
populateTypeMapFromParameterizedType(pt, typeVariableMap);
394+
}
395+
extractTypeVariablesFromGenericInterfaces(type.getSuperclass().getGenericInterfaces(), typeVariableMap);
396+
type = type.getSuperclass();
387397
}
388-
extractTypeVariablesFromGenericInterfaces(type.getGenericInterfaces(), typeVariableMap);
389-
genericType = type.getGenericSuperclass();
390-
type = type.getSuperclass();
398+
}
399+
catch (MalformedParameterizedTypeException ex) {
400+
// from getGenericSuperclass() - ignore and continue with member class check
391401
}
392402

393-
// enclosing class
394-
type = clazz;
395-
while (type.isMemberClass()) {
396-
genericType = type.getGenericSuperclass();
397-
if (genericType instanceof ParameterizedType) {
398-
ParameterizedType pt = (ParameterizedType) genericType;
399-
populateTypeMapFromParameterizedType(pt, typeVariableMap);
403+
try {
404+
// enclosing class
405+
Class<?> type = clazz;
406+
while (type.isMemberClass()) {
407+
Type genericType = type.getGenericSuperclass();
408+
if (genericType instanceof ParameterizedType) {
409+
ParameterizedType pt = (ParameterizedType) genericType;
410+
populateTypeMapFromParameterizedType(pt, typeVariableMap);
411+
}
412+
type = type.getEnclosingClass();
400413
}
401-
type = type.getEnclosingClass();
414+
}
415+
catch (MalformedParameterizedTypeException ex) {
416+
// from getGenericSuperclass() - ignore and preserve previously accumulated type variables
402417
}
403418

404419
typeVariableCache.put(clazz, typeVariableMap);
Lines changed: 23 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2012 the original author or authors.
2+
* Copyright 2002-2013 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.
@@ -24,7 +24,7 @@
2424
/**
2525
* The purpose of this class is to enable capturing and passing a generic
2626
* {@link Type}. In order to capture the generic type and retain it at runtime,
27-
* you need to create a sub-class as follows:
27+
* you need to create a subclass as follows:
2828
*
2929
* <pre class="code">
3030
* ParameterizedTypeReference&lt;List&lt;String&gt;&gt; typeRef = new ParameterizedTypeReference&lt;List&lt;String&gt;&gt;() {};
@@ -37,54 +37,31 @@
3737
* @author Arjen Poutsma
3838
* @author Rossen Stoyanchev
3939
* @since 3.2
40-
*
4140
* @see <a href="http://gafter.blogspot.nl/2006/12/super-type-tokens.html">Neal Gafter on Super Type Tokens</a>
4241
*/
4342
public abstract class ParameterizedTypeReference<T> {
4443

4544
private final Type type;
4645

47-
protected ParameterizedTypeReference() {
48-
Class<?> parameterizedTypeReferenceSubClass = findParameterizedTypeReferenceSubClass(getClass());
4946

50-
Type type = parameterizedTypeReferenceSubClass.getGenericSuperclass();
47+
protected ParameterizedTypeReference() {
48+
Class<?> parameterizedTypeReferenceSubclass = findParameterizedTypeReferenceSubclass(getClass());
49+
Type type = parameterizedTypeReferenceSubclass.getGenericSuperclass();
5150
Assert.isInstanceOf(ParameterizedType.class, type);
52-
5351
ParameterizedType parameterizedType = (ParameterizedType) type;
5452
Assert.isTrue(parameterizedType.getActualTypeArguments().length == 1);
55-
5653
this.type = parameterizedType.getActualTypeArguments()[0];
5754
}
5855

59-
private static Class<?> findParameterizedTypeReferenceSubClass(Class<?> child) {
60-
61-
Class<?> parent = child.getSuperclass();
62-
63-
if (Object.class.equals(parent)) {
64-
throw new IllegalStateException("Expected ParameterizedTypeReference superclass");
65-
}
66-
else if (ParameterizedTypeReference.class.equals(parent)) {
67-
return child;
68-
}
69-
else {
70-
return findParameterizedTypeReferenceSubClass(parent);
71-
}
72-
}
7356

7457
public Type getType() {
7558
return this.type;
7659
}
7760

7861
@Override
79-
public boolean equals(Object o) {
80-
if (this == o) {
81-
return true;
82-
}
83-
if (o instanceof ParameterizedTypeReference) {
84-
ParameterizedTypeReference<?> other = (ParameterizedTypeReference<?>) o;
85-
return this.type.equals(other.type);
86-
}
87-
return false;
62+
public boolean equals(Object obj) {
63+
return (this == obj || (obj instanceof ParameterizedTypeReference &&
64+
this.type.equals(((ParameterizedTypeReference) obj).type)));
8865
}
8966

9067
@Override
@@ -96,4 +73,19 @@ public int hashCode() {
9673
public String toString() {
9774
return "ParameterizedTypeReference<" + this.type + ">";
9875
}
76+
77+
78+
private static Class<?> findParameterizedTypeReferenceSubclass(Class<?> child) {
79+
Class<?> parent = child.getSuperclass();
80+
if (Object.class.equals(parent)) {
81+
throw new IllegalStateException("Expected ParameterizedTypeReference superclass");
82+
}
83+
else if (ParameterizedTypeReference.class.equals(parent)) {
84+
return child;
85+
}
86+
else {
87+
return findParameterizedTypeReferenceSubclass(parent);
88+
}
89+
}
90+
9991
}

spring-core/src/test/java/org/springframework/core/ParameterizedTypeReferenceTest.java renamed to spring-core/src/test/java/org/springframework/core/ParameterizedTypeReferenceTests.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2012 the original author or authors.
2+
* Copyright 2002-2013 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.
@@ -20,16 +20,17 @@
2020
import java.util.List;
2121
import java.util.Map;
2222

23-
import static org.junit.Assert.assertEquals;
2423
import org.junit.Test;
2524

25+
import static org.junit.Assert.*;
26+
2627
/**
2728
* Test fixture for {@link ParameterizedTypeReference}.
2829
*
2930
* @author Arjen Poutsma
3031
* @author Rossen Stoyanchev
3132
*/
32-
public class ParameterizedTypeReferenceTest {
33+
public class ParameterizedTypeReferenceTests {
3334

3435
@Test
3536
public void map() throws NoSuchMethodException {
@@ -58,4 +59,5 @@ public static Map<Object, String> mapMethod() {
5859
public static List<String> listMethod() {
5960
return null;
6061
}
62+
6163
}

0 commit comments

Comments
 (0)