297b21d72f646e48aa0f73eb1d64cce9af9ffd6e
[cacao.git] / tests / regression / TestAnnotations.java
1 /* tests/regression/TestAnnotations.java - checks correct functionality of the
2    annotation API
3
4    Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel,
5    C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
6    E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
7    TU Wien
8
9    This file is part of CACAO.
10
11    This program is free software; you can redistribute it and/or
12    modify it under the terms of the GNU General Public License as
13    published by the Free Software Foundation; either version 2, or (at
14    your option) any later version.
15
16    This program is distributed in the hope that it will be useful, but
17    WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19    General Public License for more details.
20
21    You should have received a copy of the GNU General Public License
22    along with this program; if not, write to the Free Software
23    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
24    02110-1301, USA.
25
26    Contact: cacao@cacaojvm.org
27
28    Authors: Mathias Panzenböck
29
30    $Id$
31
32 */
33
34 import java.lang.annotation.Annotation;
35 import java.lang.annotation.Inherited;
36 import java.lang.annotation.Retention;
37 import java.lang.annotation.RetentionPolicy;
38 import java.lang.reflect.AnnotatedElement;
39 import java.lang.reflect.Array;
40 import java.lang.reflect.Constructor;
41 import java.lang.reflect.Method;
42 import java.lang.reflect.Field;
43 import java.util.ArrayList;
44 import java.util.Arrays;
45 import java.util.Collection;
46 import java.util.Collections;
47 import java.util.Comparator;
48 import java.util.List;
49 import java.util.Map;
50 import java.util.HashMap;
51 import java.util.SortedSet;
52 import java.util.TreeMap;
53 import java.util.LinkedHashMap;
54 import java.util.Set;
55 import java.util.HashSet;
56 import java.util.TreeSet;
57 import java.util.LinkedHashSet;
58
59 /* ********* helper classes for the tests *************************************/
60 enum IndexingType {
61         HASH,
62         LINKED_HASH,
63         TREE
64 }
65
66 class MapFactory {
67         private IndexingType indexingType;
68         
69         public MapFactory(IndexingType indexingType) {
70                 this.indexingType = indexingType;
71         }
72         
73         public <K, V> Map<K, V> createMap() {
74                 switch (indexingType) {
75                 case HASH:        return new HashMap<K, V>();
76                 case LINKED_HASH: return new LinkedHashMap<K, V>(); 
77                 case TREE:        return new TreeMap<K, V>();
78                 default:
79                         throw new IllegalArgumentException(
80                                         "Illegal indexing type: " + indexingType);
81                 }
82         }
83
84         public <K, V> Map<K, V> createMap(Map<? extends K,? extends V> map) {
85                 switch (indexingType) {
86                 case HASH:        return new HashMap<K, V>(map);
87                 case LINKED_HASH: return new LinkedHashMap<K, V>(map);
88                 case TREE:        return new TreeMap<K, V>(map);
89                 default:
90                         throw new IllegalArgumentException(
91                                         "Illegal indexing type: " + indexingType);
92                 }
93         }
94 }
95
96 class SetFactory {
97         private IndexingType indexingType;
98         
99         public SetFactory(IndexingType indexingType) {
100                 this.indexingType = indexingType;
101         }
102         
103         public <E> Set<E> createSet() {
104                 switch (indexingType) {
105                 case HASH:        return new HashSet<E>();
106                 case TREE:        return new TreeSet<E>();
107                 case LINKED_HASH: return new LinkedHashSet<E>();
108                 default:
109                         throw new IllegalArgumentException(
110                                         "Illegal indexing type: " + indexingType);
111                 }
112         }
113         
114         public <E> Set<E> createSet(E[] keys) {
115                 Set<E> set = createSet();
116                 
117                 for (E key : keys) {
118                         set.add(key);
119                 }
120                 
121                 return set;
122         }
123         
124         public <E> Set<E> createSet(Collection<? extends E> collection) {
125                 switch (indexingType) {
126                 case HASH:        return new HashSet<E>(collection);
127                 case TREE:        return new TreeSet<E>(collection);
128                 case LINKED_HASH: return new LinkedHashSet<E>(collection);
129                 default:
130                         throw new IllegalArgumentException(
131                                         "Illegal indexing type: " + indexingType);
132                 }
133         }
134 }
135
136 class TestHelper {
137         private static MapFactory mapFactory = new MapFactory(IndexingType.HASH);
138         private static SetFactory setFactory = new SetFactory(IndexingType.HASH);
139         
140         private static long testCount = 0;
141         private static long failCount = 0;
142
143         public static MapFactory getMapFactory() {
144                 return mapFactory;
145         }
146         
147         public static SetFactory getSetFactory() {
148                 return setFactory;
149         }
150         
151         public static void clear() {
152                 testCount = 0;
153                 failCount = 0;
154         }
155
156         public static long getTestCount() {
157                 return testCount;
158         }
159
160         public static long getFailCount() {
161                 return failCount;
162         }
163
164         public static void printStatistics() {
165                 System.out.printf("         passed: %8d\n", testCount - failCount);
166                 System.out.printf("         failed: %8d\n", failCount);
167                 System.out.printf("         ----------------\n");
168                 System.out.printf("         sum:    %8d\n", testCount);
169         }
170
171         public static void log() {
172                 System.out.println();
173         }
174
175         public static void log(String msg) {
176                 System.out.println(msg);
177         }
178
179         public static void log(String fmt, Object... args) {
180                 System.out.printf(fmt + "\n", args);
181         }
182
183         public static boolean ok(boolean test, String msg) {
184                 return ok(test, "%s", msg);
185         }
186
187         public static boolean ok(boolean test, String fmt, Object... args) {
188                 ++testCount;
189
190                 if (test) {
191                         System.out.printf("[  OK  ] " + fmt + "\n", args);
192                         return true;
193                 } else {
194                         ++failCount;
195                         System.out.printf("[ FAIL ] " + fmt + "\n", args);
196                         return false;
197                 }
198         }
199
200         public static boolean okx(boolean test, String what, String fmt,
201                         String errfmt, Object[] args, Object... errargs) {
202                 if (!test)
203                         return ok(test, fmt + ": %s\n         error: " + errfmt, concat(
204                                         concat(args, what), errargs));
205                 else
206                         return ok(test, fmt + ": %s", concat(args, what));
207         }
208
209         /* helper methods: */
210         @SuppressWarnings("unchecked")
211         public static <T> T[] concat(T[] firstArray, T... moreElements) {
212                 return concat2(firstArray, moreElements);
213         }
214
215         @SuppressWarnings("unchecked")
216         public static <T> T[] concat2(T[] firstArray, T[]... moreArrays) {
217                 int length = firstArray.length;
218
219                 for (T[] array : moreArrays) {
220                         length += array.length;
221                 }
222
223                 T[] result = (T[]) Array.newInstance(firstArray.getClass()
224                                 .getComponentType(), length);
225
226                 System.arraycopy(firstArray, 0, result, 0, firstArray.length);
227
228                 int pos = firstArray.length;
229                 for (T[] array : moreArrays) {
230                         System.arraycopy(array, 0, result, pos, array.length);
231                         pos += array.length;
232                 }
233
234                 return result;
235         }
236
237         public static <T> String str(T object) {
238                 /* null */
239                 if (object == null) {
240                         return "null";
241                 }
242                 /* array */
243                 else if (object.getClass().isArray()) {
244                         StringBuilder buf = new StringBuilder();
245                         int length = Array.getLength(object);
246
247                         buf.append('{');
248
249                         if (length > 0) {
250                                 buf.append(str(Array.get(object, 0)));
251
252                                 for (int i = 1; i < length; ++i) {
253                                         buf.append(", ");
254                                         buf.append(str(Array.get(object, i)));
255                                 }
256                         }
257
258                         buf.append('}');
259
260                         return buf.toString();
261                 }
262                 /* escape String */
263                 else if (object instanceof String) {
264                         String s = object.toString();
265                         StringBuilder buf = new StringBuilder();
266
267                         buf.append('"');
268
269                         for (int i = 0; i < s.length(); ++i) {
270                                 char ch = s.charAt(i);
271
272                                 switch (ch) {
273                                 case '"':
274                                         buf.append("\\\"");
275                                         break;
276                                 case '\\':
277                                         buf.append("\\\\");
278                                         break;
279                                 case '\b':
280                                         buf.append("\\b");
281                                         break;
282                                 case '\f':
283                                         buf.append("\\f");
284                                         break;
285                                 case '\t':
286                                         buf.append("\\t");
287                                         break;
288                                 case '\n':
289                                         buf.append("\\n");
290                                         break;
291                                 case '\r':
292                                         buf.append("\\r");
293                                         break;
294                                 default:
295                                         buf.append(ch);
296                                 }
297                         }
298
299                         buf.append('"');
300                         return buf.toString();
301                 }
302                 /* escape Character */
303                 else if (object instanceof Character) {
304                         switch ((Character) object) {
305                         case '\'':
306                                 return "'\\''";
307                         case '\\':
308                                 return "'\\\\'";
309                         case '\b':
310                                 return "'\\b'";
311                         case '\f':
312                                 return "'\\f'";
313                         case '\t':
314                                 return "'\\t'";
315                         case '\n':
316                                 return "'\\n'";
317                         case '\r':
318                                 return "'\\r'";
319                         default:
320                                 return "'" + object + "'";
321                         }
322                 }
323                 /* Class */
324                 else if (object instanceof Class) {
325                         return ((Class<?>) object).getName();
326                 }
327
328                 return object.toString();
329         }
330         
331         public static <E extends Comparable<? super E>> Collection<E> sorted(
332                         Collection<E> collection) {
333                 if (collection instanceof SortedSet) {
334                         return collection;
335                 }
336                 else {
337                         List<E> reply = new ArrayList<E>(collection);
338                         Collections.sort(reply);
339                         
340                         return reply;
341                 }
342         }
343
344         public static <E> Collection<E> sorted(
345                         Collection<E> collection,
346                         Comparator<? super E> comparator) {
347                 if (collection instanceof SortedSet) {
348                         return collection;
349                 }
350                 else {
351                         List<E> reply = new ArrayList<E>(collection);
352                         Collections.sort(reply, comparator);
353                         
354                         return reply;
355                 }
356         }
357
358         public static <E extends Comparable<? super E>> E[] sorted(E[] values) {
359                 Arrays.sort(values);
360                 return values;
361         }
362         
363         public static <E> E[] sorted(
364                         E[] values,
365                         Comparator<? super E> comparator) {
366                 Arrays.sort(values, comparator);
367                 return values;
368         }
369 }
370
371 class Entry implements Map.Entry<String, Object> {
372         private String key;
373         private Object val;
374
375         public Entry(String key, Object value) {
376                 this.key = key;
377                 this.val = value;
378         }
379
380         public String getKey() {
381                 return key;
382         }
383
384         public Object getValue() {
385                 return val;
386         }
387
388         public Object setValue(Object value) {
389                 Object oldval = val;
390                 val = value;
391                 return oldval;
392         }
393
394         public int hashCode() {
395                 return (key != null ? key.hashCode() << 8 : 0)
396                                 ^ (val != null ? val.hashCode() : 0);
397         }
398
399         public boolean equals(Object other) {
400                 if (other != null && other instanceof Entry) {
401                         Entry otherEntry = (Entry) other;
402
403                         return (key == null ? otherEntry.key == null :
404                                 key.equals(otherEntry.key))
405                                         && (val == null ? otherEntry.val == null :
406                                                 val.equals(otherEntry.val));
407                 }
408
409                 return false;
410         }
411 }
412
413 class AnnotationTester implements Comparable<AnnotationTester> {
414         private Class<? extends Annotation> annotationType;
415
416         private Map<String, Object> values =
417                 TestHelper.getMapFactory().<String, Object>createMap();
418
419         public AnnotationTester(Class<? extends Annotation> annotationType,
420                         Map<String, Object> values) {
421                 this.annotationType = annotationType;
422                 this.values.putAll(values);
423
424                 checkValues();
425         }
426
427         public AnnotationTester(Class<? extends Annotation> annotationType) {
428                 this.annotationType = annotationType;
429
430                 checkValues();
431         }
432
433         public AnnotationTester(Class<? extends Annotation> annotationType,
434                         Map.Entry<String, Object>... values) {
435                 this.annotationType = annotationType;
436
437                 for (Map.Entry<String, Object> value : values) {
438                         if (this.values.put(value.getKey(), value.getValue()) != null)
439                                 throw new IllegalArgumentException(
440                                                 "duplicated key: " + TestHelper.str(value.getKey()));
441                 }
442
443                 checkValues();
444         }
445
446         public Class<? extends Annotation> annotationType() {
447                 return annotationType;
448         }
449
450         private void checkValues() {
451                 for (String methodName : values.keySet()) {
452                         try {
453                                 annotationType.getDeclaredMethod(methodName);
454                         } catch (NoSuchMethodException e) {
455                                 throw new IllegalArgumentException(
456                                                 "annotation " + annotationType.getName() +
457                                                 " has no method of name " + methodName + "()", e);
458                         }
459                 }
460
461                 for (Method method : annotationType.getDeclaredMethods()) {
462                         Object value = values.get(method.getName());
463                         Class<?> returnType = method.getReturnType();
464                         Class<?> valueType = value.getClass();
465
466                         if (value == null) {
467                                 throw new IllegalArgumentException(
468                                                 "annotation method of name " + method.getName() +
469                                                 "() needs an expected value");
470                         } else if (value instanceof AnnotationTester) {
471                                 AnnotationTester tester = (AnnotationTester) value;
472
473                                 if (!tester.annotationType().equals(returnType)) {
474                                         throw new IllegalArgumentException(
475                                                         "illegal value type for annotation method " +
476                                                         method.getName() + "()");
477                                 }
478                         } else if (!returnType.isInstance(value)) {
479                                 if (returnType.isArray()
480                                                 && returnType.getComponentType().isAnnotation()) {
481                                         if (!valueType.isArray()
482                                                         || !isSubclassOf(valueType.getComponentType(),
483                                                                         AnnotationTester.class)) {
484                                                 throw new IllegalArgumentException(
485                                                                 "illegal value type for annotation method " +
486                                                                 method.getName() + "()");
487                                         }
488
489                                         for (AnnotationTester tester : (AnnotationTester[]) value) {
490                                                 if (!tester.annotationType().equals(
491                                                                 returnType.getComponentType())) {
492                                                         throw new IllegalArgumentException(
493                                                                         "illegal value type for annotation method " +
494                                                                         method.getName() + "()");
495                                                 }
496                                         }
497                                 } else if (!returnType.isPrimitive()
498                                                 || !valueType.equals(getBoxingType(returnType))) {
499                                         throw new IllegalArgumentException(
500                                                         "illegal value type for annotation method " +
501                                                         method.getName() + "()");
502                                 }
503                         }
504                 }
505         }
506
507         public static boolean isSubclassOf(Class<?> subClass, Class<?> superClass) {
508                 do {
509                         if (subClass.equals(superClass)) {
510                                 return true;
511                         }
512                         subClass = subClass.getSuperclass();
513                 } while (subClass != null);
514
515                 return false;
516         }
517
518         private static Map<Class<?>, Class<?>> boxingMap =
519                 TestHelper.getMapFactory().<Class<?>, Class<?>>createMap();
520
521         static {
522                 boxingMap.put(byte.class,   Byte.class);
523                 boxingMap.put(char.class,   Character.class);
524                 boxingMap.put(short.class,  Short.class);
525                 boxingMap.put(long.class,   Long.class);
526                 boxingMap.put(int.class,    Integer.class);
527                 boxingMap.put(float.class,  Float.class);
528                 boxingMap.put(double.class, Double.class);
529         }
530
531         public static Class<?> getBoxingType(Class<?> primitiveType) {
532                 Class<?> type = boxingMap.get(primitiveType);
533
534                 if (type == null) {
535                         throw new IllegalArgumentException(
536                                         "illegal type for boxing: "     + primitiveType.getName());
537                 }
538
539                 return type;
540         }
541
542         public int hashCode() {
543                 return (annotationType.hashCode() << 8) ^ values.hashCode();
544         }
545
546         public boolean equals(Object other) {
547                 if (other != null) {
548                         if (other instanceof AnnotationTester) {
549                                 AnnotationTester otherAnnotationTester =
550                                         (AnnotationTester) other;
551
552                                 if (!otherAnnotationTester.annotationType.equals(annotationType) ||
553                                                 otherAnnotationTester.values.size() != values.size())
554                                         return false;
555
556                                 for (Map.Entry<String, Object> entry : values.entrySet()) {
557                                         if (!otherAnnotationTester.values.containsKey(entry.getKey()) ||
558                                                         !otherAnnotationTester.values.get(
559                                                                         entry.getKey()).equals(entry.getValue()))
560                                                 return false;
561                                 }
562
563                                 return true;
564                         } else if (other instanceof Annotation) {
565                                 Annotation anno = (Annotation) other;
566                                 Method[] annotationFields = anno.annotationType()
567                                                 .getDeclaredMethods();
568
569                                 if (!annotationType.equals(anno.annotationType())
570                                                 || annotationFields.length != values.size())
571                                         return false;
572
573                                 for (Method method : annotationFields) {
574                                         if (!values.get(method.getName()).equals(
575                                                         method.getDefaultValue()))
576                                                 return false;
577                                 }
578
579                                 return true;
580                         }
581                 }
582                 return false;
583         }
584         
585         public String toString() {
586                 StringBuilder buf = new StringBuilder();
587                 
588                 buf.append('@');
589                 buf.append(annotationType.getName());
590                 buf.append('(');
591                 
592                 int i = 0;
593                 for (Map.Entry<String, Object> entry : values.entrySet()) {
594                         buf.append(entry.getKey());
595                         buf.append('=');
596                         buf.append(TestHelper.str(entry.getValue()));
597                         
598                         ++ i;
599                         if (i < values.size()) {
600                                 buf.append(", ");
601                         }
602                 }
603                 buf.append(')');
604                 
605                 return buf.toString();
606         }
607
608         private final static Object[] EMPTY_OBJECT_ARRAY = new Object[] {};
609
610         protected boolean ok(boolean test, String what, String errfmt,
611                         Object... errargs) {
612                 return TestHelper.okx(test, what, annotationType.getName(), errfmt,
613                                 EMPTY_OBJECT_ARRAY, errargs);
614         }
615
616         public boolean test(Annotation annotation) throws SecurityException,
617                         NoSuchMethodException {
618                 boolean ok = true;
619                 Method[] declaredMedthods = annotation.annotationType()
620                                 .getDeclaredMethods();
621
622                 TestHelper.log(" * Testing %s", annotationType.getName());
623                 
624                 ok = ok(annotationType.equals(annotation.annotationType()),
625                                 "test annotationType", "expected %s but got %s",
626                                 annotationType, annotation.annotationType());
627
628                 if (ok) {
629                         ok = ok(declaredMedthods.length == values.size(),
630                                         "test annotation methods count", "expected %d but got %d",
631                                         values.size(), declaredMedthods.length)
632                                         && ok;
633                         
634                         for (String methodName : TestHelper.sorted(values.keySet())) {
635                                 Object    expected = values.get(methodName);
636                                 Object    got = null;
637                                 Exception ex  = null;
638
639                                 try {
640                                         got = annotation.getClass().getMethod(methodName).invoke(
641                                                         annotation);
642                                 } catch (Exception e) {
643                                         ex = e;
644                                 }
645
646                                 ok = ok(ex == null,
647                                                 "test invocation of the annotation method " +
648                                                 methodName + "()",
649                                                 "exception occured while invokation: %s",
650                                                 ex != null ? ex.getMessage() : "")
651                                                 && ok;
652
653                                 if (ex != null) {
654                                         ex.printStackTrace();
655                                 } else {
656                                         ok = ok(got != null, "test return value of " + methodName +
657                                                         "() != null", "got null!")
658                                                         && ok;
659
660                                         ok = ok(equals(got, expected), "test return value of "
661                                                         + methodName + "()", "expected %s (type: %s) but"
662                                                         + " got %s (type: %s)", TestHelper.str(got), got
663                                                         .getClass().getName(), TestHelper.str(expected),
664                                                         expected.getClass().getName())
665                                                         && ok;
666                                 }
667                         }
668                 }
669
670                 return ok;
671         }
672
673         public static boolean equals(Object a, Object b) {
674                 if (a == null) {
675                         return b == null;
676                 }
677                 else if (a instanceof Annotation && b instanceof AnnotationTester) {
678                         return equals((Annotation) a, (AnnotationTester) b);
679                 }
680                 else if (b instanceof Annotation && a instanceof AnnotationTester) {
681                         return equals((Annotation) b, (AnnotationTester) a);
682                 }
683                 else if (a.getClass().isArray()) {
684                         if (!b.getClass().isArray()) {
685                                 return false;
686                         }
687
688                         int alen = Array.getLength(a);
689                         int blen = Array.getLength(b);
690
691                         if (alen != blen) {
692                                 return false;
693                         }
694
695                         for (int i = 0; i < alen; ++i) {
696                                 if (!equals(Array.get(a, i), Array.get(b, i))) {
697                                         return false;
698                                 }
699                         }
700
701                         return true;
702                 }
703                 else {
704                         return a.equals(b);
705                 }
706         }
707
708         public static boolean equals(Annotation annoation, AnnotationTester tester) {
709                 if (!tester.annotationType().equals(annoation.annotationType())) {
710                         return false;
711                 }
712
713                 try {
714                         for (Map.Entry<String, Object> bEntry : tester.values.entrySet()) {
715                                 Object aValue = annoation.getClass().getMethod(bEntry.getKey())
716                                                 .invoke(annoation);
717
718                                 if (!equals(bEntry.getValue(), aValue)) {
719                                         return false;
720                                 }
721                         }
722                 } catch (Exception e) {
723                         // TODO: better error handling?
724                         e.printStackTrace();
725                         return false;
726                 }
727
728                 return true;
729         }
730
731         public int compareTo(AnnotationTester other) {
732                 return annotationType.getName().compareTo(
733                                 other.annotationType().getName());
734         }
735 }
736
737 abstract class AnnotatedElementAnnotationTester<T extends AnnotatedElement>
738                 implements Comparable<AnnotatedElementAnnotationTester<? extends AnnotatedElement>> {
739         protected ClassAnnotationTester declaringClass;
740         private T                       element;
741         private String                  name;
742         
743         private Map<Class<? extends Annotation>, AnnotationTester> annotations =
744                 TestHelper.getMapFactory().
745                 <Class<? extends Annotation>, AnnotationTester>createMap();
746         
747         private Map<Class<? extends Annotation>, AnnotationTester> declaredAnnotations =
748                 TestHelper.getMapFactory().
749                 <Class<? extends Annotation>, AnnotationTester>createMap();
750
751         protected final static Object[] EMPTY_OBJECT_ARRAY = new Object[] {};
752
753         public AnnotatedElementAnnotationTester(
754                         ClassAnnotationTester clazz,
755                         T                     element,
756                         String                name) {
757                 this.declaringClass = clazz;
758                 this.element        = element;
759                 this.name           = name;
760         }
761         
762         public T annotatedElement() {
763                 return element;
764         }
765         
766         public String getName() {
767                 return name;
768         }
769         
770         public int compareTo(
771                         AnnotatedElementAnnotationTester<? extends AnnotatedElement> other) {
772                 return name.compareTo(other.getName());
773         }
774         
775         private static Comparator<Annotation> annotationComparator =
776                 new Comparator<Annotation>() {
777                         public int compare(Annotation o1, Annotation o2) {
778                                 return o1.annotationType().getName().compareTo(
779                                                 o2.annotationType().getName());
780                         }
781         };
782         
783         protected static Annotation[] sorted(Annotation[] annotations) {
784                 return TestHelper.sorted(annotations, annotationComparator);
785         }
786
787         protected boolean ok(
788                         boolean test, String what,
789                         String errfmt, Object... errargs) {
790                 return TestHelper.okx(test, what, name, errfmt,
791                                 EMPTY_OBJECT_ARRAY, errargs);
792         }
793         
794         protected void logName() {
795                 TestHelper.log("-- Testing %s --", getName());
796         }
797         
798         protected void logHeader(String fmt, Object... args) {
799                 TestHelper.log("-- " + getName() + ": Testing " + fmt + " --", args);
800         }
801
802         protected void log() {
803                 TestHelper.log();
804         }
805
806         public void putInheritedAnnotation(
807                         Class<? extends Annotation> annotationType,
808                         Map.Entry<String, Object>... values) {
809                 if (annotations.containsKey(annotationType))
810                         throw new IllegalArgumentException(
811                                         "Annotation already exists: " + annotationType.getName());
812
813                 annotations.put(annotationType,
814                                 new AnnotationTester(annotationType, values));
815         }
816
817         public void putInheritedAnnotation(
818                         Class<? extends Annotation> annotationType,
819                         Map<String, Object> values) {
820                 if (annotations.containsKey(annotationType))
821                         throw new IllegalArgumentException(
822                                         "Annotation already exists: " + annotationType.getName());
823
824                 annotations.put(annotationType,
825                                 new AnnotationTester(annotationType, values));
826         }
827
828         public void putDeclaredAnnotation(
829                         Class<? extends Annotation> annotationType,
830                         Map.Entry<String, Object>... values) {
831                 if (annotations.containsKey(annotationType))
832                         throw new IllegalArgumentException(
833                                         "Annotation already exists: " + annotationType.getName());
834
835                 AnnotationTester tester = new AnnotationTester(annotationType, values);
836
837                 annotations.put(annotationType, tester);
838                 declaredAnnotations.put(annotationType, tester);
839         }
840
841         public void putDeclaredAnnotation(
842                         Class<? extends Annotation> annotationType,
843                         Map<String, Object> values) {
844                 if (annotations.containsKey(annotationType))
845                         throw new IllegalArgumentException(
846                                         "Annotation already exists: " + annotationType.getName());
847
848                 AnnotationTester tester = new AnnotationTester(annotationType, values);
849
850                 annotations.put(annotationType, tester);
851                 declaredAnnotations.put(annotationType, tester);
852         }
853
854         public boolean test() throws SecurityException, NoSuchMethodException {
855                 boolean ok;
856                 
857                 logName();
858                 
859                 ok = testGetDeclaredAnnotations();
860                 ok = testGetAnnotations()      && ok;
861                 ok = testGetAnnotation()       && ok;
862                 ok = testIsAnnotationPresent() && ok;
863
864                 return ok;
865         }
866
867
868         private boolean testGetDeclaredAnnotations() throws SecurityException,
869                         NoSuchMethodException {
870                 Annotation[] declaredAnnotations = element.getDeclaredAnnotations();
871                 boolean ok = true;
872                 Set<Class<? extends Annotation>> annoTypes =
873                         TestHelper.getSetFactory().<Class<? extends Annotation>>createSet();
874
875                 logHeader("getDeclaredAnnotations()");
876                 
877                 ok = ok(this.declaredAnnotations.size() == declaredAnnotations.length,
878                                 "test declared annotations count", "expected %d but got %d",
879                                 this.declaredAnnotations.size(), declaredAnnotations.length)
880                                 && ok;
881
882                 for (Annotation anno : sorted(declaredAnnotations)) {
883                         AnnotationTester tester = this.annotations.get(
884                                         anno.annotationType());
885
886                         ok = ok(!annoTypes.contains(anno.annotationType()),
887                                         "test unique occurrence of the annotation type " +
888                                         anno.annotationType().getName(),
889                                         "duplicated annotation!") && ok;
890
891                         annoTypes.add(anno.annotationType());
892
893                         ok = ok(tester != null, "test if annotation " +
894                                         anno.annotationType().getName() + " should be there",
895                                         "wrong annotation") && ok;
896
897                         if (tester != null) {
898                                 ok = tester.test(anno) && ok;
899                         }
900                 }
901
902                 return ok;
903         }
904         
905         private boolean testGetAnnotations() throws SecurityException,
906                         NoSuchMethodException {
907                 Annotation[] annotations = element.getAnnotations();
908                 boolean ok = true;
909                 Set<Class<? extends Annotation>> annoTypes =
910                         TestHelper.getSetFactory().<Class<? extends Annotation>>createSet();
911
912                 logHeader("getAnnotations()");
913                 
914                 ok = ok(this.annotations.size() == annotations.length,
915                                 "test annotations count", "expected %d but got %d",
916                                 this.annotations.size(), annotations.length)
917                                 && ok;
918
919                 for (Annotation anno : sorted(annotations)) {
920                         AnnotationTester tester = this.annotations.get(anno
921                                         .annotationType());
922
923                         ok = ok(!annoTypes.contains(anno.annotationType()),
924                                         "test unique occurrence of the annotation type " +
925                                         anno.annotationType().getName(),
926                                         "duplicated annotation!")
927                                         && ok;
928
929                         annoTypes.add(anno.annotationType());
930
931                         ok = ok(tester != null, "test if annotation " +
932                                         anno.annotationType().getName() + " should be there",
933                                         "wrong annotation")
934                                         && ok;
935
936                         if (tester != null) {
937                                 ok = tester.test(anno) && ok;
938                         }
939                 }
940
941                 return ok;
942         }
943
944         private boolean testGetAnnotation() throws SecurityException,
945                         NoSuchMethodException {
946                 boolean ok = true;
947
948                 logHeader("getAnnotation(Class<? extends Annotation>)");
949                 
950                 for (AnnotationTester tester : TestHelper.sorted(annotations.values())) {
951                         Class<? extends Annotation> annotationType = tester
952                                         .annotationType();
953                         Annotation anno = element.getAnnotation(annotationType);
954
955                         ok = ok(anno != null, "try to get required annotation " +
956                                         annotationType.getName() +
957                                         " using getAnnotation(Class<? extends Annotation>)",
958                                         "annotation dose not exist")
959                                         && ok;
960
961                         if (anno != null) {
962                                 ok = tester.test(anno) && ok;
963                         }
964                 }
965
966                 return ok;
967         }
968
969         private boolean testIsAnnotationPresent() {
970                 boolean ok = true;
971
972                 logHeader("isAnnotationPresent(Class<? extends Annotation>)");
973                 
974                 for (AnnotationTester tester : TestHelper.sorted(annotations.values())) {
975                         Class<? extends Annotation> annotationType =
976                                 tester.annotationType();
977
978                         ok = ok(element.isAnnotationPresent(annotationType),
979                                         "test if annotation " + annotationType.getName() +
980                                         " is present using isAnnotationPresent()",
981                                         "annotation dose not exist")
982                                         && ok;
983                 }
984
985                 return ok;
986         }
987 }
988
989 class FieldAnnotationTester extends AnnotatedElementAnnotationTester<Field> {
990         public FieldAnnotationTester(ClassAnnotationTester clazz, Field field) {
991                 super(clazz, field, field.getDeclaringClass().getName() + "." +
992                                 field.getName());
993         }
994 }
995
996 abstract class AbstractMethodAnnotationTester<T extends AnnotatedElement>
997                 extends AnnotatedElementAnnotationTester<T> {
998         private Map<Class<? extends Annotation>, AnnotationTester>[] parameterAnnotations;
999
1000         @SuppressWarnings("unchecked")
1001         public AbstractMethodAnnotationTester(ClassAnnotationTester clazz,
1002                         T element, String name, Class<?>[] parameterTypes) {
1003                 super(clazz, element,
1004                                 methodName(clazz.annotatedElement(), name, parameterTypes));
1005
1006                 parameterAnnotations = new Map[parameterTypes.length];
1007
1008                 MapFactory mapFactory = TestHelper.getMapFactory();
1009                 
1010                 for (int i = 0; i < parameterTypes.length; ++i) {
1011                         parameterAnnotations[i] = mapFactory.
1012                                 <Class<? extends Annotation>, AnnotationTester>createMap();
1013                 }
1014         }
1015
1016         private static String methodName(Class<?> declaringClass, String name,
1017                         Class<?>[] parameterTypes) {
1018                 StringBuilder buf = new StringBuilder(128);
1019
1020                 buf.append(declaringClass.getName());
1021                 buf.append('.');
1022                 buf.append(name);
1023                 buf.append('(');
1024
1025                 if (parameterTypes.length > 0) {
1026                         buf.append(parameterTypes[0].getName());
1027
1028                         for (int i = 1; i < parameterTypes.length; ++i) {
1029                                 buf.append(',');
1030                                 buf.append(parameterTypes[i].getName());
1031                         }
1032                 }
1033
1034                 buf.append(')');
1035
1036                 return buf.toString();
1037         }
1038
1039         abstract protected Annotation[][] getParameterAnnotations();
1040
1041         public void putParameterAnnotation(int index,
1042                         Class<? extends Annotation> annotationType,
1043                         Map.Entry<String, Object>... values) {
1044                 if (parameterAnnotations[index].containsKey(annotationType))
1045                         throw new IllegalArgumentException(
1046                                         "Annotation already exists: " + annotationType.getName());
1047
1048                 parameterAnnotations[index].put(
1049                                 annotationType,
1050                                 new AnnotationTester(annotationType, values));
1051         }
1052
1053         public void putParameterAnnotation(int index,
1054                         Class<? extends Annotation> annotationType,
1055                         Map<String, Object> values) {
1056                 if (parameterAnnotations[index].containsKey(annotationType))
1057                         throw new IllegalArgumentException(
1058                                         "Annotation already exists: " + annotationType.getName());
1059
1060                 parameterAnnotations[index].put(
1061                                 annotationType,
1062                                 new AnnotationTester(annotationType, values));
1063         }
1064
1065         public boolean test() throws SecurityException, NoSuchMethodException {
1066                 boolean ok = super.test();
1067
1068                 ok = testParameterAnnotations() && ok;
1069
1070                 return ok;
1071         }
1072
1073         private boolean testParameterAnnotations() throws SecurityException,
1074                         NoSuchMethodException {
1075                 boolean ok = true;
1076                 Annotation[][] parameterAnnotations = getParameterAnnotations();
1077
1078                 logHeader("getParameterAnnotations()");
1079                 
1080                 ok = ok(
1081                                 this.parameterAnnotations.length == parameterAnnotations.length,
1082                                 "test parameter count", "expected %d but got %d",
1083                                 this.parameterAnnotations.length, parameterAnnotations.length)
1084                                 && ok;
1085
1086                 if (this.parameterAnnotations.length == parameterAnnotations.length) {
1087                         for (int i = 0; i < parameterAnnotations.length; ++i) {
1088                                 Set<Class<? extends Annotation>> annoTypes =
1089                                         TestHelper.getSetFactory().
1090                                         <Class<? extends Annotation>>createSet();
1091
1092                                 ok = ok(
1093                                                 this.parameterAnnotations[i].size() == parameterAnnotations[i].length,
1094                                                 "test parameter annotations count for parameter " + i,
1095                                                 "expected %d but got %d",
1096                                                 Integer.valueOf(this.parameterAnnotations.length),
1097                                                 Integer.valueOf(parameterAnnotations.length))
1098                                                 && ok;
1099
1100                                 for (Annotation anno : sorted(parameterAnnotations[i])) {
1101                                         AnnotationTester tester =
1102                                                 this.parameterAnnotations[i].get(anno.annotationType());
1103
1104                                         ok = ok(!annoTypes.contains(anno.annotationType()),
1105                                                         "test unique occurrence of the annotation type " +
1106                                                         anno.annotationType().getName(),
1107                                                         "duplicated annotation!")
1108                                                         && ok;
1109
1110                                         annoTypes.add(anno.annotationType());
1111
1112                                         ok = ok(tester != null, "test if annotation of type " +
1113                                                         anno.annotationType().getName() +
1114                                                         " should be defined for parameter " + i,
1115                                                         "no, it shouldn't be!")
1116                                                         && ok;
1117
1118                                         if (tester != null) {
1119                                                 ok = tester.test(anno) && ok;
1120                                         }
1121                                 }
1122                         }
1123                 }
1124
1125                 return ok;
1126         }
1127 }
1128
1129 class MethodAnnotationTester extends AbstractMethodAnnotationTester<Method> {
1130         private Object defaultValue = null;
1131
1132         public MethodAnnotationTester(ClassAnnotationTester clazz, Method method) {
1133                 super(clazz, method, method.getName(), method.getParameterTypes());
1134         }
1135
1136         public MethodAnnotationTester(ClassAnnotationTester clazz, Method method,
1137                         Object defaultValue) {
1138                 this(clazz, method);
1139                 setDefaultValue(defaultValue);
1140         }
1141
1142         public void setDefaultValue(Object value) {
1143                 if (value != null && !declaringClass.isAnnotation())
1144                         throw new IllegalArgumentException(
1145                                         "cannot set annotation default value of a method " +
1146                                         "of a non-annotation class.");
1147
1148                 defaultValue = value;
1149         }
1150
1151         public Object getDefaultValue() {
1152                 return defaultValue;
1153         }
1154
1155         public boolean test() throws SecurityException, NoSuchMethodException {
1156                 boolean ok = testGetDefaultValue();
1157
1158                 return super.test() && ok;
1159         }
1160
1161         private boolean testGetDefaultValue() {
1162                 boolean ok = true;
1163                 Object defaultValue = annotatedElement().getDefaultValue();
1164                 
1165                 logHeader("getDefaultValue()");
1166
1167                 if (this.defaultValue == null) {
1168                         ok = ok(defaultValue == null, "test for annotation " +
1169                                         "default value", "there is one, but it should NOT be one!")
1170                                         && ok;
1171                 } else {
1172                         ok = ok(defaultValue != null, "test for annotation " +
1173                                         "default value", "there is NONE, but it should be one!")
1174                                         && ok;
1175
1176                         ok = ok(AnnotationTester.equals(this.defaultValue, defaultValue),
1177                                         "test default value", "expected %s but got %s",
1178                                         this.defaultValue, defaultValue)
1179                                         && ok;
1180                 }
1181
1182                 return ok;
1183         }
1184
1185         protected Annotation[][] getParameterAnnotations() {
1186                 return annotatedElement().getParameterAnnotations();
1187         }
1188 }
1189
1190 class ConstructorAnnotationTester
1191                 extends AbstractMethodAnnotationTester<Constructor<?>> {
1192         public ConstructorAnnotationTester(ClassAnnotationTester clazz,
1193                         Constructor<?> constructor) {
1194                 super(clazz, constructor, constructor.getName(),
1195                                 constructor.getParameterTypes());
1196         }
1197
1198         protected Annotation[][] getParameterAnnotations() {
1199                 return annotatedElement().getParameterAnnotations();
1200         }
1201 }
1202
1203 class ClassAnnotationTester extends AnnotatedElementAnnotationTester<Class<?>> {
1204         private boolean isAnnotation;
1205         
1206         private Map<Constructor<?>, ConstructorAnnotationTester> constructors =
1207                 TestHelper.getMapFactory().
1208                 <Constructor<?>, ConstructorAnnotationTester>createMap();
1209         
1210         private Map<Method, MethodAnnotationTester> methods =
1211                 TestHelper.getMapFactory().
1212                 <Method, MethodAnnotationTester>createMap();
1213         
1214         private Map<String, FieldAnnotationTester> fields =
1215                 TestHelper.getMapFactory().
1216                 <String, FieldAnnotationTester>createMap();
1217
1218         public ClassAnnotationTester(Class<?> clazz, boolean isAnnotation) {
1219                 super(null, clazz, clazz.getName());
1220
1221                 this.isAnnotation = isAnnotation;
1222         }
1223
1224         public ClassAnnotationTester(Class<?> clazz) {
1225                 this(clazz, false);
1226         }
1227
1228         public boolean isAnnotation() {
1229                 return isAnnotation;
1230         }
1231
1232         public FieldAnnotationTester addField(String name)
1233                         throws SecurityException, NoSuchFieldException {
1234                 FieldAnnotationTester field = new FieldAnnotationTester(this,
1235                                 annotatedElement().getField(name));
1236
1237                 if (fields.put(name, field) != null)
1238                         throw new IllegalArgumentException("field already defined");
1239
1240                 return field;
1241         }
1242
1243         public MethodAnnotationTester addMethod(String name, Object defalutValue,
1244                         Class<?>... parameterTypes) throws SecurityException,
1245                         NoSuchMethodException {
1246                 Method reflMethod = annotatedElement().getMethod(
1247                                 name, parameterTypes);
1248                 MethodAnnotationTester method = new MethodAnnotationTester(this,
1249                                 reflMethod, defalutValue);
1250
1251                 if (methods.put(reflMethod, method) != null)
1252                         throw new IllegalArgumentException("method already defined");
1253
1254                 return method;
1255         }
1256
1257         public ConstructorAnnotationTester addConstructor(
1258                         Class<?>... parameterTypes) throws SecurityException,
1259                         NoSuchMethodException {
1260                 Constructor<?> reflConstructor =
1261                         annotatedElement().getConstructor(parameterTypes);
1262                 ConstructorAnnotationTester constructor =
1263                         new ConstructorAnnotationTester(this, reflConstructor);
1264
1265                 if (constructors.put(reflConstructor, constructor) != null)
1266                         throw new IllegalArgumentException("constructor already defined");
1267
1268                 return constructor;
1269         }
1270         
1271         protected void logName() {
1272                 TestHelper.log("== Testing %s ==", getName());
1273         }
1274
1275         public boolean test() throws SecurityException, NoSuchMethodException {
1276                 boolean ok = super.test();
1277                 
1278                 ok = testIsAnnotation() && ok;
1279
1280                 logHeader("Constructors");
1281                 for (ConstructorAnnotationTester tester :
1282                                 TestHelper.sorted(constructors.values())) {
1283                         ok = tester.test() && ok;
1284                 }
1285
1286                 logHeader("Methods");
1287                 for (MethodAnnotationTester tester :
1288                                 TestHelper.sorted(methods.values())) {
1289                         ok = tester.test() && ok;
1290                 }
1291
1292                 logHeader("Fields");
1293                 for (FieldAnnotationTester tester : 
1294                                 TestHelper.sorted(fields.values())) {
1295                         ok = tester.test() && ok;
1296                 }
1297
1298                 log();
1299                 return ok;
1300         }
1301         
1302         private boolean testIsAnnotation() {
1303                 logHeader("isAnnotation()");
1304                 
1305                 return TestHelper.okx(
1306                                 isAnnotation == annotatedElement().isAnnotation(),
1307                                 "test if the isAnnotation attribute is set properly",
1308                                 annotatedElement().getName(),
1309                                 (isAnnotation ? "class should be an annotation, but isn't!"
1310                                                 : "class should NOT be an annotation, but it is!"),
1311                                 EMPTY_OBJECT_ARRAY);
1312         }
1313 }
1314
1315 /* ********* the testcases ****************************************************/
1316
1317 /**
1318  * Test Annotations onto enums and their values.
1319  */
1320 @AnnotationB(string = "onto a enum")
1321 enum EnumA {
1322         @AnnotationB(string = "onto a enum field")
1323         VALUE1,
1324         VALUE2,
1325         VALUE3
1326 }
1327
1328 /**
1329  * Test Annotations on Annotations and their methods. Test Annotation on itself.
1330  */
1331 @Retention(value = RetentionPolicy.RUNTIME)
1332 @AnnotationA(
1333                 integer = 1,
1334                 string  = "onto itself",
1335                 classes = {AnnotationA.class, Class.class},
1336                 enumeration = EnumA.VALUE2)
1337 @interface AnnotationA {
1338         @AnnotationA(
1339                         integer = 2,
1340                         string  = "onto a method of itself")
1341         int        integer();
1342         String     string();
1343         Class<?>[] classes()     default {EnumA.class, Object[][].class};
1344         EnumA      enumeration() default EnumA.VALUE1;
1345 }
1346
1347 /**
1348  * This Annotation will be inherited as Annotation of a derived class.
1349  * Inheritance applies only for class annotations, not for methods or fields.
1350  */
1351 @Inherited
1352 @Retention(value = RetentionPolicy.RUNTIME)
1353 @interface AnnotationB {
1354         String string();
1355         Class<?> clazz() default AnnotationB.class;
1356 }
1357
1358 /**
1359  * Test all possible types of enum fields.
1360  */
1361 @Retention(value = RetentionPolicy.RUNTIME)
1362 @interface AnnotationC {
1363         byte               aByte()            default 100;
1364         char               aChar()            default 'ß';
1365         short              aShort()           default 88;
1366         int                aInt()             default Integer.MIN_VALUE;
1367         long               aLong()            default Long.MAX_VALUE;
1368         float              aFloat()           default 23.42f;
1369         double             aDouble()          default 555.0815d;
1370         String             aString()          default "ÄÖÜ";
1371         EnumA              aEnum()            default EnumA.VALUE2;
1372         Class<?>           aClass()           default EnumA.class;
1373         SuppressWarnings   aAnnotation()      default @SuppressWarnings("unchecked");
1374         byte[]             aByteArray()       default {(byte)255};
1375         char[]             aCharArray()       default {'ä', 'ö', 'ü'};
1376         short[]            aShortArray()      default {512};
1377         int[]              aIntArray()        default {640, 480};
1378         long[]             aLongArray()       default {1204l, 2048l};
1379         float[]            aFloatArray()      default {0.0f};
1380         double[]           aDoubleArray()     default {-2.2d, -3.3d};
1381         String[]           aStringArray()     default {""};
1382         EnumA[]            aEnumArray()       default EnumA.VALUE1;
1383         Class<?>[]         aClassArray()      default void.class;
1384         SuppressWarnings[] aAnnotationArray() default {};
1385 }
1386
1387 /**
1388  * This annotation will not be stored into the class file.
1389  */
1390 @interface AnnotationD {
1391 }
1392
1393 /**
1394  * Test annotations onto a class.
1395  */
1396 @AnnotationB(string = "onto a class", clazz = Foo.class)
1397 @AnnotationA(integer = 3, string = "onto a class")
1398 class Foo {
1399         /**
1400          * Test annotations onto a field.
1401          */
1402         @AnnotationA(integer = 4, string = "onto a field")
1403         public int afield;
1404
1405         /**
1406          * Test annotations onto a constructor.
1407          */
1408         @AnnotationA(integer = 9, string = "onto a constructor")
1409         public Foo() {
1410         }
1411
1412         /**
1413          * Test annotations onto a method.
1414          * 
1415          * @param x
1416          *            Test annotations onto a parameter.
1417          * @return
1418          */
1419         @AnnotationA(integer = 5, string = "onto a method")
1420         public int method(
1421                         @AnnotationA(
1422                                         integer = 6,
1423                                         string  = "onto a parameter")
1424                         int x) {
1425                 return x;
1426         }
1427
1428         /**
1429          * Test annotations onto a static method.
1430          * 
1431          * @param x
1432          *            Test annotations onto a parameter.
1433          * @return
1434          */
1435         @AnnotationA(integer = 7, string = "onto a static method")
1436         public static int staticMethod(
1437                         @AnnotationA(
1438                                         integer = 8,
1439                                         string  = "onto a parameter of a static method")
1440                         int x) {
1441                 return x;
1442         }
1443 }
1444
1445 /**
1446  * Test inheritance of annotations. Test all possible annotation field types as
1447  * default values. Test if an annotation without RetentionPolicy.RUNTIME is
1448  * really not visible at runtime.
1449  */
1450 @AnnotationC
1451 @AnnotationD
1452 class Bar extends Foo {
1453         /**
1454          * Test that superclass field annotations will not be visible here.
1455          */
1456         public int afield;
1457
1458         /**
1459          * Test that superclass constructor annotations will not be visible here.
1460          */
1461         public Bar() {
1462         }
1463
1464         /**
1465          * Test that superclass method (and parameter) annotations will not be
1466          * visible here.
1467          */
1468         public int method(int x) {
1469                 return x;
1470         }
1471
1472         /**
1473          * Test that superclass method (and parameter) annotations will not be
1474          * visible here.
1475          */
1476         public static int staticMethod(int x) {
1477                 return x;
1478         }
1479 }
1480
1481 /**
1482  * Test availability of annotations of inherited fields/methods. Test all
1483  * possible annotation field types. Test if not overloaded (=inherited)
1484  * methods/fields still have their annotations.
1485  */
1486 @AnnotationB(string = "onto a derived class", clazz = Baz.class)
1487 @AnnotationC(
1488                 aByte            = 0,
1489                 aChar            = 'a',
1490                 aShort           = 1,
1491                 aInt             = 2,
1492                 aLong            = 3l,
1493                 aFloat           = 4.4f,
1494                 aDouble          = 5.5d,
1495                 aString          = "a string",
1496                 aEnum            = EnumA.VALUE3,
1497                 aClass           = Class.class,
1498                 aAnnotation      = @SuppressWarnings("unchecked"),
1499                 aByteArray       = {0, 1, 2, 3},
1500                 aCharArray       = {'a', 'b', 'c'},
1501                 aShortArray      = 4,
1502                 aIntArray        = {5, 6, 7},
1503                 aLongArray       = {8l, 9l},
1504                 aFloatArray      = {10.10f, 11.11f, 12.12f},
1505                 aDoubleArray     = {},
1506                 aStringArray     = {"a string","another string"},
1507                 aEnumArray       = {EnumA.VALUE3, EnumA.VALUE3},
1508                 aClassArray      = {Class.class, Integer.class, Long.class},
1509                 aAnnotationArray = {
1510                         @SuppressWarnings(value = "unchecked"),
1511                         @SuppressWarnings(value = {"unused", "deprecation"})})
1512 class Baz extends Foo {
1513 }
1514
1515 /* ********* running the testcases ********************************************/
1516 public class TestAnnotations {
1517         @SuppressWarnings("unchecked")
1518         public static void main(String[] args) {
1519                 boolean ok = true;
1520                 MethodAnnotationTester mtester;
1521
1522                 try {
1523                         ClassAnnotationTester classEnumA       =
1524                                 new ClassAnnotationTester(EnumA.class);
1525                         ClassAnnotationTester classAnnotationA =
1526                                 new ClassAnnotationTester(AnnotationA.class, true);
1527                         ClassAnnotationTester classAnnotationB =
1528                                 new ClassAnnotationTester(AnnotationB.class, true);
1529                         ClassAnnotationTester classAnnotationC =
1530                                 new ClassAnnotationTester(AnnotationC.class, true);
1531                         ClassAnnotationTester classAnnotationD =
1532                                 new ClassAnnotationTester(AnnotationD.class, true);
1533                         ClassAnnotationTester classFoo         =
1534                                 new ClassAnnotationTester(Foo.class);
1535                         ClassAnnotationTester classBar         =
1536                                 new ClassAnnotationTester(Bar.class);
1537                         ClassAnnotationTester classBaz         =
1538                                 new ClassAnnotationTester(Baz.class);
1539
1540                         /* EnumA */
1541                         classEnumA.putDeclaredAnnotation(
1542                                         AnnotationB.class,
1543                                         new Entry("string", "onto a enum"),
1544                                         new Entry("clazz", AnnotationB.class));
1545                         classEnumA.addField("VALUE1").putDeclaredAnnotation(
1546                                         AnnotationB.class,
1547                                         new Entry("string", "onto a enum field"),
1548                                         new Entry("clazz", AnnotationB.class)
1549                         );
1550
1551                         /* AnnotationA */
1552                         classAnnotationA.putDeclaredAnnotation(
1553                                         Retention.class,
1554                                         new Entry("value", RetentionPolicy.RUNTIME)
1555                         );
1556                         classAnnotationA.putDeclaredAnnotation(
1557                                         AnnotationA.class,
1558                                         new Entry("integer", 1),
1559                                         new Entry("string",  "onto itself"),
1560                                         new Entry("classes", new Class<?>[] {
1561                                                         AnnotationA.class, Class.class}),
1562                                         new Entry("enumeration", EnumA.VALUE2)
1563                         );
1564                         classAnnotationA.addMethod("integer", null).putDeclaredAnnotation(
1565                                         AnnotationA.class,
1566                                         new Entry("integer", 2),
1567                                         new Entry("string", "onto a method of itself"),
1568                                         new Entry("classes", new Class<?>[] {
1569                                                         EnumA.class, Object[][].class }),
1570                                         new Entry("enumeration", EnumA.VALUE1)
1571                         );
1572                         classAnnotationA.addMethod("classes", 
1573                                         new Class<?>[] {EnumA.class, Object[][].class});
1574                         classAnnotationA.addMethod("enumeration", EnumA.VALUE1);
1575
1576                         /* AnnotationB */
1577                         classAnnotationB.putDeclaredAnnotation(Inherited.class);
1578                         classAnnotationB.putDeclaredAnnotation(
1579                                         Retention.class,
1580                                         new Entry("value", RetentionPolicy.RUNTIME)
1581                         );
1582                         classAnnotationB.addMethod("clazz", AnnotationB.class);
1583
1584                         /* AnnotationC */
1585                         classAnnotationC.putDeclaredAnnotation(
1586                                         Retention.class,
1587                                         new Entry("value", RetentionPolicy.RUNTIME)
1588                         );
1589
1590                         /* Foo */
1591                         classFoo.putDeclaredAnnotation(
1592                                         AnnotationB.class,
1593                                         new Entry("string", "onto a class"),
1594                                         new Entry("clazz",  Foo.class)
1595                         );
1596                         classFoo.putDeclaredAnnotation(
1597                                         AnnotationA.class,
1598                                         new Entry("integer", 3),
1599                                         new Entry("string",  "onto a class"),
1600                                         new Entry("classes", new Class<?>[] {
1601                                                         EnumA.class, Object[][].class}),
1602                                         new Entry("enumeration", EnumA.VALUE1)
1603                         );
1604                         classFoo.addField("afield").putDeclaredAnnotation(
1605                                         AnnotationA.class,
1606                                         new Entry("integer", 4),
1607                                         new Entry("string",  "onto a field"),
1608                                         new Entry("classes", new Class<?>[] {
1609                                                         EnumA.class, Object[][].class}),
1610                                         new Entry("enumeration", EnumA.VALUE1)
1611                         );
1612                         mtester = classFoo.addMethod("method", null, int.class);
1613                         mtester.putDeclaredAnnotation(
1614                                         AnnotationA.class,
1615                                         new Entry("integer", 5),
1616                                         new Entry("string",  "onto a method"),
1617                                         new Entry("classes", new Class<?>[] {
1618                                                         EnumA.class, Object[][].class}),
1619                                         new Entry("enumeration", EnumA.VALUE1)
1620                         );
1621                         mtester.putParameterAnnotation(0,
1622                                         AnnotationA.class,
1623                                         new Entry("integer", 6),
1624                                         new Entry("string", "onto a parameter"),
1625                                         new Entry("classes", new Class<?>[] {
1626                                                         EnumA.class, Object[][].class}),
1627                                         new Entry("enumeration", EnumA.VALUE1)
1628                         );
1629                         mtester = classFoo.addMethod("staticMethod", null, int.class);
1630                         mtester.putDeclaredAnnotation(
1631                                         AnnotationA.class,
1632                                         new Entry("integer", 7),
1633                                         new Entry("string", "onto a static method"),
1634                                         new Entry("classes", new Class<?>[] {
1635                                                         EnumA.class, Object[][].class }),
1636                                         new Entry("enumeration", EnumA.VALUE1)
1637                         );
1638                         mtester.putParameterAnnotation(0,
1639                                         AnnotationA.class,
1640                                         new Entry("integer", 8),
1641                                         new Entry("string", "onto a parameter of a static method"),
1642                                         new Entry("classes", new Class<?>[] {
1643                                                         EnumA.class, Object[][].class}),
1644                                         new Entry("enumeration", EnumA.VALUE1)
1645                         );
1646                         classFoo.addConstructor().putDeclaredAnnotation(
1647                                         AnnotationA.class,
1648                                         new Entry("integer", 9),
1649                                         new Entry("string", "onto a constructor"),
1650                                         new Entry("classes", new Class<?>[] {
1651                                                         EnumA.class, Object[][].class}),
1652                                         new Entry("enumeration", EnumA.VALUE1)
1653                         );
1654
1655                         /* Bar */
1656                         classBar.putInheritedAnnotation(
1657                                         AnnotationB.class,
1658                                         new Entry("string", "onto a class"),
1659                                         new Entry("clazz", Foo.class)
1660                         );
1661                         classBar.putDeclaredAnnotation(
1662                                         AnnotationC.class,
1663                                         new Entry("aByte",            (byte)100),
1664                                         new Entry("aChar",            (char)'ß'),
1665                                         new Entry("aShort",           (short)88),
1666                                         new Entry("aInt",             Integer.MIN_VALUE),
1667                                         new Entry("aLong",            Long.MAX_VALUE),
1668                                         new Entry("aFloat",           (float)23.42f),
1669                                         new Entry("aDouble",          (double)555.0815d),
1670                                         new Entry("aString",          "ÄÖÜ"),
1671                                         new Entry("aEnum",            EnumA.VALUE2),
1672                                         new Entry("aClass",           EnumA.class),
1673                                         new Entry("aAnnotation",      new AnnotationTester(
1674                                                         SuppressWarnings.class,
1675                                                         new Entry("value", new String[] {"unchecked"}))),
1676                                         new Entry("aByteArray",       new byte[]   {(byte) 255}),
1677                                         new Entry("aCharArray",       new char[]   {'ä', 'ö', 'ü'}),
1678                                         new Entry("aShortArray",      new short[]  {512}),
1679                                         new Entry("aIntArray",        new int[]    {640, 480}),
1680                                         new Entry("aLongArray",       new long[]   {1204l, 2048l}),
1681                                         new Entry("aFloatArray",      new float[]  {0.0f}),
1682                                         new Entry("aDoubleArray",     new double[] {-2.2d, -3.3d}),
1683                                         new Entry("aStringArray",     new String[] {""}),
1684                                         new Entry("aEnumArray",       new EnumA[]  {EnumA.VALUE1}),
1685                                         new Entry("aClassArray",      new Class<?>[] {void.class}),
1686                                         new Entry("aAnnotationArray", new AnnotationTester[] {})
1687                         );
1688                         classBar.addField("afield");
1689                         classBar.addMethod("method", null, int.class);
1690                         classBar.addMethod("staticMethod", null, int.class);
1691                         classBar.addConstructor();
1692
1693                         /* Baz */
1694                         classBaz.putDeclaredAnnotation(
1695                                         AnnotationB.class,
1696                                         new Entry("string", "onto a derived class"),
1697                                         new Entry("clazz",  Baz.class)
1698                         );
1699                         classBaz.putDeclaredAnnotation(
1700                                         AnnotationC.class,
1701                                         new Entry("aByte",            (byte)0),
1702                                         new Entry("aChar",            (char)'a'),
1703                                         new Entry("aShort",           (short)1),
1704                                         new Entry("aInt",             (int)2),
1705                                         new Entry("aLong",            (long)3l),
1706                                         new Entry("aFloat",           (float)4.4f),
1707                                         new Entry("aDouble",          (double)5.5d),
1708                                         new Entry("aString",          "a string"),
1709                                         new Entry("aEnum",            EnumA.VALUE3),
1710                                         new Entry("aClass",           Class.class),
1711                                         new Entry("aAnnotation",      new AnnotationTester(
1712                                                         SuppressWarnings.class,
1713                                                         new Entry("value",new String[] {"unchecked"}))),
1714                                         new Entry("aByteArray",       new byte[]  {0, 1, 2, 3}),
1715                                         new Entry("aCharArray",       new char[]  {'a', 'b', 'c'}),
1716                                         new Entry("aShortArray",      new short[] {4}),
1717                                         new Entry("aIntArray",        new int[]   {5, 6, 7}),
1718                                         new Entry("aLongArray",       new long[]  {8l, 9l}), 
1719                                         new Entry("aFloatArray",      new float[] {
1720                                                         10.10f, 11.11f, 12.12f}),
1721                                         new Entry("aDoubleArray",     new double[] {}),
1722                                         new Entry("aStringArray",     new String[] {
1723                                                         "a string",     "another string"}),
1724                                         new Entry("aEnumArray",       new EnumA[] {
1725                                                         EnumA.VALUE3, EnumA.VALUE3}),
1726                                         new Entry("aClassArray",      new Class<?>[] {
1727                                                         Class.class, Integer.class, Long.class}),
1728                                         new Entry("aAnnotationArray", new AnnotationTester[] {
1729                                                         new AnnotationTester(
1730                                                                         SuppressWarnings.class,
1731                                                                         new Entry("value", new String[] {
1732                                                                                         "unchecked"})),
1733                                                         new AnnotationTester(
1734                                                                         SuppressWarnings.class,
1735                                                                         new Entry("value", new String[] {
1736                                                                                         "unused", "deprecation"}))})
1737                         );
1738                         classBaz.addField("afield").putDeclaredAnnotation(
1739                                         AnnotationA.class,
1740                                         new Entry("integer", 4),
1741                                         new Entry("string", "onto a field"),
1742                                         new Entry("classes", new Class<?>[] {
1743                                                         EnumA.class, Object[][].class}),
1744                                         new Entry("enumeration", EnumA.VALUE1)
1745                         );
1746                         mtester = classBaz.addMethod("method", null, int.class);
1747                         mtester.putDeclaredAnnotation(
1748                                         AnnotationA.class,
1749                                         new Entry("integer", 5),
1750                                         new Entry("string",  "onto a method"),
1751                                         new Entry("classes", new Class<?>[] {
1752                                                         EnumA.class, Object[][].class }),
1753                                         new Entry("enumeration", EnumA.VALUE1)
1754                         );
1755                         mtester.putParameterAnnotation(0,
1756                                         AnnotationA.class,
1757                                         new Entry("integer", 6),
1758                                         new Entry("string",  "onto a parameter"),
1759                                         new Entry("classes", new Class<?>[] {
1760                                                         EnumA.class, Object[][].class }),
1761                                         new Entry("enumeration", EnumA.VALUE1)
1762                         );
1763                         mtester = classBaz.addMethod("staticMethod", null, int.class);
1764                         mtester.putDeclaredAnnotation(
1765                                         AnnotationA.class,
1766                                         new Entry("integer",     7),
1767                                         new Entry("string",      "onto a static method"),
1768                                         new Entry("classes",     new Class<?>[] {
1769                                                         EnumA.class, Object[][].class}),
1770                                         new Entry("enumeration", EnumA.VALUE1)
1771                         );
1772                         mtester.putParameterAnnotation(0,
1773                                         AnnotationA.class,
1774                                         new Entry("integer", 8),
1775                                         new Entry("string",      "onto a parameter of a static method"),
1776                                         new Entry("classes", new Class<?>[] {
1777                                                         EnumA.class, Object[][].class}),
1778                                         new Entry("enumeration", EnumA.VALUE1)
1779                         );
1780
1781                         ok = classEnumA.test();
1782                         ok = classAnnotationA.test() && ok;
1783                         ok = classAnnotationB.test() && ok;
1784                         ok = classAnnotationC.test() && ok;
1785                         ok = classAnnotationD.test() && ok;
1786                         ok = classFoo.test() && ok;
1787                         ok = classBar.test() && ok;
1788                         ok = classBaz.test() && ok;
1789                 } catch (Exception e) {
1790                         ok = TestHelper.ok(false, "exception free execution\n");
1791                         e.printStackTrace();
1792                 }
1793                 
1794                 TestHelper.printStatistics();
1795
1796                 if (!ok) {
1797                         System.exit(1);
1798                 }
1799         }
1800 }