diff --git a/spring-context/src/main/java/org/springframework/context/event/GenericApplicationListenerAdapter.java b/spring-context/src/main/java/org/springframework/context/event/GenericApplicationListenerAdapter.java index 8c7f6e6d57..bc7e2660ac 100644 --- a/spring-context/src/main/java/org/springframework/context/event/GenericApplicationListenerAdapter.java +++ b/spring-context/src/main/java/org/springframework/context/event/GenericApplicationListenerAdapter.java @@ -1,5 +1,5 @@ /* - * 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 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); } diff --git a/spring-core/src/main/java/org/springframework/core/GenericCollectionTypeResolver.java b/spring-core/src/main/java/org/springframework/core/GenericCollectionTypeResolver.java index c3b05e35fe..8b4c280a97 100644 --- a/spring-core/src/main/java/org/springframework/core/GenericCollectionTypeResolver.java +++ b/spring-core/src/main/java/org/springframework/core/GenericCollectionTypeResolver.java @@ -1,5 +1,5 @@ /* - * 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) { diff --git a/spring-core/src/main/java/org/springframework/core/GenericTypeResolver.java b/spring-core/src/main/java/org/springframework/core/GenericTypeResolver.java index 3ddd294236..b8dc32c18b 100644 --- a/spring-core/src/main/java/org/springframework/core/GenericTypeResolver.java +++ b/spring-core/src/main/java/org/springframework/core/GenericTypeResolver.java @@ -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 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 getTypeVariableMap(Class clazz) { + public static Map getTypeVariableMap(Class clazz) { Map 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); diff --git a/spring-core/src/main/java/org/springframework/core/ParameterizedTypeReference.java b/spring-core/src/main/java/org/springframework/core/ParameterizedTypeReference.java index 88204140f3..d7165b3ee3 100644 --- a/spring-core/src/main/java/org/springframework/core/ParameterizedTypeReference.java +++ b/spring-core/src/main/java/org/springframework/core/ParameterizedTypeReference.java @@ -1,5 +1,5 @@ /* - * 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: * *
  * ParameterizedTypeReference<List<String>> typeRef = new ParameterizedTypeReference<List<String>>() {};
@@ -37,54 +37,31 @@ import org.springframework.util.Assert;
  * @author Arjen Poutsma
  * @author Rossen Stoyanchev
  * @since 3.2
- *
  * @see Neal Gafter on Super Type Tokens
  */
 public abstract class ParameterizedTypeReference {
 
 	private final Type type;
 
+
 	protected ParameterizedTypeReference() {
-		Class parameterizedTypeReferenceSubClass = findParameterizedTypeReferenceSubClass(getClass());
-
-		Type type = parameterizedTypeReferenceSubClass.getGenericSuperclass();
+		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 {
 	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);
+		}
+	}
+
 }
diff --git a/spring-core/src/test/java/org/springframework/core/ParameterizedTypeReferenceTest.java b/spring-core/src/test/java/org/springframework/core/ParameterizedTypeReferenceTests.java
similarity index 92%
rename from spring-core/src/test/java/org/springframework/core/ParameterizedTypeReferenceTest.java
rename to spring-core/src/test/java/org/springframework/core/ParameterizedTypeReferenceTests.java
index 7162d9ad93..56060b2468 100644
--- a/spring-core/src/test/java/org/springframework/core/ParameterizedTypeReferenceTest.java
+++ b/spring-core/src/test/java/org/springframework/core/ParameterizedTypeReferenceTests.java
@@ -1,5 +1,5 @@
 /*
- * 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 listMethod() {
 		return null;
 	}
+
 }