提交 25e29b85 编写于 作者: J Juergen Hoeller 提交者: unknown

GenericTypeResolver defensively calls Class.getGenericSuperclass() and consistently uses Class<?>

Issue: SPR-10559
上级 23737a45
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
......@@ -54,9 +54,9 @@ public class GenericApplicationListenerAdapter implements SmartApplicationListen
@Override
public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
Class typeArg = GenericTypeResolver.resolveTypeArgument(this.delegate.getClass(), ApplicationListener.class);
Class<?> typeArg = GenericTypeResolver.resolveTypeArgument(this.delegate.getClass(), ApplicationListener.class);
if (typeArg == null || typeArg.equals(ApplicationEvent.class)) {
Class targetClass = AopUtils.getTargetClass(this.delegate);
Class<?> targetClass = AopUtils.getTargetClass(this.delegate);
if (targetClass != this.delegate.getClass()) {
typeArg = GenericTypeResolver.resolveTypeArgument(targetClass, ApplicationListener.class);
}
......
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
......@@ -19,6 +19,7 @@ package org.springframework.core;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.MalformedParameterizedTypeException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
......@@ -446,8 +447,13 @@ public abstract class GenericCollectionTypeResolver {
return null;
}
if (clazz.getSuperclass() != null && isIntrospectionCandidate(clazz.getSuperclass())) {
return extractType(clazz.getGenericSuperclass(), source, typeIndex, typeVariableMap, typeIndexesPerLevel,
nestingLevel, currentLevel);
try {
return extractType(clazz.getGenericSuperclass(), source, typeIndex, typeVariableMap,
typeIndexesPerLevel, nestingLevel, currentLevel);
}
catch (MalformedParameterizedTypeException ex) {
// from getGenericSuperclass() - ignore and continue with interface introspection
}
}
Type[] ifcs = clazz.getGenericInterfaces();
if (ifcs != null) {
......
......@@ -18,6 +18,7 @@ package org.springframework.core;
import java.lang.reflect.Array;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.MalformedParameterizedTypeException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
......@@ -74,12 +75,12 @@ public abstract class GenericTypeResolver {
* @param clazz the class to resolve type variables against
* @return the corresponding generic parameter or return type
*/
public static Class<?> resolveParameterType(MethodParameter methodParam, Class clazz) {
public static Class<?> resolveParameterType(MethodParameter methodParam, Class<?> clazz) {
Type genericType = getTargetType(methodParam);
Assert.notNull(clazz, "Class must not be null");
Map<TypeVariable, Type> typeVariableMap = getTypeVariableMap(clazz);
Type rawType = getRawType(genericType, typeVariableMap);
Class result = (rawType instanceof Class ? (Class) rawType : methodParam.getParameterType());
Class<?> result = (rawType instanceof Class ? (Class) rawType : methodParam.getParameterType());
methodParam.setParameterType(result);
methodParam.typeVariableMap = typeVariableMap;
return result;
......@@ -227,7 +228,7 @@ public abstract class GenericTypeResolver {
* @param genericIfc the generic interface or superclass to resolve the type argument from
* @return the resolved type of the argument, or {@code null} if not resolvable
*/
public static Class<?> resolveTypeArgument(Class clazz, Class genericIfc) {
public static Class<?> resolveTypeArgument(Class<?> clazz, Class<?> genericIfc) {
Class[] typeArgs = resolveTypeArguments(clazz, genericIfc);
if (typeArgs == null) {
return null;
......@@ -248,11 +249,11 @@ public abstract class GenericTypeResolver {
* @return the resolved type of each argument, with the array size matching the
* number of actual type arguments, or {@code null} if not resolvable
*/
public static Class[] resolveTypeArguments(Class clazz, Class genericIfc) {
public static Class[] resolveTypeArguments(Class<?> clazz, Class<?> genericIfc) {
return doResolveTypeArguments(clazz, clazz, genericIfc);
}
private static Class[] doResolveTypeArguments(Class ownerClass, Class classToIntrospect, Class genericIfc) {
private static Class[] doResolveTypeArguments(Class<?> ownerClass, Class<?> classToIntrospect, Class<?> genericIfc) {
while (classToIntrospect != null) {
if (genericIfc.isInterface()) {
Type[] ifcs = classToIntrospect.getGenericInterfaces();
......@@ -264,10 +265,15 @@ public abstract class GenericTypeResolver {
}
}
else {
Class[] result = doResolveTypeArguments(
ownerClass, classToIntrospect.getGenericSuperclass(), genericIfc);
if (result != null) {
return result;
try {
Class[] result = doResolveTypeArguments(ownerClass, classToIntrospect.getGenericSuperclass(), genericIfc);
if (result != null) {
return result;
}
}
catch (MalformedParameterizedTypeException ex) {
// from getGenericSuperclass() - return null to skip further superclass traversal
return null;
}
}
classToIntrospect = classToIntrospect.getSuperclass();
......@@ -275,7 +281,7 @@ public abstract class GenericTypeResolver {
return null;
}
private static Class[] doResolveTypeArguments(Class ownerClass, Type ifc, Class genericIfc) {
private static Class[] doResolveTypeArguments(Class<?> ownerClass, Type ifc, Class<?> genericIfc) {
if (ifc instanceof ParameterizedType) {
ParameterizedType paramIfc = (ParameterizedType) ifc;
Type rawType = paramIfc.getRawType();
......@@ -301,7 +307,7 @@ public abstract class GenericTypeResolver {
/**
* Extract a class instance from given Type.
*/
private static Class extractClass(Class ownerClass, Type arg) {
private static Class<?> extractClass(Class<?> ownerClass, Type arg) {
if (arg instanceof ParameterizedType) {
return extractClass(ownerClass, ((ParameterizedType) arg).getRawType());
}
......@@ -368,7 +374,7 @@ public abstract class GenericTypeResolver {
* {@link Class concrete classes} for the specified {@link Class}. Searches
* all super types, enclosing types and interfaces.
*/
public static Map<TypeVariable, Type> getTypeVariableMap(Class clazz) {
public static Map<TypeVariable, Type> getTypeVariableMap(Class<?> clazz) {
Map<TypeVariable, Type> typeVariableMap = typeVariableCache.get(clazz);
if (typeVariableMap == null) {
......@@ -377,28 +383,37 @@ public abstract class GenericTypeResolver {
// interfaces
extractTypeVariablesFromGenericInterfaces(clazz.getGenericInterfaces(), typeVariableMap);
// super class
Type genericType = clazz.getGenericSuperclass();
Class type = clazz.getSuperclass();
while (type != null && !Object.class.equals(type)) {
if (genericType instanceof ParameterizedType) {
ParameterizedType pt = (ParameterizedType) genericType;
populateTypeMapFromParameterizedType(pt, typeVariableMap);
try {
// super class
Class<?> type = clazz;
while (type.getSuperclass() != null && !Object.class.equals(type.getSuperclass())) {
Type genericType = type.getGenericSuperclass();
if (genericType instanceof ParameterizedType) {
ParameterizedType pt = (ParameterizedType) genericType;
populateTypeMapFromParameterizedType(pt, typeVariableMap);
}
extractTypeVariablesFromGenericInterfaces(type.getSuperclass().getGenericInterfaces(), typeVariableMap);
type = type.getSuperclass();
}
extractTypeVariablesFromGenericInterfaces(type.getGenericInterfaces(), typeVariableMap);
genericType = type.getGenericSuperclass();
type = type.getSuperclass();
}
catch (MalformedParameterizedTypeException ex) {
// from getGenericSuperclass() - ignore and continue with member class check
}
// enclosing class
type = clazz;
while (type.isMemberClass()) {
genericType = type.getGenericSuperclass();
if (genericType instanceof ParameterizedType) {
ParameterizedType pt = (ParameterizedType) genericType;
populateTypeMapFromParameterizedType(pt, typeVariableMap);
try {
// enclosing class
Class<?> type = clazz;
while (type.isMemberClass()) {
Type genericType = type.getGenericSuperclass();
if (genericType instanceof ParameterizedType) {
ParameterizedType pt = (ParameterizedType) genericType;
populateTypeMapFromParameterizedType(pt, typeVariableMap);
}
type = type.getEnclosingClass();
}
type = type.getEnclosingClass();
}
catch (MalformedParameterizedTypeException ex) {
// from getGenericSuperclass() - ignore and preserve previously accumulated type variables
}
typeVariableCache.put(clazz, typeVariableMap);
......
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
......@@ -24,7 +24,7 @@ import org.springframework.util.Assert;
/**
* The purpose of this class is to enable capturing and passing a generic
* {@link Type}. In order to capture the generic type and retain it at runtime,
* you need to create a sub-class as follows:
* you need to create a subclass as follows:
*
* <pre class="code">
* ParameterizedTypeReference&lt;List&lt;String&gt;&gt; typeRef = new ParameterizedTypeReference&lt;List&lt;String&gt;&gt;() {};
......@@ -37,54 +37,31 @@ import org.springframework.util.Assert;
* @author Arjen Poutsma
* @author Rossen Stoyanchev
* @since 3.2
*
* @see <a href="http://gafter.blogspot.nl/2006/12/super-type-tokens.html">Neal Gafter on Super Type Tokens</a>
*/
public abstract class ParameterizedTypeReference<T> {
private final Type type;
protected ParameterizedTypeReference() {
Class<?> parameterizedTypeReferenceSubClass = findParameterizedTypeReferenceSubClass(getClass());
Type type = parameterizedTypeReferenceSubClass.getGenericSuperclass();
protected ParameterizedTypeReference() {
Class<?> parameterizedTypeReferenceSubclass = findParameterizedTypeReferenceSubclass(getClass());
Type type = parameterizedTypeReferenceSubclass.getGenericSuperclass();
Assert.isInstanceOf(ParameterizedType.class, type);
ParameterizedType parameterizedType = (ParameterizedType) type;
Assert.isTrue(parameterizedType.getActualTypeArguments().length == 1);
this.type = parameterizedType.getActualTypeArguments()[0];
}
private static Class<?> findParameterizedTypeReferenceSubClass(Class<?> child) {
Class<?> parent = child.getSuperclass();
if (Object.class.equals(parent)) {
throw new IllegalStateException("Expected ParameterizedTypeReference superclass");
}
else if (ParameterizedTypeReference.class.equals(parent)) {
return child;
}
else {
return findParameterizedTypeReferenceSubClass(parent);
}
}
public Type getType() {
return this.type;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o instanceof ParameterizedTypeReference) {
ParameterizedTypeReference<?> other = (ParameterizedTypeReference<?>) o;
return this.type.equals(other.type);
}
return false;
public boolean equals(Object obj) {
return (this == obj || (obj instanceof ParameterizedTypeReference &&
this.type.equals(((ParameterizedTypeReference) obj).type)));
}
@Override
......@@ -96,4 +73,19 @@ public abstract class ParameterizedTypeReference<T> {
public String toString() {
return "ParameterizedTypeReference<" + this.type + ">";
}
private static Class<?> findParameterizedTypeReferenceSubclass(Class<?> child) {
Class<?> parent = child.getSuperclass();
if (Object.class.equals(parent)) {
throw new IllegalStateException("Expected ParameterizedTypeReference superclass");
}
else if (ParameterizedTypeReference.class.equals(parent)) {
return child;
}
else {
return findParameterizedTypeReferenceSubclass(parent);
}
}
}
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2013 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.
......@@ -20,16 +20,17 @@ import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* Test fixture for {@link ParameterizedTypeReference}.
*
* @author Arjen Poutsma
* @author Rossen Stoyanchev
*/
public class ParameterizedTypeReferenceTest {
public class ParameterizedTypeReferenceTests {
@Test
public void map() throws NoSuchMethodException {
......@@ -58,4 +59,5 @@ public class ParameterizedTypeReferenceTest {
public static List<String> listMethod() {
return null;
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册