1
2
3
4
5
6
7
8
9
10
11
12 package org.hyphenType.util;
13
14 import java.lang.annotation.Annotation;
15 import java.lang.reflect.Array;
16 import java.lang.reflect.Field;
17 import java.lang.reflect.InvocationHandler;
18 import java.lang.reflect.InvocationTargetException;
19 import java.lang.reflect.Method;
20 import java.lang.reflect.Proxy;
21 import java.util.ArrayList;
22 import java.util.Arrays;
23 import java.util.Hashtable;
24 import java.util.ResourceBundle;
25
26 import org.hyphenType.util.soc.StringObjectConversion;
27 import org.hyphenType.util.soc.StringParsingError;
28
29
30
31
32 public final class DefaultAnnotation implements InvocationHandler {
33
34
35
36
37
38 public static final String METHOD_SEPARATOR = ".";
39 public static final String FIELD_SEPARATOR = ".";
40 public static final String ANNOTATION_SEPARATOR = "@";
41
42
43
44
45
46 @SuppressWarnings("unchecked")
47 public static Annotation[] getAnnotations(final Class clazz) {
48
49 Annotation[] annotations = clazz.getAnnotations();
50 Annotation[] result = new Annotation[annotations.length];
51 for (int i = 0; i < annotations.length; i++) {
52 result[i] = getAnnotation(clazz, annotations[i].annotationType());
53 }
54 return result;
55 }
56
57
58
59
60
61
62
63
64
65
66 @SuppressWarnings("unchecked")
67 public static <T extends Annotation> T getAnnotation(final Class clazz, final Class<T> annotationClass) {
68
69 Class proxyClass = Proxy.getProxyClass(DefaultAnnotation.class.getClassLoader(), new Class[] { annotationClass });
70 try {
71 return (T) proxyClass.getConstructor(new Class[] { InvocationHandler.class }).newInstance(new Object[] { new DefaultAnnotation(annotationClass, clazz.getAnnotation(annotationClass), clazz) });
72 } catch (IllegalArgumentException e) {
73 e.printStackTrace();
74 } catch (SecurityException e) {
75 e.printStackTrace();
76 } catch (InstantiationException e) {
77 e.printStackTrace();
78 } catch (IllegalAccessException e) {
79 e.printStackTrace();
80 } catch (InvocationTargetException e) {
81 e.printStackTrace();
82 } catch (NoSuchMethodException e) {
83 e.printStackTrace();
84 }
85
86
87
88 return null;
89 }
90
91
92
93
94
95
96 public static Annotation[] getAnnotations(final Method method) {
97
98 Annotation[] annotations = method.getAnnotations();
99 Annotation[] result = new Annotation[annotations.length];
100 for (int i = 0; i < annotations.length; i++) {
101 result[i] = getAnnotation(method, annotations[i].annotationType());
102 }
103 return result;
104 }
105
106
107
108
109
110
111
112
113
114
115 @SuppressWarnings("unchecked")
116 public static <T extends Annotation> T getAnnotation(final Method method, final Class<T> annotationClass) {
117
118 Class proxyClass = Proxy.getProxyClass(DefaultAnnotation.class.getClassLoader(), new Class[] { annotationClass });
119 try {
120 return (T) proxyClass.getConstructor(new Class[] { InvocationHandler.class }).newInstance(new Object[] { new DefaultAnnotation(annotationClass, method.getAnnotation(annotationClass), method) });
121 } catch (IllegalArgumentException e) {
122 e.printStackTrace();
123 } catch (SecurityException e) {
124 e.printStackTrace();
125 } catch (InstantiationException e) {
126 e.printStackTrace();
127 } catch (IllegalAccessException e) {
128 e.printStackTrace();
129 } catch (InvocationTargetException e) {
130 e.printStackTrace();
131 } catch (NoSuchMethodException e) {
132 e.printStackTrace();
133 }
134
135
136
137 return null;
138 }
139
140
141
142
143
144
145 public static Annotation[] getAnnotations(final Field field) {
146
147 Annotation[] annotations = field.getAnnotations();
148 Annotation[] result = new Annotation[annotations.length];
149 for (int i = 0; i < annotations.length; i++) {
150 result[i] = getAnnotation(field, annotations[i].annotationType());
151 }
152 return result;
153 }
154
155
156
157
158
159
160
161
162
163
164 @SuppressWarnings("unchecked")
165 public static <T extends Annotation> T getAnnotation(final Field field, final Class<T> annotationClass) {
166
167 Class proxyClass = Proxy.getProxyClass(DefaultAnnotation.class.getClassLoader(), new Class[] { annotationClass });
168 try {
169 return (T) proxyClass.getConstructor(new Class[] { InvocationHandler.class }).newInstance(new Object[] { new DefaultAnnotation(annotationClass, field.getAnnotation(annotationClass), field) });
170 } catch (IllegalArgumentException e) {
171 e.printStackTrace();
172 } catch (SecurityException e) {
173 e.printStackTrace();
174 } catch (InstantiationException e) {
175 e.printStackTrace();
176 } catch (IllegalAccessException e) {
177 e.printStackTrace();
178 } catch (InvocationTargetException e) {
179 e.printStackTrace();
180 } catch (NoSuchMethodException e) {
181 e.printStackTrace();
182 }
183
184
185
186 return null;
187 }
188
189
190
191
192
193
194 public static Annotation[] getAnnotations(final Enum<?> enumConstant) {
195 Field f;
196 try {
197 f = enumConstant.getClass().getField(enumConstant.name());
198 } catch (SecurityException e) {
199 e.printStackTrace();
200 return null;
201 } catch (NoSuchFieldException e) {
202 e.printStackTrace();
203 return null;
204 }
205
206 return getAnnotations(f);
207 }
208
209
210
211
212
213
214
215
216
217
218 public static <T extends Annotation> T getAnnotation(final Enum<?> enumConstant, final Class<T> annotationClass) {
219 Field f;
220 try {
221 f = enumConstant.getClass().getField(enumConstant.name());
222 } catch (SecurityException e) {
223 e.printStackTrace();
224 return null;
225 } catch (NoSuchFieldException e) {
226 e.printStackTrace();
227 return null;
228 }
229
230 return getAnnotation(f, annotationClass);
231 }
232
233
234
235
236
237
238
239
240 @SuppressWarnings("unchecked")
241 public static <T extends Annotation> T getAnnotationWithDefaults(final Class<? extends Annotation> annotationClass) {
242 try {
243 Class proxyClass = Proxy.getProxyClass(DefaultAnnotation.class.getClassLoader(), new Class[] { annotationClass });
244 return (T) proxyClass.getConstructor(new Class[] { InvocationHandler.class }).newInstance(new Object[] { new DefaultAnnotation(annotationClass) });
245 } catch (Exception e) {
246 e.printStackTrace();
247 return null;
248 }
249 }
250
251
252
253
254
255
256
257
258
259 public static void set(final Annotation annotation, final Method method, final Object value) {
260
261 if (!isDefaultAnnotation(annotation)) {
262 throw new IllegalArgumentException("The first argument should be an annotation retrieved from " + DefaultAnnotation.class.getName());
263 }
264 DefaultAnnotation da = (DefaultAnnotation) Proxy.getInvocationHandler(annotation);
265 da.values.put(method, value);
266 }
267
268
269
270
271
272
273
274
275
276 public static void set(final Annotation annotation, final String methodName, final Object value) {
277
278 Method method;
279
280 try {
281 method = annotation.annotationType().getMethod(methodName);
282 } catch (SecurityException e) {
283 throw new IllegalArgumentException(e);
284 } catch (NoSuchMethodException e) {
285 throw new IllegalArgumentException(e);
286 }
287
288 InvocationHandler ih = Proxy.getInvocationHandler(annotation);
289 if (!(ih instanceof DefaultAnnotation)) {
290 throw new IllegalArgumentException("The first argument should be an annotation retrieved from " + DefaultAnnotation.class.getName());
291 }
292 DefaultAnnotation da = (DefaultAnnotation) ih;
293 da.values.put(method, value);
294 }
295
296
297
298
299
300
301
302 public static void fillWithResourceBundle(final Annotation annotation, final ResourceBundle resourceBundle) {
303 recursiveFillWithResourceBundle(annotation, resourceBundle, annotation.annotationType().getName());
304 }
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320 @SuppressWarnings("unchecked")
321 private static void recursiveFillWithResourceBundle(final Annotation annotation, final ResourceBundle resourceBundle, final String key) {
322
323 Class<? extends Annotation> anClass = annotation.annotationType();
324 DefaultAnnotation defaultAnnotation = (DefaultAnnotation) Proxy.getInvocationHandler(annotation);
325
326 for (Method method : anClass.getDeclaredMethods()) {
327
328 String newkey = key + METHOD_SEPARATOR + method.getName();
329 if (method.getReturnType().isAnnotation()) {
330 Annotation subAnnotation = (Annotation) defaultAnnotation.values.get(method);
331 recursiveFillWithResourceBundle(subAnnotation, resourceBundle, newkey);
332 set(annotation, method, subAnnotation);
333 } else {
334 try {
335
336 if (method.getReturnType().isArray()) {
337
338 if (method.getReturnType().getComponentType().isAnnotation()) {
339
340
341
342
343
344
345
346
347
348
349 Object array = defaultAnnotation.invoke(null, method, new Object[] {});
350
351 int i = 0;
352 String arrayKey = newkey + "[" + i + "]";
353 boolean hasPrefix = hasPrefix(resourceBundle, arrayKey);
354
355 ArrayList<Annotation> newArrayValue = new ArrayList<Annotation>();
356
357
358
359
360
361
362
363
364 if (array == null) {
365 while (hasPrefix) {
366 Annotation subAnnotation = DefaultAnnotation.getAnnotationWithDefaults((Class<? extends Annotation>) method.getReturnType().getComponentType());
367 recursiveFillWithResourceBundle(subAnnotation, resourceBundle, arrayKey);
368 newArrayValue.add(subAnnotation);
369 i++;
370 arrayKey = newkey + "[" + i + "]";
371 hasPrefix = hasPrefix(resourceBundle, arrayKey);
372 }
373 } else {
374 while (hasPrefix || i < Array.getLength(array)) {
375 if (i >= Array.getLength(array)) {
376
377 Annotation subAnnotation = DefaultAnnotation.getAnnotationWithDefaults((Class<? extends Annotation>) method.getReturnType().getComponentType());
378 recursiveFillWithResourceBundle(subAnnotation, resourceBundle, arrayKey);
379 newArrayValue.add(subAnnotation);
380 } else if (hasPrefix) {
381
382 Annotation subAnnotation = (Annotation) Array.get(array, i);
383 recursiveFillWithResourceBundle(subAnnotation, resourceBundle, arrayKey);
384 newArrayValue.add(subAnnotation);
385 } else {
386
387 newArrayValue.add((Annotation) Array.get(array, i));
388 }
389 i++;
390 arrayKey = newkey + "[" + i + "]";
391 hasPrefix = hasPrefix(resourceBundle, arrayKey);
392 }
393 }
394
395
396 defaultAnnotation.values.put(method, newArrayValue.toArray((Object[]) Array.newInstance(method.getReturnType().getComponentType(), newArrayValue.size())));
397 } else {
398
399
400
401
402 if(resourceBundle.containsKey(defaultAnnotation.getBasePrefix() + newkey)) {
403 set(annotation, method, StringObjectConversion.fromString(method.getReturnType(), resourceBundle.getString(defaultAnnotation.getBasePrefix() + newkey)));
404 }
405
406
407
408
409
410 else {
411 ArrayList<String> value = new ArrayList<String>();
412 int i = 0;
413 String arrayKey = newkey + "[" + i + "]";
414 while (resourceBundle.containsKey(arrayKey)) {
415 value.add(resourceBundle.getString(arrayKey));
416 i++;
417 arrayKey = newkey + "[" + i + "]";
418 }
419
420 if (value.size() > 0) {
421 Object[] array = (Object[]) Array.newInstance(method.getReturnType().getComponentType(), value.size());
422 set(annotation, method, value.toArray(array));
423 }
424 }
425 }
426 } else {
427 if(resourceBundle.containsKey(defaultAnnotation.getBasePrefix() + newkey)) {
428 set(annotation, method, StringObjectConversion.fromString(method.getReturnType(), resourceBundle.getString(defaultAnnotation.getBasePrefix() + newkey)));
429 } else if (resourceBundle.containsKey(newkey)) {
430 set(annotation, method, StringObjectConversion.fromString(method.getReturnType(), resourceBundle.getString(newkey)));
431 }
432 }
433 } catch (StringParsingError e) {
434 e.printStackTrace();
435 } catch (IllegalArgumentException e) {
436 e.printStackTrace();
437 } catch (IllegalAccessException e) {
438 e.printStackTrace();
439 } catch (InvocationTargetException e) {
440 e.printStackTrace();
441 } catch (Throwable e) {
442 e.printStackTrace();
443 }
444 }
445 }
446 }
447
448
449
450
451
452
453
454
455 private static boolean hasPrefix(final ResourceBundle resourceBundle, final String prefix) {
456 for (String s : resourceBundle.keySet()) {
457 if (s.startsWith(prefix)) {
458 return true;
459 }
460 }
461 return false;
462 }
463
464
465
466
467
468
469 public static boolean isDefaultAnnotation(final Annotation annotation) {
470 InvocationHandler ih = Proxy.getInvocationHandler(annotation);
471 return ih instanceof DefaultAnnotation;
472 }
473
474
475
476
477
478
479
480
481 private final Annotation annotation;
482
483
484
485 private final Class<? extends Annotation> annotationClass;
486
487
488
489 private final Hashtable<Method, Object> values = new Hashtable<Method, Object>();
490
491
492
493 private final String basePrefix;
494
495
496
497
498
499 private DefaultAnnotation(final Class<? extends Annotation> clazz) {
500 annotation = null;
501 annotationClass = clazz;
502 basePrefix = null;
503 init();
504 }
505
506
507
508
509
510 private DefaultAnnotation(final Class<? extends Annotation> clazz, final Class<?> base) {
511 annotation = null;
512 annotationClass = clazz;
513 basePrefix = base.getName() + ANNOTATION_SEPARATOR;
514 init();
515 }
516
517
518
519
520
521 private DefaultAnnotation(final Class<? extends Annotation> clazz, final Method base) {
522 annotation = null;
523 annotationClass = clazz;
524 basePrefix = base.getDeclaringClass().getName() + METHOD_SEPARATOR + base.getName() + ANNOTATION_SEPARATOR;
525 init();
526 }
527
528
529
530
531
532 private DefaultAnnotation(final Class<? extends Annotation> clazz, final Field base) {
533 annotation = null;
534 annotationClass = clazz;
535 basePrefix = base.getDeclaringClass().getName() + FIELD_SEPARATOR + base.getName() + ANNOTATION_SEPARATOR;
536 init();
537 }
538
539
540
541
542
543
544
545 private DefaultAnnotation(final Class<? extends Annotation> clazz, final Annotation annotationObject) {
546 annotation = annotationObject;
547 annotationClass = clazz;
548 basePrefix = null;
549 init();
550 }
551
552
553
554
555
556
557
558 private DefaultAnnotation(final Class<? extends Annotation> clazz, final Annotation annotationObject, final Class<?> base) {
559 annotation = annotationObject;
560 annotationClass = clazz;
561 basePrefix = base.getName() + ANNOTATION_SEPARATOR;
562 init();
563 }
564
565 private DefaultAnnotation(final Class<? extends Annotation> clazz, final Annotation annotationObject, final Method base) {
566 annotation = annotationObject;
567 annotationClass = clazz;
568 basePrefix = base.getDeclaringClass().getName() + METHOD_SEPARATOR + base.getName() + ANNOTATION_SEPARATOR;
569 init();
570 }
571
572 private DefaultAnnotation(final Class<? extends Annotation> clazz, final Annotation annotationObject, final Field base) {
573 annotation = annotationObject;
574 annotationClass = clazz;
575 basePrefix = base.getDeclaringClass().getName() + FIELD_SEPARATOR + base.getName() + ANNOTATION_SEPARATOR;
576 init();
577 }
578
579 @SuppressWarnings("unchecked")
580 private void init() {
581
582
583
584
585
586
587 if (annotation != null) {
588 try {
589 for (Method method : annotationClass.getDeclaredMethods()) {
590 if (method.getReturnType().isAnnotation()) {
591 Annotation subAnnotation = (Annotation) method.invoke(annotation, new Object[] {});
592 Class proxyClass = Proxy.getProxyClass(DefaultAnnotation.class.getClassLoader(), new Class[] { method.getReturnType() });
593 Object dynamicProxy = proxyClass.getConstructor(new Class[] { InvocationHandler.class }).newInstance(new Object[] { new DefaultAnnotation((Class<? extends Annotation>) method.getReturnType(), subAnnotation, method) });
594 values.put(method, dynamicProxy);
595 } else if (method.getReturnType().isArray() && method.getReturnType().getComponentType().isAnnotation()) {
596 Object array = method.invoke(annotation, new Object[] {});
597 Object subArray = Array.newInstance(method.getReturnType().getComponentType(), Array.getLength(array));
598 for (int i = 0; i < Array.getLength(array); i++) {
599 Annotation subAnnotation = (Annotation) Array.get(array, i);
600 Class proxyClass = Proxy.getProxyClass(DefaultAnnotation.class.getClassLoader(), new Class[] { method.getReturnType().getComponentType() });
601 Object dynamicProxy = proxyClass.getConstructor(new Class[] { InvocationHandler.class }).newInstance(new Object[] { new DefaultAnnotation((Class<? extends Annotation>) method.getReturnType().getComponentType(), subAnnotation, method) });
602 Array.set(subArray, i, dynamicProxy);
603 }
604 values.put(method, subArray);
605 }
606 }
607 } catch (IllegalArgumentException e) {
608 e.printStackTrace();
609 } catch (IllegalAccessException e) {
610 e.printStackTrace();
611 } catch (InvocationTargetException e) {
612 e.printStackTrace();
613 } catch (SecurityException e) {
614 e.printStackTrace();
615 } catch (InstantiationException e) {
616 e.printStackTrace();
617 } catch (NoSuchMethodException e) {
618 e.printStackTrace();
619 }
620 }
621 }
622
623 @Override
624 public boolean equals(final Object obj) {
625 if (obj == null) {
626 return false;
627 }
628 try {
629 InvocationHandler ih = Proxy.getInvocationHandler(obj);
630 if (ih instanceof DefaultAnnotation) {
631 DefaultAnnotation other = (DefaultAnnotation) ih;
632 return this.values.equals(other.values);
633 } else {
634 return false;
635 }
636 } catch (IllegalArgumentException e) {
637 return false;
638 }
639 }
640
641 @Override
642 public int hashCode() {
643 return toString().hashCode();
644 }
645
646 @Override
647 public String toString() {
648 try {
649 String keyValueString = "";
650 for (Method m : annotationClass.getDeclaredMethods()) {
651 if (m.getReturnType().isArray()) {
652 keyValueString += String.format("%s=%s, ", m.getName(), Arrays.toString((Object[]) invoke(null, m, new Object[] {})));
653 } else {
654 keyValueString += String.format("%s=%s, ", m.getName(), invoke(null, m, new Object[] {}));
655 }
656 }
657
658
659 if (annotationClass.getDeclaredMethods().length > 1) {
660 keyValueString = keyValueString.substring(0, keyValueString.length() - 2);
661 }
662
663 return String.format("@%s(%s)", annotationClass.getName(), keyValueString);
664 } catch (SecurityException e) {
665 e.printStackTrace();
666 } catch (Throwable e) {
667 e.printStackTrace();
668 }
669 return "";
670 }
671
672
673
674
675
676 public Class<? extends Annotation> annotationType() {
677 return annotationClass;
678 }
679
680 public String getBasePrefix() {
681 return basePrefix;
682 }
683
684 @Override
685 public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
686
687 if (method.equals(Annotation.class.getMethod("equals", Object.class))) {
688 return this.equals(args[0]);
689 }
690 if (method.equals(Annotation.class.getMethod("hashCode"))) {
691 return this.hashCode();
692 }
693 if (method.equals(Annotation.class.getMethod("toString"))) {
694 return this.toString();
695 }
696 if (method.equals(Annotation.class.getMethod("annotationType"))) {
697 return this.annotationType();
698 }
699 if (method.equals(Object.class.getMethod("notify"))) {
700 this.notify();
701 return null;
702 }
703 if (method.equals(Object.class.getMethod("notifyAll"))) {
704 this.notifyAll();
705 return null;
706 }
707 if (method.equals(Object.class.getMethod("wait"))) {
708 this.wait();
709 return null;
710 }
711 if (method.equals(Object.class.getMethod("wait", long.class))) {
712 this.wait((Long) args[0]);
713 return null;
714 }
715 if (method.equals(Object.class.getMethod("wait", long.class, int.class))) {
716 this.wait((Long) args[0], (Integer) args[1]);
717 return null;
718 }
719
720 if (values.containsKey(method)) {
721 return values.get(method);
722 }
723
724 if (annotation != null) {
725 return method.invoke(annotation, args);
726 }
727
728 return method.getDefaultValue();
729 }
730 }