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