1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 package org.nuiton.util;
24
25 import org.apache.commons.logging.Log;
26 import org.apache.commons.logging.LogFactory;
27
28 import java.lang.annotation.Annotation;
29 import java.lang.reflect.Field;
30 import java.lang.reflect.Method;
31 import java.lang.reflect.Modifier;
32 import java.util.ArrayList;
33 import java.util.Arrays;
34 import java.util.HashMap;
35 import java.util.HashSet;
36 import java.util.List;
37 import java.util.Map;
38 import java.util.Set;
39
40 import static org.nuiton.i18n.I18n.t;
41
42
43
44
45
46
47
48
49
50
51 public class ReflectUtil {
52
53
54
55 private static final Log log = LogFactory.getLog(ReflectUtil.class);
56
57
58
59
60
61
62
63
64 public static boolean isConstantField(Field field) {
65 int modifiers = field.getModifiers();
66 return Modifier.isPublic(modifiers) &&
67 Modifier.isStatic(modifiers) &&
68 Modifier.isFinal(modifiers);
69 }
70
71
72
73
74
75
76
77
78
79
80
81
82
83 @SuppressWarnings({"unchecked"})
84 public static <T> List<T> getConstants(Class<?> klass,
85 Class<T> searchingClass) {
86 List<T> result = new ArrayList<T>();
87 for (Field field : klass.getDeclaredFields()) {
88 if (!field.isAccessible()) {
89 field.setAccessible(true);
90 }
91 if (searchingClass.isAssignableFrom(field.getType()) &&
92 isConstantField(field)) {
93 try {
94 result.add((T) field.get(null));
95 } catch (IllegalAccessException e) {
96 throw new RuntimeException(e);
97 }
98 }
99 }
100 Class<?> superClass = klass.getSuperclass();
101 if (superClass != null) {
102 result.addAll(getConstants(superClass, searchingClass));
103 }
104 return result;
105 }
106
107
108
109
110
111
112
113 @SuppressWarnings({"unchecked"})
114 public static <T> T getConstant(Class<?> klass, String fieldName) {
115 try {
116 T result = null;
117 Field f = klass.getDeclaredField(fieldName);
118 if (isConstantField(f)) {
119 f.setAccessible(true);
120 result = (T) f.get(null);
121 }
122 return result;
123 } catch (NoSuchFieldException e) {
124 throw new RuntimeException(e);
125 } catch (IllegalAccessException e) {
126 throw new RuntimeException(e);
127 }
128 }
129
130
131
132
133
134
135
136
137
138
139 @SuppressWarnings({"unchecked"})
140 public static <T extends Enum<T>> Class<T> getEnumClass(Class<?> type) throws IllegalArgumentException {
141 if (type == null) {
142 throw new IllegalArgumentException(t("nuitonutil.error.null.parameter", "type"));
143 }
144 if (!type.isEnum()) {
145 throw new IllegalArgumentException(t("nuitonutil.error.not.an.enum", type));
146 }
147 return (Class<T>) type;
148 }
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163 public static Method getDeclaredMethod(Class<?> klass,
164 String methodName,
165 boolean strict,
166 Object... arguments) throws IllegalArgumentException {
167 HashSet<Class<?>> classes = new HashSet<Class<?>>();
168 Method method;
169 try {
170 method = getDeclaredMethod(klass, methodName, classes, arguments);
171 } finally {
172 if (log.isDebugEnabled()) {
173 log.debug("Inspected classes : " + classes);
174 }
175 classes.clear();
176 }
177 if (method == null && strict) {
178 throw new IllegalArgumentException(
179 "could not find method " + methodName + " on type " +
180 klass.getName());
181 }
182
183 return method;
184 }
185
186
187
188
189
190
191
192
193
194
195
196 public static Class<?> boxType(Class<?> type) {
197 if (!type.isPrimitive()) {
198 return type;
199 }
200 if (boolean.class.equals(type)) {
201 return Boolean.class;
202 }
203 if (char.class.equals(type)) {
204 return Character.class;
205 }
206 if (byte.class.equals(type)) {
207 return Byte.class;
208 }
209 if (short.class.equals(type)) {
210 return Short.class;
211 }
212 if (int.class.equals(type)) {
213 return Integer.class;
214 }
215 if (long.class.equals(type)) {
216 return Long.class;
217 }
218 if (float.class.equals(type)) {
219 return Float.class;
220 }
221 if (double.class.equals(type)) {
222 return Double.class;
223 }
224 if (void.class.equals(type)) {
225 return Void.class;
226 }
227
228 return type;
229
230 }
231
232
233
234
235
236
237
238
239
240
241
242 public static Class<?> unboxType(Class<?> type) {
243 if (type.isPrimitive()) {
244 return type;
245 }
246 if (Boolean.class.equals(type)) {
247 return boolean.class;
248 }
249 if (Character.class.equals(type)) {
250 return char.class;
251 }
252 if (Byte.class.equals(type)) {
253 return byte.class;
254 }
255 if (Short.class.equals(type)) {
256 return short.class;
257 }
258 if (Integer.class.equals(type)) {
259 return int.class;
260 }
261 if (Long.class.equals(type)) {
262 return long.class;
263 }
264 if (Float.class.equals(type)) {
265 return float.class;
266 }
267 if (Double.class.equals(type)) {
268 return double.class;
269 }
270 if (Void.class.equals(type)) {
271 return void.class;
272 }
273
274
275 return type;
276 }
277
278
279
280
281
282
283
284
285
286
287
288 public static Set<Field> getAllDeclaredFields(Class<?> objectClass) {
289 Set<Field> result = new HashSet<Field>();
290 Set<Class<?>> visitedClasses = new HashSet<Class<?>>();
291
292 try {
293 getAllDeclaredFields(objectClass, visitedClasses, result);
294 } finally {
295 visitedClasses.clear();
296 }
297 return result;
298 }
299
300
301
302
303
304
305
306
307
308
309
310 public static Set<Method> getAllDeclaredMethods(Class<?> objectClass) {
311 Set<Method> result = new HashSet<Method>();
312 Set<Class<?>> visitedClasses = new HashSet<Class<?>>();
313
314 try {
315 getAllDeclaredMethods(objectClass, visitedClasses, result);
316 } finally {
317 visitedClasses.clear();
318 }
319 return result;
320 }
321
322
323
324
325
326
327
328
329
330
331
332
333
334 public static <A extends Annotation> Map<Field, A> getFieldAnnotation(Class<?> objectClass,
335 Class<A> annotationClass) {
336 Map<Field, A> result = getFieldAnnotation(objectClass,
337 annotationClass,
338 false
339 );
340 return result;
341 }
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360 public static <A extends Annotation> Map<Field, A> getFieldAnnotation(Class<?> objectClass,
361 Class<A> annotationClass,
362 boolean deepVisit) {
363
364 Map<Field, A> result = new HashMap<Field, A>();
365 Set<Class<?>> visitedClasses = new HashSet<Class<?>>();
366
367 try {
368 getFieldAnnotation(objectClass,
369 annotationClass,
370 deepVisit,
371 visitedClasses,
372 result
373 );
374 } finally {
375 visitedClasses.clear();
376 }
377
378 return result;
379 }
380
381
382
383
384
385
386
387
388
389
390
391
392
393 public static <A extends Annotation> Map<Method, A> getMethodAnnotation(Class<?> objectClass,
394 Class<A> annotationClass) {
395 Map<Method, A> result = getMethodAnnotation(objectClass,
396 annotationClass,
397 false
398 );
399 return result;
400 }
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419 public static <A extends Annotation> Map<Method, A> getMethodAnnotation(Class<?> objectClass,
420 Class<A> annotationClass,
421 boolean deepVisit) {
422 Map<Method, A> result = new HashMap<Method, A>();
423 Set<Class<?>> visitedClasses = new HashSet<Class<?>>();
424
425 try {
426 getMethodAnnotation(objectClass,
427 annotationClass,
428 deepVisit,
429 visitedClasses,
430 result
431 );
432 } finally {
433 visitedClasses.clear();
434 }
435 return result;
436 }
437
438 protected static Method getDeclaredMethod(Class<?> klass,
439 String methodName,
440 Set<Class<?>> visitedClasses,
441 Object... arguments) {
442 if (visitedClasses.contains(klass)) {
443
444
445 return null;
446 }
447 visitedClasses.add(klass);
448 Method method = null;
449 for (Method m : klass.getDeclaredMethods()) {
450 if (!methodName.equals(m.getName())) {
451 continue;
452 }
453
454
455
456 Class<?>[] types = m.getParameterTypes();
457 if (arguments.length != types.length) {
458 continue;
459 }
460
461
462
463 Class<?>[] prototype = m.getParameterTypes();
464 if (log.isDebugEnabled()) {
465 log.debug("Found a method with same parameters size : " +
466 m.getName() + " : " + Arrays.toString(prototype));
467 }
468 int index = 0;
469 boolean parametersMatches = true;
470 for (Object argument : arguments) {
471 Class<?> type = prototype[index++];
472 if (argument == null) {
473
474
475 continue;
476 }
477 Class<?> runtimeType = argument.getClass();
478 if (log.isDebugEnabled()) {
479 log.debug("Test parameter [" + (index - 1) + "] : " +
480 type + " vs " + runtimeType);
481 }
482
483 type = boxType(type);
484 runtimeType = boxType(runtimeType);
485
486 if (!type.equals(runtimeType) &&
487 !type.isAssignableFrom(runtimeType)) {
488
489
490 parametersMatches = false;
491 if (log.isDebugEnabled()) {
492 log.debug("Types are not matching.");
493 }
494 break;
495 }
496 }
497 if (parametersMatches) {
498
499
500 method = m;
501 }
502 break;
503 }
504 if (method == null) {
505
506
507 if (klass.getSuperclass() != null) {
508 method = getDeclaredMethod(klass.getSuperclass(),
509 methodName,
510 visitedClasses,
511 arguments
512 );
513 }
514 }
515
516 if (method == null) {
517
518
519 Class<?>[] interfaces = klass.getInterfaces();
520 for (Class<?> anInterface : interfaces) {
521 method = getDeclaredMethod(anInterface,
522 methodName,
523 visitedClasses,
524 arguments
525 );
526 if (method != null) {
527 break;
528 }
529 }
530 }
531 return method;
532
533 }
534
535 protected static void getAllDeclaredFields(Class<?> objectClass,
536 Set<Class<?>> visitedClasses,
537 Set<Field> result) {
538
539 if (visitedClasses.contains(objectClass) ||
540 Object.class.equals(objectClass)) {
541
542
543
544 return;
545 }
546
547
548 visitedClasses.add(objectClass);
549
550 Field[] declaredFields = objectClass.getDeclaredFields();
551 result.addAll(Arrays.asList(declaredFields));
552
553 Class<?> superclass = objectClass.getSuperclass();
554 if (superclass != null) {
555
556
557 getAllDeclaredFields(superclass,
558 visitedClasses,
559 result
560 );
561 }
562
563 Class<?>[] interfaces = objectClass.getInterfaces();
564
565 for (Class<?> anInterface : interfaces) {
566
567
568 getAllDeclaredFields(anInterface,
569 visitedClasses,
570 result
571 );
572 }
573
574 }
575
576 protected static void getAllDeclaredMethods(Class<?> objectClass,
577 Set<Class<?>> visitedClasses,
578 Set<Method> result) {
579
580 if (visitedClasses.contains(objectClass) ||
581 Object.class.equals(objectClass)) {
582
583
584
585 return;
586 }
587
588
589 visitedClasses.add(objectClass);
590
591 Method[] declaredFields = objectClass.getDeclaredMethods();
592 result.addAll(Arrays.asList(declaredFields));
593
594 Class<?> superclass = objectClass.getSuperclass();
595 if (superclass != null) {
596
597
598 getAllDeclaredMethods(superclass,
599 visitedClasses,
600 result
601 );
602 }
603
604 Class<?>[] interfaces = objectClass.getInterfaces();
605
606 for (Class<?> anInterface : interfaces) {
607
608
609 getAllDeclaredMethods(anInterface,
610 visitedClasses,
611 result
612 );
613 }
614
615 }
616
617 protected static <A extends Annotation> void getFieldAnnotation(Class<?> objectClass,
618 Class<A> annotationClass,
619 boolean deepVisit,
620 Set<Class<?>> visitedClasses,
621 Map<Field, A> result) {
622
623 if (visitedClasses.contains(objectClass) ||
624 Object.class.equals(objectClass)) {
625
626
627
628 return;
629 }
630
631
632 visitedClasses.add(objectClass);
633
634 for (Field field : objectClass.getDeclaredFields()) {
635 A annotation = field.getAnnotation(annotationClass);
636 if (annotation != null) {
637 result.put(field, annotation);
638 }
639 }
640
641 if (deepVisit) {
642
643 Class<?> superclass = objectClass.getSuperclass();
644 if (superclass != null) {
645
646
647 getFieldAnnotation(superclass,
648 annotationClass,
649 deepVisit,
650 visitedClasses,
651 result
652 );
653 }
654
655 Class<?>[] interfaces = objectClass.getInterfaces();
656
657 for (Class<?> anInterface : interfaces) {
658
659
660 getFieldAnnotation(anInterface,
661 annotationClass,
662 deepVisit,
663 visitedClasses,
664 result
665 );
666 }
667 }
668 }
669
670 protected static <A extends Annotation> void getMethodAnnotation(Class<?> objectClass,
671 Class<A> annotationClass,
672 boolean deepVisit,
673 Set<Class<?>> visitedClasses,
674 Map<Method, A> result) {
675
676 if (visitedClasses.contains(objectClass) ||
677 Object.class.equals(objectClass)) {
678
679
680
681 return;
682 }
683
684
685 visitedClasses.add(objectClass);
686
687 for (Method method : objectClass.getDeclaredMethods()) {
688 A annotation = method.getAnnotation(annotationClass);
689 if (annotation != null) {
690 result.put(method, annotation);
691 }
692 }
693
694 if (deepVisit) {
695
696 Class<?> superclass = objectClass.getSuperclass();
697 if (superclass != null) {
698
699
700 getMethodAnnotation(superclass,
701 annotationClass,
702 deepVisit,
703 visitedClasses,
704 result
705 );
706 }
707
708 Class<?>[] interfaces = objectClass.getInterfaces();
709
710 for (Class<?> anInterface : interfaces) {
711
712
713 getMethodAnnotation(anInterface,
714 annotationClass,
715 deepVisit,
716 visitedClasses,
717 result
718 );
719 }
720 }
721 }
722 }