1
1
/*
2
- * Copyright 2002-2010 the original author or authors.
2
+ * Copyright 2002-2011 the original author or authors.
3
3
*
4
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
5
* you may not use this file except in compliance with the License.
@@ -75,7 +75,7 @@ public static Class<?> getMapValueType(Class<? extends Map> mapClass) {
75
75
* @return the generic type, or <code>null</code> if none
76
76
*/
77
77
public static Class <?> getCollectionFieldType (Field collectionField ) {
78
- return getGenericFieldType (collectionField , Collection .class , 0 , 1 );
78
+ return getGenericFieldType (collectionField , Collection .class , 0 , null , 1 );
79
79
}
80
80
81
81
/**
@@ -87,7 +87,21 @@ public static Class<?> getCollectionFieldType(Field collectionField) {
87
87
* @return the generic type, or <code>null</code> if none
88
88
*/
89
89
public static Class <?> getCollectionFieldType (Field collectionField , int nestingLevel ) {
90
- return getGenericFieldType (collectionField , Collection .class , 0 , nestingLevel );
90
+ return getGenericFieldType (collectionField , Collection .class , 0 , null , nestingLevel );
91
+ }
92
+
93
+ /**
94
+ * Determine the generic element type of the given Collection field.
95
+ * @param collectionField the collection field to introspect
96
+ * @param nestingLevel the nesting level of the target type
97
+ * (typically 1; e.g. in case of a List of Lists, 1 would indicate the
98
+ * nested List, whereas 2 would indicate the element of the nested List)
99
+ * @param typeIndexesPerLevel Map keyed by nesting level, with each value
100
+ * expressing the type index for traversal at that level
101
+ * @return the generic type, or <code>null</code> if none
102
+ */
103
+ public static Class <?> getCollectionFieldType (Field collectionField , int nestingLevel , Map <Integer , Integer > typeIndexesPerLevel ) {
104
+ return getGenericFieldType (collectionField , Collection .class , 0 , typeIndexesPerLevel , nestingLevel );
91
105
}
92
106
93
107
/**
@@ -96,7 +110,7 @@ public static Class<?> getCollectionFieldType(Field collectionField, int nesting
96
110
* @return the generic type, or <code>null</code> if none
97
111
*/
98
112
public static Class <?> getMapKeyFieldType (Field mapField ) {
99
- return getGenericFieldType (mapField , Map .class , 0 , 1 );
113
+ return getGenericFieldType (mapField , Map .class , 0 , null , 1 );
100
114
}
101
115
102
116
/**
@@ -108,7 +122,21 @@ public static Class<?> getMapKeyFieldType(Field mapField) {
108
122
* @return the generic type, or <code>null</code> if none
109
123
*/
110
124
public static Class <?> getMapKeyFieldType (Field mapField , int nestingLevel ) {
111
- return getGenericFieldType (mapField , Map .class , 0 , nestingLevel );
125
+ return getGenericFieldType (mapField , Map .class , 0 , null , nestingLevel );
126
+ }
127
+
128
+ /**
129
+ * Determine the generic key type of the given Map field.
130
+ * @param mapField the map field to introspect
131
+ * @param nestingLevel the nesting level of the target type
132
+ * (typically 1; e.g. in case of a List of Lists, 1 would indicate the
133
+ * nested List, whereas 2 would indicate the element of the nested List)
134
+ * @param typeIndexesPerLevel Map keyed by nesting level, with each value
135
+ * expressing the type index for traversal at that level
136
+ * @return the generic type, or <code>null</code> if none
137
+ */
138
+ public static Class <?> getMapKeyFieldType (Field mapField , int nestingLevel , Map <Integer , Integer > typeIndexesPerLevel ) {
139
+ return getGenericFieldType (mapField , Map .class , 0 , typeIndexesPerLevel , nestingLevel );
112
140
}
113
141
114
142
/**
@@ -117,7 +145,7 @@ public static Class<?> getMapKeyFieldType(Field mapField, int nestingLevel) {
117
145
* @return the generic type, or <code>null</code> if none
118
146
*/
119
147
public static Class <?> getMapValueFieldType (Field mapField ) {
120
- return getGenericFieldType (mapField , Map .class , 1 , 1 );
148
+ return getGenericFieldType (mapField , Map .class , 1 , null , 1 );
121
149
}
122
150
123
151
/**
@@ -129,7 +157,21 @@ public static Class<?> getMapValueFieldType(Field mapField) {
129
157
* @return the generic type, or <code>null</code> if none
130
158
*/
131
159
public static Class <?> getMapValueFieldType (Field mapField , int nestingLevel ) {
132
- return getGenericFieldType (mapField , Map .class , 1 , nestingLevel );
160
+ return getGenericFieldType (mapField , Map .class , 1 , null , nestingLevel );
161
+ }
162
+
163
+ /**
164
+ * Determine the generic value type of the given Map field.
165
+ * @param mapField the map field to introspect
166
+ * @param nestingLevel the nesting level of the target type
167
+ * (typically 1; e.g. in case of a List of Lists, 1 would indicate the
168
+ * nested List, whereas 2 would indicate the element of the nested List)
169
+ * @param typeIndexesPerLevel Map keyed by nesting level, with each value
170
+ * expressing the type index for traversal at that level
171
+ * @return the generic type, or <code>null</code> if none
172
+ */
173
+ public static Class <?> getMapValueFieldType (Field mapField , int nestingLevel , Map <Integer , Integer > typeIndexesPerLevel ) {
174
+ return getGenericFieldType (mapField , Map .class , 1 , typeIndexesPerLevel , nestingLevel );
133
175
}
134
176
135
177
/**
@@ -234,8 +276,8 @@ public static Class<?> getMapValueReturnType(Method method, int nestingLevel) {
234
276
* @return the generic type, or <code>null</code> if none
235
277
*/
236
278
private static Class <?> getGenericParameterType (MethodParameter methodParam , Class <?> source , int typeIndex ) {
237
- return extractType (methodParam , GenericTypeResolver .getTargetType (methodParam ),
238
- source , typeIndex , methodParam .getNestingLevel (), 1 );
279
+ return extractType (GenericTypeResolver .getTargetType (methodParam ), source , typeIndex ,
280
+ methodParam . typeVariableMap , methodParam . typeIndexesPerLevel , methodParam .getNestingLevel (), 1 );
239
281
}
240
282
241
283
/**
@@ -247,8 +289,9 @@ private static Class<?> getGenericParameterType(MethodParameter methodParam, Cla
247
289
* @param nestingLevel the nesting level of the target type
248
290
* @return the generic type, or <code>null</code> if none
249
291
*/
250
- private static Class <?> getGenericFieldType (Field field , Class <?> source , int typeIndex , int nestingLevel ) {
251
- return extractType (null , field .getGenericType (), source , typeIndex , nestingLevel , 1 );
292
+ private static Class <?> getGenericFieldType (Field field , Class <?> source , int typeIndex ,
293
+ Map <Integer , Integer > typeIndexesPerLevel , int nestingLevel ) {
294
+ return extractType (field .getGenericType (), source , typeIndex , null , typeIndexesPerLevel , nestingLevel , 1 );
252
295
}
253
296
254
297
/**
@@ -261,35 +304,40 @@ private static Class<?> getGenericFieldType(Field field, Class<?> source, int ty
261
304
* @return the generic type, or <code>null</code> if none
262
305
*/
263
306
private static Class <?> getGenericReturnType (Method method , Class <?> source , int typeIndex , int nestingLevel ) {
264
- return extractType (null , method .getGenericReturnType (), source , typeIndex , nestingLevel , 1 );
307
+ return extractType (method .getGenericReturnType (), source , typeIndex , null , null , nestingLevel , 1 );
265
308
}
266
309
267
310
/**
268
311
* Extract the generic type from the given Type object.
269
- * @param methodParam the method parameter specification
270
312
* @param type the Type to check
271
313
* @param source the source collection/map Class that we check
272
314
* @param typeIndex the index of the actual type argument
273
315
* @param nestingLevel the nesting level of the target type
274
316
* @param currentLevel the current nested level
275
317
* @return the generic type as Class, or <code>null</code> if none
276
318
*/
277
- private static Class <?> extractType (
278
- MethodParameter methodParam , Type type , Class <?> source , int typeIndex , int nestingLevel , int currentLevel ) {
319
+ private static Class <?> extractType (Type type , Class <?> source , int typeIndex ,
320
+ Map <TypeVariable , Type > typeVariableMap , Map <Integer , Integer > typeIndexesPerLevel ,
321
+ int nestingLevel , int currentLevel ) {
279
322
280
323
Type resolvedType = type ;
281
- if (type instanceof TypeVariable && methodParam != null && methodParam . typeVariableMap != null ) {
282
- Type mappedType = methodParam . typeVariableMap .get ((TypeVariable ) type );
324
+ if (type instanceof TypeVariable && typeVariableMap != null ) {
325
+ Type mappedType = typeVariableMap .get ((TypeVariable ) type );
283
326
if (mappedType != null ) {
284
327
resolvedType = mappedType ;
285
328
}
286
329
}
287
330
if (resolvedType instanceof ParameterizedType ) {
288
- return extractTypeFromParameterizedType (
289
- methodParam , ( ParameterizedType ) resolvedType , source , typeIndex , nestingLevel , currentLevel );
331
+ return extractTypeFromParameterizedType (( ParameterizedType ) resolvedType , source , typeIndex , typeVariableMap , typeIndexesPerLevel ,
332
+ nestingLevel , currentLevel );
290
333
}
291
334
else if (resolvedType instanceof Class ) {
292
- return extractTypeFromClass (methodParam , (Class ) resolvedType , source , typeIndex , nestingLevel , currentLevel );
335
+ return extractTypeFromClass ((Class ) resolvedType , source , typeIndex , typeVariableMap , typeIndexesPerLevel ,
336
+ nestingLevel , currentLevel );
337
+ }
338
+ else if (resolvedType instanceof GenericArrayType ) {
339
+ Type compType = ((GenericArrayType ) resolvedType ).getGenericComponentType ();
340
+ return extractType (compType , source , typeIndex , typeVariableMap , typeIndexesPerLevel , nestingLevel , currentLevel + 1 );
293
341
}
294
342
else {
295
343
return null ;
@@ -298,16 +346,16 @@ else if (resolvedType instanceof Class) {
298
346
299
347
/**
300
348
* Extract the generic type from the given ParameterizedType object.
301
- * @param methodParam the method parameter specification
302
349
* @param ptype the ParameterizedType to check
303
350
* @param source the expected raw source type (can be <code>null</code>)
304
351
* @param typeIndex the index of the actual type argument
305
352
* @param nestingLevel the nesting level of the target type
306
353
* @param currentLevel the current nested level
307
354
* @return the generic type as Class, or <code>null</code> if none
308
355
*/
309
- private static Class <?> extractTypeFromParameterizedType (MethodParameter methodParam ,
310
- ParameterizedType ptype , Class <?> source , int typeIndex , int nestingLevel , int currentLevel ) {
356
+ private static Class <?> extractTypeFromParameterizedType (ParameterizedType ptype , Class <?> source , int typeIndex ,
357
+ Map <TypeVariable , Type > typeVariableMap , Map <Integer , Integer > typeIndexesPerLevel ,
358
+ int nestingLevel , int currentLevel ) {
311
359
312
360
if (!(ptype .getRawType () instanceof Class )) {
313
361
return null ;
@@ -316,26 +364,26 @@ private static Class<?> extractTypeFromParameterizedType(MethodParameter methodP
316
364
Type [] paramTypes = ptype .getActualTypeArguments ();
317
365
if (nestingLevel - currentLevel > 0 ) {
318
366
int nextLevel = currentLevel + 1 ;
319
- Integer currentTypeIndex = (methodParam != null ? methodParam . getTypeIndexForLevel (nextLevel ) : null );
367
+ Integer currentTypeIndex = (typeIndexesPerLevel != null ? typeIndexesPerLevel . get (nextLevel ) : null );
320
368
// Default is last parameter type: Collection element or Map value.
321
369
int indexToUse = (currentTypeIndex != null ? currentTypeIndex : paramTypes .length - 1 );
322
370
Type paramType = paramTypes [indexToUse ];
323
- return extractType (methodParam , paramType , source , typeIndex , nestingLevel , nextLevel );
371
+ return extractType (paramType , source , typeIndex , typeVariableMap , typeIndexesPerLevel , nestingLevel , nextLevel );
324
372
}
325
373
if (source != null && !source .isAssignableFrom (rawType )) {
326
374
return null ;
327
375
}
328
- Class fromSuperclassOrInterface =
329
- extractTypeFromClass ( methodParam , rawType , source , typeIndex , nestingLevel , currentLevel );
376
+ Class fromSuperclassOrInterface = extractTypeFromClass ( rawType , source , typeIndex , typeVariableMap , typeIndexesPerLevel ,
377
+ nestingLevel , currentLevel );
330
378
if (fromSuperclassOrInterface != null ) {
331
379
return fromSuperclassOrInterface ;
332
380
}
333
381
if (paramTypes == null || typeIndex >= paramTypes .length ) {
334
382
return null ;
335
383
}
336
384
Type paramType = paramTypes [typeIndex ];
337
- if (paramType instanceof TypeVariable && methodParam != null && methodParam . typeVariableMap != null ) {
338
- Type mappedType = methodParam . typeVariableMap .get ((TypeVariable ) paramType );
385
+ if (paramType instanceof TypeVariable && typeVariableMap != null ) {
386
+ Type mappedType = typeVariableMap .get ((TypeVariable ) paramType );
339
387
if (mappedType != null ) {
340
388
paramType = mappedType ;
341
389
}
@@ -378,27 +426,28 @@ else if (paramType instanceof Class) {
378
426
* @return the generic type as Class, or <code>null</code> if none
379
427
*/
380
428
private static Class <?> extractTypeFromClass (Class <?> clazz , Class <?> source , int typeIndex ) {
381
- return extractTypeFromClass (null , clazz , source , typeIndex , 1 , 1 );
429
+ return extractTypeFromClass (clazz , source , typeIndex , null , null , 1 , 1 );
382
430
}
383
431
384
432
/**
385
433
* Extract the generic type from the given Class object.
386
- * @param methodParam the method parameter specification
387
434
* @param clazz the Class to check
388
435
* @param source the expected raw source type (can be <code>null</code>)
389
436
* @param typeIndex the index of the actual type argument
390
437
* @param nestingLevel the nesting level of the target type
391
438
* @param currentLevel the current nested level
392
439
* @return the generic type as Class, or <code>null</code> if none
393
440
*/
394
- private static Class <?> extractTypeFromClass (
395
- MethodParameter methodParam , Class <?> clazz , Class <?> source , int typeIndex , int nestingLevel , int currentLevel ) {
441
+ private static Class <?> extractTypeFromClass (Class <?> clazz , Class <?> source , int typeIndex ,
442
+ Map <TypeVariable , Type > typeVariableMap , Map <Integer , Integer > typeIndexesPerLevel ,
443
+ int nestingLevel , int currentLevel ) {
396
444
397
445
if (clazz .getName ().startsWith ("java.util." )) {
398
446
return null ;
399
447
}
400
448
if (clazz .getSuperclass () != null && isIntrospectionCandidate (clazz .getSuperclass ())) {
401
- return extractType (methodParam , clazz .getGenericSuperclass (), source , typeIndex , nestingLevel , currentLevel );
449
+ return extractType (clazz .getGenericSuperclass (), source , typeIndex , typeVariableMap , typeIndexesPerLevel ,
450
+ nestingLevel , currentLevel );
402
451
}
403
452
Type [] ifcs = clazz .getGenericInterfaces ();
404
453
if (ifcs != null ) {
@@ -408,7 +457,7 @@ private static Class<?> extractTypeFromClass(
408
457
rawType = ((ParameterizedType ) ifc ).getRawType ();
409
458
}
410
459
if (rawType instanceof Class && isIntrospectionCandidate ((Class ) rawType )) {
411
- return extractType (methodParam , ifc , source , typeIndex , nestingLevel , currentLevel );
460
+ return extractType (ifc , source , typeIndex , typeVariableMap , typeIndexesPerLevel , nestingLevel , currentLevel );
412
461
}
413
462
}
414
463
}
0 commit comments