18
18
19
19
import java .lang .annotation .Annotation ;
20
20
import java .lang .reflect .Array ;
21
+ import java .lang .reflect .Member ;
21
22
import java .lang .reflect .Method ;
23
+ import java .util .Arrays ;
22
24
import java .util .Collections ;
25
+ import java .util .HashMap ;
23
26
import java .util .LinkedHashMap ;
24
27
import java .util .List ;
25
28
import java .util .Map ;
68
71
*/
69
72
final class TypeMappedAnnotation <A extends Annotation > extends AbstractMergedAnnotation <A > {
70
73
74
+ private static final Object [] EMPTY_OBJECT_ARRAY = {};
75
+
76
+ private static final Map <Class <?>, Object > EMPTY_ARRAYS ;
77
+ static {
78
+ Map <Class <?>, Object > emptyArrays = new HashMap <>();
79
+ emptyArrays .put (String .class , new String [] {});
80
+ emptyArrays .put (boolean .class , new boolean [] {});
81
+ emptyArrays .put (byte .class , new byte [] {});
82
+ emptyArrays .put (char .class , new char [] {});
83
+ emptyArrays .put (double .class , new double [] {});
84
+ emptyArrays .put (float .class , new float [] {});
85
+ emptyArrays .put (int .class , new int [] {});
86
+ emptyArrays .put (long .class , new long [] {});
87
+ emptyArrays .put (short .class , new short [] {});
88
+ EMPTY_ARRAYS = Collections .unmodifiableMap (emptyArrays );
89
+ }
90
+
71
91
private final AnnotationTypeMapping mapping ;
72
92
93
+ @ Nullable
94
+ private final ClassLoader classLoader ;
95
+
73
96
@ Nullable
74
97
private final Object source ;
75
98
@@ -93,21 +116,23 @@ final class TypeMappedAnnotation<A extends Annotation> extends AbstractMergedAnn
93
116
private String string ;
94
117
95
118
96
- private TypeMappedAnnotation (AnnotationTypeMapping mapping , @ Nullable Object source ,
97
- @ Nullable Object rootAttributes , BiFunction < Method , Object , Object > valueExtractor ,
98
- int aggregateIndex ) {
119
+ private TypeMappedAnnotation (AnnotationTypeMapping mapping , @ Nullable ClassLoader classLoader ,
120
+ @ Nullable Object source , @ Nullable Object rootAttributes ,
121
+ BiFunction < Method , Object , Object > valueExtractor , int aggregateIndex ) {
99
122
100
- this (mapping , source , rootAttributes , valueExtractor , aggregateIndex , null );
123
+ this (mapping , classLoader , source , rootAttributes , valueExtractor , aggregateIndex , null );
101
124
}
102
125
103
- private TypeMappedAnnotation (AnnotationTypeMapping mapping , @ Nullable Object source ,
104
- @ Nullable Object rootAttributes , BiFunction <Method , Object , Object > valueExtractor ,
105
- int aggregateIndex , @ Nullable int [] resolvedRootMirrors ) {
126
+ private TypeMappedAnnotation (AnnotationTypeMapping mapping , @ Nullable ClassLoader classLoader ,
127
+ @ Nullable Object source , @ Nullable Object rootAttributes ,
128
+ BiFunction <Method , Object , Object > valueExtractor , int aggregateIndex ,
129
+ @ Nullable int [] resolvedRootMirrors ) {
106
130
131
+ this .mapping = mapping ;
132
+ this .classLoader = classLoader ;
107
133
this .source = source ;
108
134
this .rootAttributes = rootAttributes ;
109
135
this .valueExtractor = valueExtractor ;
110
- this .mapping = mapping ;
111
136
this .aggregateIndex = aggregateIndex ;
112
137
this .useMergedValues = true ;
113
138
this .attributeFilter = null ;
@@ -117,11 +142,13 @@ private TypeMappedAnnotation(AnnotationTypeMapping mapping, @Nullable Object sou
117
142
mapping .getMirrorSets ().resolve (source , this , this ::getValueForMirrorResolution ));
118
143
}
119
144
120
- private TypeMappedAnnotation (AnnotationTypeMapping mapping , @ Nullable Object source ,
121
- @ Nullable Object rootAnnotation , BiFunction <Method , Object , Object > valueExtractor ,
122
- int aggregateIndex , boolean useMergedValues , @ Nullable Predicate <String > attributeFilter ,
145
+ private TypeMappedAnnotation (AnnotationTypeMapping mapping , @ Nullable ClassLoader classLoader ,
146
+ @ Nullable Object source , @ Nullable Object rootAnnotation ,
147
+ BiFunction <Method , Object , Object > valueExtractor , int aggregateIndex ,
148
+ boolean useMergedValues , @ Nullable Predicate <String > attributeFilter ,
123
149
int [] resolvedRootMirrors , int [] resolvedMirrors ) {
124
150
151
+ this .classLoader = classLoader ;
125
152
this .source = source ;
126
153
this .rootAttributes = rootAnnotation ;
127
154
this .valueExtractor = valueExtractor ;
@@ -173,7 +200,7 @@ public MergedAnnotation<?> getParent() {
173
200
if (parentMapping == null ) {
174
201
return null ;
175
202
}
176
- return new TypeMappedAnnotation <>(parentMapping , this .source , this .rootAttributes ,
203
+ return new TypeMappedAnnotation <>(parentMapping , this .classLoader , this . source , this .rootAttributes ,
177
204
this .valueExtractor , this .aggregateIndex , this .resolvedRootMirrors );
178
205
}
179
206
@@ -183,7 +210,7 @@ public MergedAnnotation<?> getRoot() {
183
210
return this ;
184
211
}
185
212
AnnotationTypeMapping rootMapping = this .mapping .getRoot ();
186
- return new TypeMappedAnnotation <>(rootMapping , this .source , this .rootAttributes ,
213
+ return new TypeMappedAnnotation <>(rootMapping , this .classLoader , this . source , this .rootAttributes ,
187
214
this .valueExtractor , this .aggregateIndex , this .resolvedRootMirrors );
188
215
}
189
216
@@ -204,7 +231,7 @@ public <T extends Annotation> MergedAnnotation<T> getAnnotation(String attribute
204
231
Assert .notNull (type , "Type must not be null" );
205
232
Assert .isAssignable (type , attribute .getReturnType (),
206
233
() -> "Attribute " + attributeName + " type mismatch:" );
207
- return (MergedAnnotation <T >) getRequiredValue (attributeIndex );
234
+ return (MergedAnnotation <T >) getRequiredValue (attributeIndex , attributeName );
208
235
}
209
236
210
237
@ Override
@@ -218,7 +245,7 @@ public <T extends Annotation> MergedAnnotation<T>[] getAnnotationArray(
218
245
Assert .notNull (type , "Type must not be null" );
219
246
Assert .notNull (componentType , () -> "Attribute " + attributeName + " is not an array" );
220
247
Assert .isAssignable (type , componentType , () -> "Attribute " + attributeName + " component type mismatch:" );
221
- return (MergedAnnotation <T >[]) getRequiredValue (attributeIndex );
248
+ return (MergedAnnotation <T >[]) getRequiredValue (attributeIndex , attributeName );
222
249
}
223
250
224
251
@ Override
@@ -236,14 +263,14 @@ public MergedAnnotation<A> filterAttributes(Predicate<String> predicate) {
236
263
if (this .attributeFilter != null ) {
237
264
predicate = this .attributeFilter .and (predicate );
238
265
}
239
- return new TypeMappedAnnotation <>(this .mapping , this .source , this .rootAttributes ,
266
+ return new TypeMappedAnnotation <>(this .mapping , this .classLoader , this . source , this .rootAttributes ,
240
267
this .valueExtractor , this .aggregateIndex , this .useMergedValues , predicate ,
241
268
this .resolvedRootMirrors , this .resolvedMirrors );
242
269
}
243
270
244
271
@ Override
245
272
public MergedAnnotation <A > withNonMergedAttributes () {
246
- return new TypeMappedAnnotation <>(this .mapping , this .source , this .rootAttributes ,
273
+ return new TypeMappedAnnotation <>(this .mapping , this .classLoader , this . source , this .rootAttributes ,
247
274
this .valueExtractor , this .aggregateIndex , false , this .attributeFilter ,
248
275
this .resolvedRootMirrors , this .resolvedMirrors );
249
276
}
@@ -359,10 +386,11 @@ protected <T> T getAttributeValue(String attributeName, Class<T> type) {
359
386
return (attributeIndex != -1 ? getValue (attributeIndex , type ) : null );
360
387
}
361
388
362
- private final Object getRequiredValue (int attributeIndex ) {
389
+ private final Object getRequiredValue (int attributeIndex , String attributeName ) {
363
390
Object value = getValue (attributeIndex , Object .class );
364
391
if (value == null ) {
365
- throw new NoSuchElementException ("No element at attribute index " + attributeIndex );
392
+ throw new NoSuchElementException ("No element at attribute index "
393
+ + attributeIndex + " for name " + attributeName );
366
394
}
367
395
return value ;
368
396
}
@@ -400,7 +428,8 @@ private Object getValue(int attributeIndex, boolean useConventionMapping, boolea
400
428
}
401
429
if (mapping .getDepth () == 0 ) {
402
430
Method attribute = mapping .getAttributes ().get (attributeIndex );
403
- return this .valueExtractor .apply (attribute , this .rootAttributes );
431
+ Object result = this .valueExtractor .apply (attribute , this .rootAttributes );
432
+ return (result != null ) ? result : attribute .getDefaultValue ();
404
433
}
405
434
return getValueFromMetaAnnotation (attributeIndex , forMirrorResolution );
406
435
}
@@ -430,12 +459,13 @@ private <T> T adapt(Method attribute, @Nullable Object value, Class<T> type) {
430
459
return null ;
431
460
}
432
461
value = adaptForAttribute (attribute , value );
433
- if (type == Object .class ) {
434
- type = (Class <T >) getDefaultAdaptType (attribute );
435
- }
436
- else if (value instanceof Class && type == String .class ) {
462
+ type = getAdaptType (attribute , type );
463
+ if (value instanceof Class && type == String .class ) {
437
464
value = ((Class <?>) value ).getName ();
438
465
}
466
+ else if (value instanceof String && type == Class .class ) {
467
+ value = ClassUtils .resolveClassName ((String ) value , getClassLoader ());
468
+ }
439
469
else if (value instanceof Class [] && type == String [].class ) {
440
470
Class <?>[] classes = (Class []) value ;
441
471
String [] names = new String [classes .length ];
@@ -444,6 +474,14 @@ else if (value instanceof Class[] && type == String[].class) {
444
474
}
445
475
value = names ;
446
476
}
477
+ else if (value instanceof String [] && type == Class [].class ) {
478
+ String [] names = (String []) value ;
479
+ Class <?>[] classes = new Class <?>[names .length ];
480
+ for (int i = 0 ; i < names .length ; i ++) {
481
+ classes [i ] = ClassUtils .resolveClassName (names [i ], getClassLoader ());
482
+ }
483
+ value = classes ;
484
+ }
447
485
else if (value instanceof MergedAnnotation && type .isAnnotation ()) {
448
486
MergedAnnotation <?> annotation = (MergedAnnotation <?>) value ;
449
487
value = annotation .synthesize ();
@@ -484,9 +522,14 @@ private Object adaptForAttribute(Method attribute, Object value) {
484
522
return result ;
485
523
}
486
524
if ((attributeType == Class .class && value instanceof String ) ||
487
- (attributeType == Class [].class && value instanceof String [])) {
525
+ (attributeType == Class [].class && value instanceof String []) ||
526
+ (attributeType == String .class && value instanceof Class ) ||
527
+ (attributeType == String [].class && value instanceof Class [])) {
488
528
return value ;
489
529
}
530
+ if (attributeType .isArray () && isEmptyObjectArray (value )) {
531
+ return emptyArray (attributeType .getComponentType ());
532
+ }
490
533
if (!attributeType .isInstance (value )) {
491
534
throw new IllegalStateException ("Attribute '" + attribute .getName () +
492
535
"' in annotation " + getType ().getName () + " should be compatible with " +
@@ -496,9 +539,24 @@ private Object adaptForAttribute(Method attribute, Object value) {
496
539
return value ;
497
540
}
498
541
542
+ private boolean isEmptyObjectArray (Object value ) {
543
+ return value instanceof Object [] && Arrays .equals ((Object []) value , EMPTY_OBJECT_ARRAY );
544
+ }
545
+
546
+ private Object emptyArray (Class <?> componentType ) {
547
+ Object result = EMPTY_ARRAYS .get (componentType );
548
+ if (result == null ) {
549
+ result = Array .newInstance (componentType , 0 );
550
+ }
551
+ return result ;
552
+ }
553
+
499
554
private MergedAnnotation <?> adaptToMergedAnnotation (Object value , Class <? extends Annotation > annotationType ) {
555
+ if (value instanceof MergedAnnotation ) {
556
+ return (MergedAnnotation <?>) value ;
557
+ }
500
558
AnnotationTypeMapping mapping = AnnotationTypeMappings .forAnnotationType (annotationType ).get (0 );
501
- return new TypeMappedAnnotation <>(mapping , this .source , value , getValueExtractor (value ), this .aggregateIndex );
559
+ return new TypeMappedAnnotation <>(mapping , null , this .source , value , getValueExtractor (value ), this .aggregateIndex );
502
560
}
503
561
504
562
private BiFunction <Method , Object , Object > getValueExtractor (Object value ) {
@@ -511,15 +569,19 @@ private BiFunction<Method, Object, Object> getValueExtractor(Object value) {
511
569
return this .valueExtractor ;
512
570
}
513
571
514
- private Class <?> getDefaultAdaptType (Method attribute ) {
572
+ @ SuppressWarnings ("unchecked" )
573
+ private <T > Class <T > getAdaptType (Method attribute , Class <T > type ) {
574
+ if (type != Object .class ) {
575
+ return type ;
576
+ }
515
577
Class <?> attributeType = attribute .getReturnType ();
516
578
if (attributeType .isAnnotation ()) {
517
- return MergedAnnotation .class ;
579
+ return ( Class < T >) MergedAnnotation .class ;
518
580
}
519
581
if (attributeType .isArray () && attributeType .getComponentType ().isAnnotation ()) {
520
- return MergedAnnotation [].class ;
582
+ return ( Class < T >) MergedAnnotation [].class ;
521
583
}
522
- return ClassUtils .resolvePrimitiveIfNecessary (attributeType );
584
+ return ( Class < T >) ClassUtils .resolvePrimitiveIfNecessary (attributeType );
523
585
}
524
586
525
587
private int getAttributeIndex (String attributeName , boolean required ) {
@@ -540,30 +602,71 @@ private boolean isFiltered(String attributeName) {
540
602
return false ;
541
603
}
542
604
605
+ @ Nullable
606
+ private ClassLoader getClassLoader () {
607
+ if (this .classLoader != null ) {
608
+ return this .classLoader ;
609
+ }
610
+ if (this .source != null ) {
611
+ if (this .source instanceof Class ) {
612
+ return ((Class <?>) source ).getClassLoader ();
613
+ }
614
+ if (this .source instanceof Member ) {
615
+ ((Member ) this .source ).getDeclaringClass ().getClassLoader ();
616
+ }
617
+ }
618
+ return null ;
619
+ }
620
+
543
621
544
622
static <A extends Annotation > MergedAnnotation <A > from (@ Nullable Object source , A annotation ) {
545
623
Assert .notNull (annotation , "Annotation must not be null" );
546
624
AnnotationTypeMappings mappings = AnnotationTypeMappings .forAnnotationType (annotation .annotationType ());
547
- return new TypeMappedAnnotation <>(mappings .get (0 ), source , annotation , ReflectionUtils ::invokeMethod , 0 );
625
+ return new TypeMappedAnnotation <>(mappings .get (0 ), null , source , annotation , ReflectionUtils ::invokeMethod , 0 );
548
626
}
549
627
550
- static <A extends Annotation > MergedAnnotation <A > of (@ Nullable Object source ,
628
+ static <A extends Annotation > MergedAnnotation <A > of (
629
+ @ Nullable ClassLoader classLoader , @ Nullable Object source ,
551
630
Class <A > annotationType , @ Nullable Map <String , ?> attributes ) {
552
631
553
632
Assert .notNull (annotationType , "Annotation type must not be null" );
554
633
AnnotationTypeMappings mappings = AnnotationTypeMappings .forAnnotationType (annotationType );
555
634
return new TypeMappedAnnotation <>(
556
- mappings .get (0 ), source , attributes , TypeMappedAnnotation ::extractFromMap , 0 );
635
+ mappings .get (0 ), classLoader , source , attributes , TypeMappedAnnotation ::extractFromMap , 0 );
636
+ }
637
+
638
+ @ Nullable
639
+ static <A extends Annotation > TypeMappedAnnotation <A > createIfPossible (
640
+ AnnotationTypeMapping mapping , MergedAnnotation <?> annotation , IntrospectionFailureLogger logger ) {
641
+ if (annotation instanceof TypeMappedAnnotation ) {
642
+ TypeMappedAnnotation <?> typeMappedAnnotation = (TypeMappedAnnotation <?>) annotation ;
643
+ return createIfPossible (mapping , typeMappedAnnotation .source ,
644
+ typeMappedAnnotation .rootAttributes ,
645
+ typeMappedAnnotation .valueExtractor ,
646
+ typeMappedAnnotation .aggregateIndex , logger );
647
+ }
648
+ return createIfPossible (mapping , annotation .getSource (), annotation .synthesize (),
649
+ annotation .getAggregateIndex (), logger );
557
650
}
558
651
559
652
@ Nullable
560
653
static <A extends Annotation > TypeMappedAnnotation <A > createIfPossible (
561
654
AnnotationTypeMapping mapping , @ Nullable Object source , Annotation annotation ,
562
655
int aggregateIndex , IntrospectionFailureLogger logger ) {
563
656
657
+ return createIfPossible (mapping , source , annotation ,
658
+ ReflectionUtils ::invokeMethod , aggregateIndex , logger );
659
+ }
660
+
661
+ @ Nullable
662
+ static <A extends Annotation > TypeMappedAnnotation <A > createIfPossible (
663
+ AnnotationTypeMapping mapping , @ Nullable Object source , Object rootAttribute ,
664
+ BiFunction <Method , Object , Object > valueExtractor ,
665
+ int aggregateIndex , IntrospectionFailureLogger logger ) {
666
+
564
667
try {
565
- return new TypeMappedAnnotation <>(mapping , source , annotation ,
566
- ReflectionUtils :: invokeMethod , aggregateIndex );
668
+ return new TypeMappedAnnotation <>(mapping , null , source , rootAttribute ,
669
+ valueExtractor , aggregateIndex );
567
670
}
568
671
catch (Exception ex ) {
569
672
if (ex instanceof AnnotationConfigurationException ) {
0 commit comments