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 Type actualType = parentAsType.getActualTypeArguments()[i];
210 return actualType instanceof TypeVariable<?> ? Object.class : actualType;
211 }
212 }
213 }
214 if (declaringClass.isAssignableFrom(parentAsClass)) {
215 return resolveTypeVar(typeVar, parentAsType, declaringClass);
216 }
217 } else if (superclass instanceof Class && declaringClass.isAssignableFrom((Class<?>) superclass)) {
218 return resolveTypeVar(typeVar, superclass, declaringClass);
219 }
220 return null;
221 }
222
223 private static ParameterizedType translateParentTypeVars(ParameterizedType srcType, Class<?> srcClass,
224 ParameterizedType parentType) {
225 Type[] parentTypeArgs = parentType.getActualTypeArguments();
226 Type[] srcTypeArgs = srcType.getActualTypeArguments();
227 TypeVariable<?>[] srcTypeVars = srcClass.getTypeParameters();
228 Type[] newParentArgs = new Type[parentTypeArgs.length];
229 boolean noChange = true;
230 for (int i = 0; i < parentTypeArgs.length; i++) {
231 if (parentTypeArgs[i] instanceof TypeVariable) {
232 for (int j = 0; j < srcTypeVars.length; j++) {
233 if (srcTypeVars[j].equals(parentTypeArgs[i])) {
234 noChange = false;
235 newParentArgs[i] = srcTypeArgs[j];
236 }
237 }
238 } else {
239 newParentArgs[i] = parentTypeArgs[i];
240 }
241 }
242 return noChange ? parentType : new ParameterizedTypeImpl((Class<?>) parentType.getRawType(), null, newParentArgs);
243 }
244
245 private TypeParameterResolver() {
246 }
247
248 static class ParameterizedTypeImpl implements ParameterizedType {
249 private final Class<?> rawType;
250
251 private final Type ownerType;
252
253 private final Type[] actualTypeArguments;
254
255 public ParameterizedTypeImpl(Class<?> rawType, Type ownerType, Type[] actualTypeArguments) {
256 this.rawType = rawType;
257 this.ownerType = ownerType;
258 this.actualTypeArguments = actualTypeArguments;
259 }
260
261 @Override
262 public Type[] getActualTypeArguments() {
263 return actualTypeArguments;
264 }
265
266 @Override
267 public Type getOwnerType() {
268 return ownerType;
269 }
270
271 @Override
272 public Type getRawType() {
273 return rawType;
274 }
275
276 @Override
277 public String toString() {
278 return "ParameterizedTypeImpl [rawType=" + rawType + ", ownerType=" + ownerType + ", actualTypeArguments="
279 + Arrays.toString(actualTypeArguments) + "]";
280 }
281 }
282
283 static class WildcardTypeImpl implements WildcardType {
284 private final Type[] lowerBounds;
285
286 private final Type[] upperBounds;
287
288 WildcardTypeImpl(Type[] lowerBounds, Type[] upperBounds) {
289 this.lowerBounds = lowerBounds;
290 this.upperBounds = upperBounds;
291 }
292
293 @Override
294 public Type[] getLowerBounds() {
295 return lowerBounds;
296 }
297
298 @Override
299 public Type[] getUpperBounds() {
300 return upperBounds;
301 }
302 }
303
304 static class GenericArrayTypeImpl implements GenericArrayType {
305 private final Type genericComponentType;
306
307 GenericArrayTypeImpl(Type genericComponentType) {
308 this.genericComponentType = genericComponentType;
309 }
310
311 @Override
312 public Type getGenericComponentType() {
313 return genericComponentType;
314 }
315 }
316 }