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