1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.apache.ibatis.reflection;
17
18 import java.lang.reflect.Array;
19 import java.lang.reflect.Field;
20 import java.lang.reflect.GenericArrayType;
21 import java.lang.reflect.Method;
22 import java.lang.reflect.ParameterizedType;
23 import java.lang.reflect.Type;
24 import java.lang.reflect.TypeVariable;
25 import java.lang.reflect.WildcardType;
26 import java.util.Arrays;
27
28
29
30
31 public class TypeParameterResolver {
32
33
34
35
36
37
38
39
40
41
42
43
44 public static Type resolveFieldType(Field field, Type srcType) {
45 Type fieldType = field.getGenericType();
46 Class<?> declaringClass = field.getDeclaringClass();
47 return resolveType(fieldType, srcType, declaringClass);
48 }
49
50
51
52
53
54
55
56
57
58
59
60
61 public static Type resolveReturnType(Method method, Type srcType) {
62 Type returnType = method.getGenericReturnType();
63 Class<?> declaringClass = method.getDeclaringClass();
64 return resolveType(returnType, srcType, declaringClass);
65 }
66
67
68
69
70
71
72
73
74
75
76
77
78
79 public static Type[] resolveParamTypes(Method method, Type srcType) {
80 Type[] paramTypes = method.getGenericParameterTypes();
81 Class<?> declaringClass = method.getDeclaringClass();
82 Type[] result = new Type[paramTypes.length];
83 for (int i = 0; i < paramTypes.length; i++) {
84 result[i] = resolveType(paramTypes[i], srcType, declaringClass);
85 }
86 return result;
87 }
88
89 private static Type resolveType(Type type, Type srcType, Class<?> declaringClass) {
90 if (type instanceof TypeVariable) {
91 return resolveTypeVar((TypeVariable<?>) type, srcType, declaringClass);
92 }
93 if (type instanceof ParameterizedType) {
94 return resolveParameterizedType((ParameterizedType) type, srcType, declaringClass);
95 } else if (type instanceof GenericArrayType) {
96 return resolveGenericArrayType((GenericArrayType) type, srcType, declaringClass);
97 } else {
98 return type;
99 }
100 }
101
102 private static Type resolveGenericArrayType(GenericArrayType genericArrayType, Type srcType,
103 Class<?> declaringClass) {
104 Type componentType = genericArrayType.getGenericComponentType();
105 Type resolvedComponentType = null;
106 if (componentType instanceof TypeVariable) {
107 resolvedComponentType = resolveTypeVar((TypeVariable<?>) componentType, srcType, declaringClass);
108 } else if (componentType instanceof GenericArrayType) {
109 resolvedComponentType = resolveGenericArrayType((GenericArrayType) componentType, srcType, declaringClass);
110 } else if (componentType instanceof ParameterizedType) {
111 resolvedComponentType = resolveParameterizedType((ParameterizedType) componentType, srcType, declaringClass);
112 }
113 if (resolvedComponentType instanceof Class) {
114 return Array.newInstance((Class<?>) resolvedComponentType, 0).getClass();
115 }
116 return new GenericArrayTypeImpl(resolvedComponentType);
117 }
118
119 private static ParameterizedType resolveParameterizedType(ParameterizedType parameterizedType, Type srcType,
120 Class<?> declaringClass) {
121 Class<?> rawType = (Class<?>) parameterizedType.getRawType();
122 Type[] typeArgs = parameterizedType.getActualTypeArguments();
123 Type[] args = new Type[typeArgs.length];
124 for (int i = 0; i < typeArgs.length; i++) {
125 if (typeArgs[i] instanceof TypeVariable) {
126 args[i] = resolveTypeVar((TypeVariable<?>) typeArgs[i], srcType, declaringClass);
127 } else if (typeArgs[i] instanceof ParameterizedType) {
128 args[i] = resolveParameterizedType((ParameterizedType) typeArgs[i], srcType, declaringClass);
129 } else if (typeArgs[i] instanceof WildcardType) {
130 args[i] = resolveWildcardType((WildcardType) typeArgs[i], srcType, declaringClass);
131 } else {
132 args[i] = typeArgs[i];
133 }
134 }
135 return new ParameterizedTypeImpl(rawType, null, args);
136 }
137
138 private static Type resolveWildcardType(WildcardType wildcardType, Type srcType, Class<?> declaringClass) {
139 Type[] lowerBounds = resolveWildcardTypeBounds(wildcardType.getLowerBounds(), srcType, declaringClass);
140 Type[] upperBounds = resolveWildcardTypeBounds(wildcardType.getUpperBounds(), srcType, declaringClass);
141 return new WildcardTypeImpl(lowerBounds, upperBounds);
142 }
143
144 private static Type[] resolveWildcardTypeBounds(Type[] bounds, Type srcType, Class<?> declaringClass) {
145 Type[] result = new Type[bounds.length];
146 for (int i = 0; i < bounds.length; i++) {
147 if (bounds[i] instanceof TypeVariable) {
148 result[i] = resolveTypeVar((TypeVariable<?>) bounds[i], srcType, declaringClass);
149 } else if (bounds[i] instanceof ParameterizedType) {
150 result[i] = resolveParameterizedType((ParameterizedType) bounds[i], srcType, declaringClass);
151 } else if (bounds[i] instanceof WildcardType) {
152 result[i] = resolveWildcardType((WildcardType) bounds[i], srcType, declaringClass);
153 } else {
154 result[i] = bounds[i];
155 }
156 }
157 return result;
158 }
159
160 private static Type resolveTypeVar(TypeVariable<?> typeVar, Type srcType, Class<?> declaringClass) {
161 Type result;
162 Class<?> clazz;
163 if (srcType instanceof Class) {
164 clazz = (Class<?>) srcType;
165 } else if (srcType instanceof ParameterizedType) {
166 ParameterizedType parameterizedType = (ParameterizedType) srcType;
167 clazz = (Class<?>) parameterizedType.getRawType();
168 } else {
169 throw new IllegalArgumentException(
170 "The 2nd arg must be Class or ParameterizedType, but was: " + srcType.getClass());
171 }
172
173 if (clazz == declaringClass) {
174 Type[] bounds = typeVar.getBounds();
175 if (bounds.length > 0) {
176 return bounds[0];
177 }
178 return Object.class;
179 }
180
181 Type superclass = clazz.getGenericSuperclass();
182 result = scanSuperTypes(typeVar, srcType, declaringClass, clazz, superclass);
183 if (result != null) {
184 return result;
185 }
186
187 Type[] superInterfaces = clazz.getGenericInterfaces();
188 for (Type superInterface : superInterfaces) {
189 result = scanSuperTypes(typeVar, srcType, declaringClass, clazz, superInterface);
190 if (result != null) {
191 return result;
192 }
193 }
194 return Object.class;
195 }
196
197 private static Type scanSuperTypes(TypeVariable<?> typeVar, Type srcType, Class<?> declaringClass, Class<?> clazz,
198 Type superclass) {
199 if (superclass instanceof ParameterizedType) {
200 ParameterizedType parentAsType = (ParameterizedType) superclass;
201 Class<?> parentAsClass = (Class<?>) parentAsType.getRawType();
202 TypeVariable<?>[] parentTypeVars = parentAsClass.getTypeParameters();
203 if (srcType instanceof ParameterizedType) {
204 parentAsType = translateParentTypeVars((ParameterizedType) srcType, clazz, parentAsType);
205 }
206 if (declaringClass == parentAsClass) {
207 for (int i = 0; i < parentTypeVars.length; i++) {
208 if (typeVar.equals(parentTypeVars[i])) {
209 return parentAsType.getActualTypeArguments()[i];
210 }
211 }
212 }
213 if (declaringClass.isAssignableFrom(parentAsClass)) {
214 return resolveTypeVar(typeVar, parentAsType, declaringClass);
215 }
216 } else if (superclass instanceof Class && declaringClass.isAssignableFrom((Class<?>) superclass)) {
217 return resolveTypeVar(typeVar, superclass, declaringClass);
218 }
219 return null;
220 }
221
222 private static ParameterizedType translateParentTypeVars(ParameterizedType srcType, Class<?> srcClass,
223 ParameterizedType parentType) {
224 Type[] parentTypeArgs = parentType.getActualTypeArguments();
225 Type[] srcTypeArgs = srcType.getActualTypeArguments();
226 TypeVariable<?>[] srcTypeVars = srcClass.getTypeParameters();
227 Type[] newParentArgs = new Type[parentTypeArgs.length];
228 boolean noChange = true;
229 for (int i = 0; i < parentTypeArgs.length; i++) {
230 if (parentTypeArgs[i] instanceof TypeVariable) {
231 for (int j = 0; j < srcTypeVars.length; j++) {
232 if (srcTypeVars[j].equals(parentTypeArgs[i])) {
233 noChange = false;
234 newParentArgs[i] = srcTypeArgs[j];
235 }
236 }
237 } else {
238 newParentArgs[i] = parentTypeArgs[i];
239 }
240 }
241 return noChange ? parentType : new ParameterizedTypeImpl((Class<?>) parentType.getRawType(), null, newParentArgs);
242 }
243
244 private TypeParameterResolver() {
245 }
246
247 static class ParameterizedTypeImpl implements ParameterizedType {
248 private final Class<?> rawType;
249
250 private final Type ownerType;
251
252 private final Type[] actualTypeArguments;
253
254 public ParameterizedTypeImpl(Class<?> rawType, Type ownerType, Type[] actualTypeArguments) {
255 this.rawType = rawType;
256 this.ownerType = ownerType;
257 this.actualTypeArguments = actualTypeArguments;
258 }
259
260 @Override
261 public Type[] getActualTypeArguments() {
262 return actualTypeArguments;
263 }
264
265 @Override
266 public Type getOwnerType() {
267 return ownerType;
268 }
269
270 @Override
271 public Type getRawType() {
272 return rawType;
273 }
274
275 @Override
276 public String toString() {
277 return "ParameterizedTypeImpl [rawType=" + rawType + ", ownerType=" + ownerType + ", actualTypeArguments="
278 + Arrays.toString(actualTypeArguments) + "]";
279 }
280 }
281
282 static class WildcardTypeImpl implements WildcardType {
283 private final Type[] lowerBounds;
284
285 private final Type[] upperBounds;
286
287 WildcardTypeImpl(Type[] lowerBounds, Type[] upperBounds) {
288 this.lowerBounds = lowerBounds;
289 this.upperBounds = upperBounds;
290 }
291
292 @Override
293 public Type[] getLowerBounds() {
294 return lowerBounds;
295 }
296
297 @Override
298 public Type[] getUpperBounds() {
299 return upperBounds;
300 }
301 }
302
303 static class GenericArrayTypeImpl implements GenericArrayType {
304 private final Type genericComponentType;
305
306 GenericArrayTypeImpl(Type genericComponentType) {
307 this.genericComponentType = genericComponentType;
308 }
309
310 @Override
311 public Type getGenericComponentType() {
312 return genericComponentType;
313 }
314 }
315 }