26
26
import org .springframework .core .MethodParameter ;
27
27
import org .springframework .util .Assert ;
28
28
import org .springframework .util .ClassUtils ;
29
+ import org .springframework .util .CollectionUtils ;
29
30
import org .springframework .util .ObjectUtils ;
30
31
31
32
/**
34
35
* @author Keith Donald
35
36
* @author Andy Clement
36
37
* @author Juergen Hoeller
37
- * @since 3.0
38
+ * @since 3.0
38
39
*/
39
40
public class TypeDescriptor {
40
41
@@ -44,7 +45,7 @@ public class TypeDescriptor {
44
45
private static final Map <Class <?>, TypeDescriptor > typeDescriptorCache = new HashMap <Class <?>, TypeDescriptor >();
45
46
46
47
private static final Annotation [] EMPTY_ANNOTATION_ARRAY = new Annotation [0 ];
47
-
48
+
48
49
static {
49
50
typeDescriptorCache .put (boolean .class , new TypeDescriptor (boolean .class ));
50
51
typeDescriptorCache .put (Boolean .class , new TypeDescriptor (Boolean .class ));
@@ -75,13 +76,13 @@ public class TypeDescriptor {
75
76
private Object value ;
76
77
77
78
private TypeDescriptor elementType ;
78
-
79
+
79
80
private TypeDescriptor mapKeyType ;
80
-
81
+
81
82
private TypeDescriptor mapValueType ;
82
83
83
84
private Annotation [] annotations ;
84
-
85
+
85
86
86
87
/**
87
88
* Create a new type descriptor from a method or constructor parameter.
@@ -248,15 +249,15 @@ public Class<?> getElementType() {
248
249
* Return the element type as a type descriptor.
249
250
*/
250
251
public synchronized TypeDescriptor getElementTypeDescriptor () {
251
- if (elementType == null ) {
252
- elementType = forElementType (resolveElementType ());
252
+ if (this . elementType == null ) {
253
+ this . elementType = forElementType (resolveElementType ());
253
254
}
254
- return elementType ;
255
+ return this . elementType ;
255
256
}
256
257
257
258
/**
258
- * Return the element type as a type descriptor; if the element type is null (cannot be determined),
259
- * the type descriptor is derived from the element argument.
259
+ * Return the element type as a type descriptor. If the element type is null
260
+ * (cannot be determined), the type descriptor is derived from the element argument.
260
261
* @param element the element
261
262
* @return the element type descriptor
262
263
*/
@@ -273,7 +274,7 @@ public boolean isMap() {
273
274
}
274
275
275
276
/**
276
- * Is this descriptor for a map where the key type and value type are known?
277
+ * Is this descriptor for a map where the key type and value type are known?
277
278
*/
278
279
public boolean isMapEntryTypeKnown () {
279
280
return (isMap () && getMapKeyType () != null && getMapValueType () != null );
@@ -291,42 +292,43 @@ public Class<?> getMapKeyType() {
291
292
* Returns map key type as a type descriptor.
292
293
*/
293
294
public synchronized TypeDescriptor getMapKeyTypeDescriptor () {
294
- if (mapKeyType == null ) {
295
- mapKeyType = forElementType (resolveMapKeyType ());
295
+ if (this . mapKeyType == null ) {
296
+ this . mapKeyType = forElementType (resolveMapKeyType ());
296
297
}
297
- return mapKeyType ;
298
+ return this . mapKeyType ;
298
299
}
299
300
300
301
/**
301
- * Return the map key type as a type descriptor; if the key type is null (cannot be determined), the type descriptor is derived from the key argument.
302
+ * Return the map key type as a type descriptor. If the key type is null
303
+ * (cannot be determined), the type descriptor is derived from the key argument.
302
304
* @param key the key
303
305
* @return the map key type descriptor
304
306
*/
305
307
public TypeDescriptor getMapKeyTypeDescriptor (Object key ) {
306
308
TypeDescriptor keyType = getMapKeyTypeDescriptor ();
307
309
return keyType != TypeDescriptor .NULL ? keyType : TypeDescriptor .forObject (key );
308
310
}
309
-
311
+
310
312
/**
311
313
* Determine the generic value type of the wrapped Map parameter/field, if any.
312
314
* @return the generic type, or <code>null</code> if none
313
315
*/
314
316
public Class <?> getMapValueType () {
315
317
return getMapValueTypeDescriptor ().getType ();
316
318
}
317
-
319
+
318
320
/**
319
321
* Returns map value type as a type descriptor.
320
322
*/
321
323
public synchronized TypeDescriptor getMapValueTypeDescriptor () {
322
324
if (this .mapValueType == null ) {
323
- mapValueType = forElementType (resolveMapValueType ());
325
+ this . mapValueType = forElementType (resolveMapValueType ());
324
326
}
325
327
return this .mapValueType ;
326
328
}
327
329
328
330
/**
329
- * Return the map value type as a type descriptor; if the value type is null
331
+ * Return the map value type as a type descriptor. If the value type is null
330
332
* (cannot be determined), the type descriptor is derived from the value argument.
331
333
* @param value the value
332
334
* @return the map value type descriptor
@@ -355,7 +357,7 @@ public Annotation getAnnotation(Class<? extends Annotation> annotationType) {
355
357
return annotation ;
356
358
}
357
359
}
358
- return null ;
360
+ return null ;
359
361
}
360
362
361
363
/**
@@ -423,14 +425,14 @@ else if (isMap()) {
423
425
ObjectUtils .nullSafeEquals (getMapValueType (), td .getMapValueType ());
424
426
}
425
427
else {
426
- return annotatedTypeEquals ;
428
+ return annotatedTypeEquals ;
427
429
}
428
430
}
429
-
431
+
430
432
public int hashCode () {
431
433
return getType ().hashCode ();
432
434
}
433
-
435
+
434
436
/**
435
437
* A textual representation of the type descriptor (eg. Map<String,Foo>) for use in messages
436
438
*/
@@ -459,7 +461,7 @@ public String toString() {
459
461
}
460
462
else if (isCollection ()) {
461
463
Class <?> elementType = getElementType ();
462
- builder .append ("<" ).append (elementType != null ? ClassUtils .getQualifiedName (elementType ) : "?" ).append (">" );
464
+ builder .append ("<" ).append (elementType != null ? ClassUtils .getQualifiedName (elementType ) : "?" ).append (">" );
463
465
}
464
466
builder .append ("]" );
465
467
return builder .toString ();
@@ -468,7 +470,7 @@ else if (isCollection()) {
468
470
469
471
470
472
// internal helpers
471
-
473
+
472
474
private Class <?> resolveElementType () {
473
475
if (isArray ()) {
474
476
return getType ().getComponentType ();
@@ -478,9 +480,9 @@ else if (isCollection()) {
478
480
}
479
481
else {
480
482
return null ;
481
- }
483
+ }
482
484
}
483
-
485
+
484
486
@ SuppressWarnings ("unchecked" )
485
487
private Class <?> resolveCollectionElementType () {
486
488
if (this .field != null ) {
@@ -490,17 +492,14 @@ else if (this.methodParameter != null) {
490
492
return GenericCollectionTypeResolver .getCollectionParameterType (this .methodParameter );
491
493
}
492
494
else if (this .value instanceof Collection ) {
493
- Collection coll = (Collection ) this .value ;
494
- if (!coll .isEmpty ()) {
495
- Object elem = coll .iterator ().next ();
496
- if (elem != null ) {
497
- return elem .getClass ();
498
- }
495
+ Class <?> elementType = CollectionUtils .findCommonElementType ((Collection ) this .value );
496
+ if (elementType != null ) {
497
+ return elementType ;
499
498
}
500
499
}
501
- return (this .type != null ? GenericCollectionTypeResolver .getCollectionType ((Class <? extends Collection >) this .type ) : null );
500
+ return (this .type != null ? GenericCollectionTypeResolver .getCollectionType ((Class <? extends Collection >) this .type ) : null );
502
501
}
503
-
502
+
504
503
@ SuppressWarnings ("unchecked" )
505
504
private Class <?> resolveMapKeyType () {
506
505
if (this .field != null ) {
@@ -510,12 +509,9 @@ else if (this.methodParameter != null) {
510
509
return GenericCollectionTypeResolver .getMapKeyParameterType (this .methodParameter );
511
510
}
512
511
else if (this .value instanceof Map <?, ?>) {
513
- Map <?, ?> map = (Map <?, ?>) this .value ;
514
- if (!map .isEmpty ()) {
515
- Object key = map .keySet ().iterator ().next ();
516
- if (key != null ) {
517
- return key .getClass ();
518
- }
512
+ Class <?> keyType = CollectionUtils .findCommonElementType (((Map <?, ?>) this .value ).keySet ());
513
+ if (keyType != null ) {
514
+ return keyType ;
519
515
}
520
516
}
521
517
return (this .type != null && isMap () ? GenericCollectionTypeResolver .getMapKeyType ((Class <? extends Map >) this .type ) : null );
@@ -530,17 +526,14 @@ else if (this.methodParameter != null) {
530
526
return GenericCollectionTypeResolver .getMapValueParameterType (this .methodParameter );
531
527
}
532
528
else if (this .value instanceof Map <?, ?>) {
533
- Map <?, ?> map = (Map <?, ?>) this .value ;
534
- if (!map .isEmpty ()) {
535
- Object val = map .values ().iterator ().next ();
536
- if (val != null ) {
537
- return val .getClass ();
538
- }
529
+ Class <?> valueType = CollectionUtils .findCommonElementType (((Map <?, ?>) this .value ).values ());
530
+ if (valueType != null ) {
531
+ return valueType ;
539
532
}
540
533
}
541
534
return (isMap () && this .type != null ? GenericCollectionTypeResolver .getMapValueType ((Class <? extends Map >) this .type ) : null );
542
535
}
543
-
536
+
544
537
private Annotation [] resolveAnnotations () {
545
538
if (this .field != null ) {
546
539
return this .field .getAnnotations ();
0 commit comments