|
|
|
|
@ -1,5 +1,5 @@
@@ -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. |
|
|
|
|
@ -21,10 +21,12 @@ import java.lang.reflect.Type;
@@ -21,10 +21,12 @@ import java.lang.reflect.Type;
|
|
|
|
|
import java.lang.reflect.TypeVariable; |
|
|
|
|
import java.util.Collection; |
|
|
|
|
import java.util.HashMap; |
|
|
|
|
import java.util.List; |
|
|
|
|
import java.util.Map; |
|
|
|
|
|
|
|
|
|
import org.junit.Test; |
|
|
|
|
|
|
|
|
|
import static org.hamcrest.Matchers.*; |
|
|
|
|
import static org.junit.Assert.*; |
|
|
|
|
import static org.springframework.core.GenericTypeResolver.*; |
|
|
|
|
import static org.springframework.util.ReflectionUtils.*; |
|
|
|
|
@ -63,28 +65,33 @@ public class GenericTypeResolverTests {
@@ -63,28 +65,33 @@ public class GenericTypeResolverTests {
|
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
public void methodReturnTypes() { |
|
|
|
|
assertEquals(Integer.class, resolveReturnTypeArgument(findMethod(MyTypeWithMethods.class, "integer"), MyInterfaceType.class)); |
|
|
|
|
assertEquals(String.class, resolveReturnTypeArgument(findMethod(MyTypeWithMethods.class, "string"), MyInterfaceType.class)); |
|
|
|
|
assertEquals(Integer.class, |
|
|
|
|
resolveReturnTypeArgument(findMethod(MyTypeWithMethods.class, "integer"), MyInterfaceType.class)); |
|
|
|
|
assertEquals(String.class, |
|
|
|
|
resolveReturnTypeArgument(findMethod(MyTypeWithMethods.class, "string"), MyInterfaceType.class)); |
|
|
|
|
assertEquals(null, resolveReturnTypeArgument(findMethod(MyTypeWithMethods.class, "raw"), MyInterfaceType.class)); |
|
|
|
|
assertEquals(null, resolveReturnTypeArgument(findMethod(MyTypeWithMethods.class, "object"), MyInterfaceType.class)); |
|
|
|
|
assertEquals(null, |
|
|
|
|
resolveReturnTypeArgument(findMethod(MyTypeWithMethods.class, "object"), MyInterfaceType.class)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
public void testResolveType() { |
|
|
|
|
Method intMessageMethod = findMethod(MyTypeWithMethods.class, "readIntegerInputMessage", MyInterfaceType.class); |
|
|
|
|
MethodParameter intMessageMethodParam = new MethodParameter(intMessageMethod, 0); |
|
|
|
|
assertEquals(MyInterfaceType.class, |
|
|
|
|
resolveType(intMessageMethodParam.getGenericParameterType(), new HashMap<TypeVariable, Type>())); |
|
|
|
|
|
|
|
|
|
Method intArrMessageMethod = findMethod(MyTypeWithMethods.class, "readIntegerArrayInputMessage", MyInterfaceType[].class); |
|
|
|
|
MethodParameter intArrMessageMethodParam = new MethodParameter(intArrMessageMethod, 0); |
|
|
|
|
assertEquals(MyInterfaceType[].class, |
|
|
|
|
resolveType(intArrMessageMethodParam.getGenericParameterType(), new HashMap<TypeVariable, Type>())); |
|
|
|
|
|
|
|
|
|
Method genericArrMessageMethod = findMethod(MySimpleTypeWithMethods.class, "readGenericArrayInputMessage", Object[].class); |
|
|
|
|
MethodParameter genericArrMessageMethodParam = new MethodParameter(genericArrMessageMethod, 0); |
|
|
|
|
Map<TypeVariable, Type> varMap = getTypeVariableMap(MySimpleTypeWithMethods.class); |
|
|
|
|
assertEquals(Integer[].class, resolveType(genericArrMessageMethodParam.getGenericParameterType(), varMap)); |
|
|
|
|
Method intMessageMethod = findMethod(MyTypeWithMethods.class, "readIntegerInputMessage", MyInterfaceType.class); |
|
|
|
|
MethodParameter intMessageMethodParam = new MethodParameter(intMessageMethod, 0); |
|
|
|
|
assertEquals(MyInterfaceType.class, |
|
|
|
|
resolveType(intMessageMethodParam.getGenericParameterType(), new HashMap<TypeVariable, Type>())); |
|
|
|
|
|
|
|
|
|
Method intArrMessageMethod = findMethod(MyTypeWithMethods.class, "readIntegerArrayInputMessage", |
|
|
|
|
MyInterfaceType[].class); |
|
|
|
|
MethodParameter intArrMessageMethodParam = new MethodParameter(intArrMessageMethod, 0); |
|
|
|
|
assertEquals(MyInterfaceType[].class, |
|
|
|
|
resolveType(intArrMessageMethodParam.getGenericParameterType(), new HashMap<TypeVariable, Type>())); |
|
|
|
|
|
|
|
|
|
Method genericArrMessageMethod = findMethod(MySimpleTypeWithMethods.class, "readGenericArrayInputMessage", |
|
|
|
|
Object[].class); |
|
|
|
|
MethodParameter genericArrMessageMethodParam = new MethodParameter(genericArrMessageMethod, 0); |
|
|
|
|
Map<TypeVariable, Type> varMap = getTypeVariableMap(MySimpleTypeWithMethods.class); |
|
|
|
|
assertEquals(Integer[].class, resolveType(genericArrMessageMethodParam.getGenericParameterType(), varMap)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
@ -92,7 +99,76 @@ public class GenericTypeResolverTests {
@@ -92,7 +99,76 @@ public class GenericTypeResolverTests {
|
|
|
|
|
assertEquals(B.class, resolveTypeArgument(TestImpl.class, ITest.class)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
public void testGetTypeVariableMap() throws Exception { |
|
|
|
|
Map<TypeVariable, Type> map; |
|
|
|
|
|
|
|
|
|
map = GenericTypeResolver.getTypeVariableMap(MySimpleInterfaceType.class); |
|
|
|
|
assertThat(map.toString(), equalTo("{T=class java.lang.String}")); |
|
|
|
|
|
|
|
|
|
map = GenericTypeResolver.getTypeVariableMap(MyCollectionInterfaceType.class); |
|
|
|
|
assertThat(map.toString(), equalTo("{T=java.util.Collection<java.lang.String>}")); |
|
|
|
|
|
|
|
|
|
map = GenericTypeResolver.getTypeVariableMap(MyCollectionSuperclassType.class); |
|
|
|
|
assertThat(map.toString(), equalTo("{T=java.util.Collection<java.lang.String>}")); |
|
|
|
|
|
|
|
|
|
map = GenericTypeResolver.getTypeVariableMap(MySimpleTypeWithMethods.class); |
|
|
|
|
assertThat(map.toString(), equalTo("{T=class java.lang.Integer}")); |
|
|
|
|
|
|
|
|
|
map = GenericTypeResolver.getTypeVariableMap(TopLevelClass.class); |
|
|
|
|
assertThat(map.toString(), equalTo("{}")); |
|
|
|
|
|
|
|
|
|
map = GenericTypeResolver.getTypeVariableMap(TypedTopLevelClass.class); |
|
|
|
|
assertThat(map.toString(), equalTo("{T=class java.lang.Integer}")); |
|
|
|
|
|
|
|
|
|
map = GenericTypeResolver.getTypeVariableMap(TypedTopLevelClass.TypedNested.class); |
|
|
|
|
assertThat(map.size(), equalTo(2)); |
|
|
|
|
Type t = null; |
|
|
|
|
Type x = null; |
|
|
|
|
for (Map.Entry<TypeVariable, Type> entry : map.entrySet()) { |
|
|
|
|
if(entry.getKey().toString().equals("T")) { |
|
|
|
|
t = entry.getValue(); |
|
|
|
|
} |
|
|
|
|
else { |
|
|
|
|
x = entry.getValue(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
assertThat(t, equalTo((Type) Integer.class)); |
|
|
|
|
assertThat(x, equalTo((Type) Long.class)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
public void getGenericsCannotBeResolved() throws Exception { |
|
|
|
|
// SPR-11030
|
|
|
|
|
Class<?>[] resolved = GenericTypeResolver.resolveTypeArguments(List.class, Iterable.class); |
|
|
|
|
// Note: to be changed to return null in Spring 4.0
|
|
|
|
|
assertThat(resolved, equalTo(new Class[] {Object.class})); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
public void getRawMapTypeCannotBeResolved() throws Exception { |
|
|
|
|
// SPR-11052
|
|
|
|
|
Class<?>[] resolved = GenericTypeResolver.resolveTypeArguments(Map.class, Map.class); |
|
|
|
|
assertNull(resolved); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
public void getGenericsOnArrayFromParamCannotBeResolved() throws Exception { |
|
|
|
|
// SPR-11044
|
|
|
|
|
MethodParameter methodParameter = MethodParameter.forMethodOrConstructor( |
|
|
|
|
WithArrayBase.class.getDeclaredMethod("array", Object[].class), 0); |
|
|
|
|
Class<?> resolved = GenericTypeResolver.resolveParameterType(methodParameter, WithArray.class); |
|
|
|
|
assertThat(resolved, equalTo((Class) Object[].class)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
public void getGenericsOnArrayFromReturnCannotBeResolved() throws Exception { |
|
|
|
|
// SPR-11044
|
|
|
|
|
Class<?> resolved = GenericTypeResolver.resolveReturnType( |
|
|
|
|
WithArrayBase.class.getDeclaredMethod("array", Object[].class), |
|
|
|
|
WithArray.class); |
|
|
|
|
assertThat(resolved, equalTo((Class) Object[].class)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public interface MyInterfaceType<T> { |
|
|
|
|
} |
|
|
|
|
@ -113,26 +189,44 @@ public class GenericTypeResolverTests {
@@ -113,26 +189,44 @@ public class GenericTypeResolverTests {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public static class MyTypeWithMethods<T> { |
|
|
|
|
public MyInterfaceType<Integer> integer() { return null; } |
|
|
|
|
public MySimpleInterfaceType string() { return null; } |
|
|
|
|
public Object object() { return null; } |
|
|
|
|
|
|
|
|
|
public MyInterfaceType<Integer> integer() { |
|
|
|
|
return null; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public MySimpleInterfaceType string() { |
|
|
|
|
return null; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public Object object() { |
|
|
|
|
return null; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@SuppressWarnings("rawtypes") |
|
|
|
|
public MyInterfaceType raw() { return null; } |
|
|
|
|
public String notParameterized() { return null; } |
|
|
|
|
public String notParameterizedWithArguments(Integer x, Boolean b) { return null; } |
|
|
|
|
public MyInterfaceType raw() { |
|
|
|
|
return null; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public String notParameterized() { |
|
|
|
|
return null; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public String notParameterizedWithArguments(Integer x, Boolean b) { |
|
|
|
|
return null; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Simulates a factory method that wraps the supplied object in a proxy |
|
|
|
|
* of the same type. |
|
|
|
|
* Simulates a factory method that wraps the supplied object in a proxy of the |
|
|
|
|
* same type. |
|
|
|
|
*/ |
|
|
|
|
public static <T> T createProxy(T object) { |
|
|
|
|
return null; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Similar to {@link #createProxy(Object)} but adds an additional argument |
|
|
|
|
* before the argument of type {@code T}. Note that they may potentially |
|
|
|
|
* be of the same time when invoked! |
|
|
|
|
* Similar to {@link #createProxy(Object)} but adds an additional argument before |
|
|
|
|
* the argument of type {@code T}. Note that they may potentially be of the same |
|
|
|
|
* time when invoked! |
|
|
|
|
*/ |
|
|
|
|
public static <T> T createNamedProxy(String name, T object) { |
|
|
|
|
return null; |
|
|
|
|
@ -146,8 +240,8 @@ public class GenericTypeResolverTests {
@@ -146,8 +240,8 @@ public class GenericTypeResolverTests {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Similar to {@link #createMock(Class)} but adds an additional method |
|
|
|
|
* argument before the parameterized argument. |
|
|
|
|
* Similar to {@link #createMock(Class)} but adds an additional method argument |
|
|
|
|
* before the parameterized argument. |
|
|
|
|
*/ |
|
|
|
|
public static <T> T createNamedMock(String name, Class<T> toMock) { |
|
|
|
|
return null; |
|
|
|
|
@ -162,8 +256,8 @@ public class GenericTypeResolverTests {
@@ -162,8 +256,8 @@ public class GenericTypeResolverTests {
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Extract some value of the type supported by the interface (i.e., by |
|
|
|
|
* a concrete, non-generic implementation of the interface). |
|
|
|
|
* Extract some value of the type supported by the interface (i.e., by a concrete, |
|
|
|
|
* non-generic implementation of the interface). |
|
|
|
|
*/ |
|
|
|
|
public static <T> T extractValueFrom(MyInterfaceType<T> myInterfaceType) { |
|
|
|
|
return null; |
|
|
|
|
@ -201,4 +295,22 @@ public class GenericTypeResolverTests {
@@ -201,4 +295,22 @@ public class GenericTypeResolverTests {
|
|
|
|
|
class TestImpl<I extends A, T extends B<I>> extends ITest<T>{ |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static class TopLevelClass<T> { |
|
|
|
|
class Nested<X> { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static class TypedTopLevelClass extends TopLevelClass<Integer> { |
|
|
|
|
class TypedNested extends Nested<Long> { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static abstract class WithArrayBase<T> { |
|
|
|
|
|
|
|
|
|
public abstract T[] array(T... args); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static abstract class WithArray<T> extends WithArrayBase<T> { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|