1 /* tests/regression/TestAnnotations.java - checks correct functionality of the
4 Copyright (C) 2007, 2008
5 CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
7 This file is part of CACAO.
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.
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.
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
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;
42 import java.util.HashMap;
43 import java.util.SortedSet;
44 import java.util.TreeMap;
45 import java.util.LinkedHashMap;
47 import java.util.HashSet;
48 import java.util.TreeSet;
49 import java.util.LinkedHashSet;
51 /* ********* helper classes for the tests *************************************/
59 private IndexingType indexingType;
61 public MapFactory(IndexingType indexingType) {
62 this.indexingType = indexingType;
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>();
71 throw new IllegalArgumentException(
72 "Illegal indexing type: " + indexingType);
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);
82 throw new IllegalArgumentException(
83 "Illegal indexing type: " + indexingType);
89 private IndexingType indexingType;
91 public SetFactory(IndexingType indexingType) {
92 this.indexingType = indexingType;
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>();
101 throw new IllegalArgumentException(
102 "Illegal indexing type: " + indexingType);
106 public <E> Set<E> createSet(E[] keys) {
107 Set<E> set = createSet();
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);
122 throw new IllegalArgumentException(
123 "Illegal indexing type: " + indexingType);
129 private static MapFactory mapFactory = new MapFactory(IndexingType.HASH);
130 private static SetFactory setFactory = new SetFactory(IndexingType.HASH);
132 private static long testCount = 0;
133 private static long failCount = 0;
135 public static MapFactory getMapFactory() {
139 public static SetFactory getSetFactory() {
143 public static void clear() {
148 public static long getTestCount() {
152 public static long getFailCount() {
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);
163 public static void log() {
164 System.out.println();
167 public static void log(String msg) {
168 System.out.println(msg);
171 public static void log(String fmt, Object... args) {
172 System.out.printf(fmt + "\n", args);
175 public static boolean ok(boolean test, String msg) {
176 return ok(test, "%s", msg);
179 public static boolean ok(boolean test, String fmt, Object... args) {
183 System.out.printf("[ OK ] " + fmt + "\n", args);
187 System.out.printf("[ FAIL ] " + fmt + "\n", args);
192 public static boolean okx(boolean test, String what, String fmt,
193 String errfmt, Object[] args, Object... errargs) {
195 return ok(test, fmt + ": %s\n error: " + errfmt, concat(
196 concat(args, what), errargs));
198 return ok(test, fmt + ": %s", concat(args, what));
201 /* helper methods: */
202 @SuppressWarnings("unchecked")
203 public static <T> T[] concat(T[] firstArray, T... moreElements) {
204 return concat2(firstArray, moreElements);
207 @SuppressWarnings("unchecked")
208 public static <T> T[] concat2(T[] firstArray, T[]... moreArrays) {
209 int length = firstArray.length;
211 for (T[] array : moreArrays) {
212 length += array.length;
215 T[] result = (T[]) Array.newInstance(firstArray.getClass()
216 .getComponentType(), length);
218 System.arraycopy(firstArray, 0, result, 0, firstArray.length);
220 int pos = firstArray.length;
221 for (T[] array : moreArrays) {
222 System.arraycopy(array, 0, result, pos, array.length);
229 public static <T> String str(T object) {
231 if (object == null) {
235 else if (object.getClass().isArray()) {
236 StringBuilder buf = new StringBuilder();
237 int length = Array.getLength(object);
242 buf.append(str(Array.get(object, 0)));
244 for (int i = 1; i < length; ++i) {
246 buf.append(str(Array.get(object, i)));
252 return buf.toString();
255 else if (object instanceof String) {
256 String s = object.toString();
257 StringBuilder buf = new StringBuilder();
261 for (int i = 0; i < s.length(); ++i) {
262 char ch = s.charAt(i);
292 return buf.toString();
294 /* escape Character */
295 else if (object instanceof Character) {
296 switch ((Character) object) {
312 return "'" + object + "'";
316 else if (object instanceof Class) {
317 return ((Class<?>) object).getName();
320 return object.toString();
323 public static <E extends Comparable<? super E>> Collection<E> sorted(
324 Collection<E> collection) {
325 if (collection instanceof SortedSet) {
329 List<E> reply = new ArrayList<E>(collection);
330 Collections.sort(reply);
336 public static <E> Collection<E> sorted(
337 Collection<E> collection,
338 Comparator<? super E> comparator) {
339 if (collection instanceof SortedSet) {
343 List<E> reply = new ArrayList<E>(collection);
344 Collections.sort(reply, comparator);
350 public static <E extends Comparable<? super E>> E[] sorted(E[] values) {
355 public static <E> E[] sorted(
357 Comparator<? super E> comparator) {
358 Arrays.sort(values, comparator);
363 class Entry implements Map.Entry<String, Object> {
367 public Entry(String key, Object value) {
372 public String getKey() {
376 public Object getValue() {
380 public Object setValue(Object value) {
386 public int hashCode() {
387 return (key != null ? key.hashCode() << 8 : 0)
388 ^ (val != null ? val.hashCode() : 0);
391 public boolean equals(Object other) {
392 if (other != null && other instanceof Entry) {
393 Entry otherEntry = (Entry) other;
395 return (key == null ? otherEntry.key == null :
396 key.equals(otherEntry.key))
397 && (val == null ? otherEntry.val == null :
398 val.equals(otherEntry.val));
405 class AnnotationTester implements Comparable<AnnotationTester> {
406 private Class<? extends Annotation> annotationType;
408 private Map<String, Object> values =
409 TestHelper.getMapFactory().<String, Object>createMap();
411 public AnnotationTester(Class<? extends Annotation> annotationType,
412 Map<String, Object> values) {
413 this.annotationType = annotationType;
414 this.values.putAll(values);
419 public AnnotationTester(Class<? extends Annotation> annotationType) {
420 this.annotationType = annotationType;
425 public AnnotationTester(Class<? extends Annotation> annotationType,
426 Map.Entry<String, Object>... values) {
427 this.annotationType = annotationType;
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()));
438 public Class<? extends Annotation> annotationType() {
439 return annotationType;
442 private void checkValues() {
443 for (String methodName : values.keySet()) {
445 annotationType.getDeclaredMethod(methodName);
446 } catch (NoSuchMethodException e) {
447 throw new IllegalArgumentException(
448 "annotation " + annotationType.getName() +
449 " has no method of name " + methodName + "()", e);
453 for (Method method : annotationType.getDeclaredMethods()) {
454 Object value = values.get(method.getName());
455 Class<?> returnType = method.getReturnType();
456 Class<?> valueType = value.getClass();
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;
465 if (!tester.annotationType().equals(returnType)) {
466 throw new IllegalArgumentException(
467 "illegal value type for annotation method " +
468 method.getName() + "()");
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() + "()");
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() + "()");
489 } else if (!returnType.isPrimitive()
490 || !valueType.equals(getBoxingType(returnType))) {
491 throw new IllegalArgumentException(
492 "illegal value type for annotation method " +
493 method.getName() + "()");
499 public static boolean isSubclassOf(Class<?> subClass, Class<?> superClass) {
501 if (subClass.equals(superClass)) {
504 subClass = subClass.getSuperclass();
505 } while (subClass != null);
510 private static Map<Class<?>, Class<?>> boxingMap =
511 TestHelper.getMapFactory().<Class<?>, Class<?>>createMap();
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);
523 public static Class<?> getBoxingType(Class<?> primitiveType) {
524 Class<?> type = boxingMap.get(primitiveType);
527 throw new IllegalArgumentException(
528 "illegal type for boxing: " + primitiveType.getName());
534 public int hashCode() {
535 return (annotationType.hashCode() << 8) ^ values.hashCode();
538 public boolean equals(Object other) {
540 if (other instanceof AnnotationTester) {
541 AnnotationTester otherAnnotationTester =
542 (AnnotationTester) other;
544 if (!otherAnnotationTester.annotationType.equals(annotationType) ||
545 otherAnnotationTester.values.size() != values.size())
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()))
556 } else if (other instanceof Annotation) {
557 Annotation anno = (Annotation) other;
558 Method[] annotationFields = anno.annotationType()
559 .getDeclaredMethods();
561 if (!annotationType.equals(anno.annotationType())
562 || annotationFields.length != values.size())
565 for (Method method : annotationFields) {
566 if (!values.get(method.getName()).equals(
567 method.getDefaultValue()))
577 public String toString() {
578 StringBuilder buf = new StringBuilder();
581 buf.append(annotationType.getName());
585 for (Map.Entry<String, Object> entry : values.entrySet()) {
586 buf.append(entry.getKey());
588 buf.append(TestHelper.str(entry.getValue()));
591 if (i < values.size()) {
597 return buf.toString();
600 private final static Object[] EMPTY_OBJECT_ARRAY = new Object[] {};
602 protected boolean ok(boolean test, String what, String errfmt,
604 return TestHelper.okx(test, what, annotationType.getName(), errfmt,
605 EMPTY_OBJECT_ARRAY, errargs);
608 public boolean test(Annotation annotation) throws SecurityException,
609 NoSuchMethodException {
611 Method[] declaredMedthods = annotation.annotationType()
612 .getDeclaredMethods();
614 TestHelper.log(" * Testing %s", annotationType.getName());
616 ok = ok(annotationType.equals(annotation.annotationType()),
617 "test annotationType", "expected %s but got %s",
618 annotationType, annotation.annotationType());
621 ok = ok(declaredMedthods.length == values.size(),
622 "test annotation methods count", "expected %d but got %d",
623 values.size(), declaredMedthods.length)
626 for (String methodName : TestHelper.sorted(values.keySet())) {
627 Object expected = values.get(methodName);
632 got = annotation.getClass().getMethod(methodName).invoke(
634 } catch (Exception e) {
639 "test invocation of the annotation method " +
641 "exception occured while invokation: %s",
642 ex != null ? ex.getMessage() : "")
646 ex.printStackTrace();
648 ok = ok(got != null, "test return value of " + methodName +
649 "() != null", "got null!")
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())
665 public static boolean equals(Object a, Object b) {
669 else if (a instanceof Annotation && b instanceof AnnotationTester) {
670 return equals((Annotation) a, (AnnotationTester) b);
672 else if (b instanceof Annotation && a instanceof AnnotationTester) {
673 return equals((Annotation) b, (AnnotationTester) a);
675 else if (a.getClass().isArray()) {
676 if (!b.getClass().isArray()) {
680 int alen = Array.getLength(a);
681 int blen = Array.getLength(b);
687 for (int i = 0; i < alen; ++i) {
688 if (!equals(Array.get(a, i), Array.get(b, i))) {
700 public static boolean equals(Annotation annoation, AnnotationTester tester) {
701 if (!tester.annotationType().equals(annoation.annotationType())) {
706 for (Map.Entry<String, Object> bEntry : tester.values.entrySet()) {
707 Object aValue = annoation.getClass().getMethod(bEntry.getKey())
710 if (!equals(bEntry.getValue(), aValue)) {
714 } catch (Exception e) {
715 // TODO: better error handling?
723 public int compareTo(AnnotationTester other) {
724 return annotationType.getName().compareTo(
725 other.annotationType().getName());
729 abstract class AnnotatedElementAnnotationTester<T extends AnnotatedElement>
730 implements Comparable<AnnotatedElementAnnotationTester<? extends AnnotatedElement>> {
731 protected ClassAnnotationTester declaringClass;
735 private Map<Class<? extends Annotation>, AnnotationTester> annotations =
736 TestHelper.getMapFactory().
737 <Class<? extends Annotation>, AnnotationTester>createMap();
739 private Map<Class<? extends Annotation>, AnnotationTester> declaredAnnotations =
740 TestHelper.getMapFactory().
741 <Class<? extends Annotation>, AnnotationTester>createMap();
743 protected final static Object[] EMPTY_OBJECT_ARRAY = new Object[] {};
745 public AnnotatedElementAnnotationTester(
746 ClassAnnotationTester clazz,
749 this.declaringClass = clazz;
750 this.element = element;
754 public T annotatedElement() {
758 public String getName() {
762 public int compareTo(
763 AnnotatedElementAnnotationTester<? extends AnnotatedElement> other) {
764 return name.compareTo(other.getName());
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());
775 protected static Annotation[] sorted(Annotation[] annotations) {
776 return TestHelper.sorted(annotations, annotationComparator);
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);
786 protected void logName() {
787 TestHelper.log("-- Testing %s --", getName());
790 protected void logHeader(String fmt, Object... args) {
791 TestHelper.log("-- " + getName() + ": Testing " + fmt + " --", args);
794 protected void log() {
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());
805 annotations.put(annotationType,
806 new AnnotationTester(annotationType, values));
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());
816 annotations.put(annotationType,
817 new AnnotationTester(annotationType, values));
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());
827 AnnotationTester tester = new AnnotationTester(annotationType, values);
829 annotations.put(annotationType, tester);
830 declaredAnnotations.put(annotationType, tester);
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());
840 AnnotationTester tester = new AnnotationTester(annotationType, values);
842 annotations.put(annotationType, tester);
843 declaredAnnotations.put(annotationType, tester);
846 public boolean test() throws SecurityException, NoSuchMethodException {
851 ok = testGetDeclaredAnnotations();
852 ok = testGetAnnotations() && ok;
853 ok = testGetAnnotation() && ok;
854 ok = testIsAnnotationPresent() && ok;
860 private boolean testGetDeclaredAnnotations() throws SecurityException,
861 NoSuchMethodException {
862 Annotation[] declaredAnnotations = element.getDeclaredAnnotations();
864 Set<Class<? extends Annotation>> annoTypes =
865 TestHelper.getSetFactory().<Class<? extends Annotation>>createSet();
867 logHeader("getDeclaredAnnotations()");
869 ok = ok(this.declaredAnnotations.size() == declaredAnnotations.length,
870 "test declared annotations count", "expected %d but got %d",
871 this.declaredAnnotations.size(), declaredAnnotations.length)
874 for (Annotation anno : sorted(declaredAnnotations)) {
875 AnnotationTester tester = this.annotations.get(
876 anno.annotationType());
878 ok = ok(!annoTypes.contains(anno.annotationType()),
879 "test unique occurrence of the annotation type " +
880 anno.annotationType().getName(),
881 "duplicated annotation!") && ok;
883 annoTypes.add(anno.annotationType());
885 ok = ok(tester != null, "test if annotation " +
886 anno.annotationType().getName() + " should be there",
887 "wrong annotation") && ok;
889 if (tester != null) {
890 ok = tester.test(anno) && ok;
897 private boolean testGetAnnotations() throws SecurityException,
898 NoSuchMethodException {
899 Annotation[] annotations = element.getAnnotations();
901 Set<Class<? extends Annotation>> annoTypes =
902 TestHelper.getSetFactory().<Class<? extends Annotation>>createSet();
904 logHeader("getAnnotations()");
906 ok = ok(this.annotations.size() == annotations.length,
907 "test annotations count", "expected %d but got %d",
908 this.annotations.size(), annotations.length)
911 for (Annotation anno : sorted(annotations)) {
912 AnnotationTester tester = this.annotations.get(anno
915 ok = ok(!annoTypes.contains(anno.annotationType()),
916 "test unique occurrence of the annotation type " +
917 anno.annotationType().getName(),
918 "duplicated annotation!")
921 annoTypes.add(anno.annotationType());
923 ok = ok(tester != null, "test if annotation " +
924 anno.annotationType().getName() + " should be there",
928 if (tester != null) {
929 ok = tester.test(anno) && ok;
936 private boolean testGetAnnotation() throws SecurityException,
937 NoSuchMethodException {
940 logHeader("getAnnotation(Class<? extends Annotation>)");
942 for (AnnotationTester tester : TestHelper.sorted(annotations.values())) {
943 Class<? extends Annotation> annotationType = tester
945 Annotation anno = element.getAnnotation(annotationType);
947 ok = ok(anno != null, "try to get required annotation " +
948 annotationType.getName() +
949 " using getAnnotation(Class<? extends Annotation>)",
950 "annotation dose not exist")
954 ok = tester.test(anno) && ok;
961 private boolean testIsAnnotationPresent() {
964 logHeader("isAnnotationPresent(Class<? extends Annotation>)");
966 for (AnnotationTester tester : TestHelper.sorted(annotations.values())) {
967 Class<? extends Annotation> annotationType =
968 tester.annotationType();
970 ok = ok(element.isAnnotationPresent(annotationType),
971 "test if annotation " + annotationType.getName() +
972 " is present using isAnnotationPresent()",
973 "annotation dose not exist")
981 class FieldAnnotationTester extends AnnotatedElementAnnotationTester<Field> {
982 public FieldAnnotationTester(ClassAnnotationTester clazz, Field field) {
983 super(clazz, field, field.getDeclaringClass().getName() + "." +
988 abstract class AbstractMethodAnnotationTester<T extends AnnotatedElement>
989 extends AnnotatedElementAnnotationTester<T> {
990 private Map<Class<? extends Annotation>, AnnotationTester>[] parameterAnnotations;
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));
998 parameterAnnotations = new Map[parameterTypes.length];
1000 MapFactory mapFactory = TestHelper.getMapFactory();
1002 for (int i = 0; i < parameterTypes.length; ++i) {
1003 parameterAnnotations[i] = mapFactory.
1004 <Class<? extends Annotation>, AnnotationTester>createMap();
1008 private static String methodName(Class<?> declaringClass, String name,
1009 Class<?>[] parameterTypes) {
1010 StringBuilder buf = new StringBuilder(128);
1012 buf.append(declaringClass.getName());
1017 if (parameterTypes.length > 0) {
1018 buf.append(parameterTypes[0].getName());
1020 for (int i = 1; i < parameterTypes.length; ++i) {
1022 buf.append(parameterTypes[i].getName());
1028 return buf.toString();
1031 abstract protected Annotation[][] getParameterAnnotations();
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());
1040 parameterAnnotations[index].put(
1042 new AnnotationTester(annotationType, values));
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());
1052 parameterAnnotations[index].put(
1054 new AnnotationTester(annotationType, values));
1057 public boolean test() throws SecurityException, NoSuchMethodException {
1058 boolean ok = super.test();
1060 ok = testParameterAnnotations() && ok;
1065 private boolean testParameterAnnotations() throws SecurityException,
1066 NoSuchMethodException {
1068 Annotation[][] parameterAnnotations = getParameterAnnotations();
1070 logHeader("getParameterAnnotations()");
1073 this.parameterAnnotations.length == parameterAnnotations.length,
1074 "test parameter count", "expected %d but got %d",
1075 this.parameterAnnotations.length, parameterAnnotations.length)
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();
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))
1092 for (Annotation anno : sorted(parameterAnnotations[i])) {
1093 AnnotationTester tester =
1094 this.parameterAnnotations[i].get(anno.annotationType());
1096 ok = ok(!annoTypes.contains(anno.annotationType()),
1097 "test unique occurrence of the annotation type " +
1098 anno.annotationType().getName(),
1099 "duplicated annotation!")
1102 annoTypes.add(anno.annotationType());
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!")
1110 if (tester != null) {
1111 ok = tester.test(anno) && ok;
1121 class MethodAnnotationTester extends AbstractMethodAnnotationTester<Method> {
1122 private Object defaultValue = null;
1124 public MethodAnnotationTester(ClassAnnotationTester clazz, Method method) {
1125 super(clazz, method, method.getName(), method.getParameterTypes());
1128 public MethodAnnotationTester(ClassAnnotationTester clazz, Method method,
1129 Object defaultValue) {
1130 this(clazz, method);
1131 setDefaultValue(defaultValue);
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.");
1140 defaultValue = value;
1143 public Object getDefaultValue() {
1144 return defaultValue;
1147 public boolean test() throws SecurityException, NoSuchMethodException {
1148 boolean ok = testGetDefaultValue();
1150 return super.test() && ok;
1153 private boolean testGetDefaultValue() {
1155 Object defaultValue = annotatedElement().getDefaultValue();
1157 logHeader("getDefaultValue()");
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!")
1164 ok = ok(defaultValue != null, "test for annotation " +
1165 "default value", "there is NONE, but it should be one!")
1168 ok = ok(AnnotationTester.equals(this.defaultValue, defaultValue),
1169 "test default value", "expected %s but got %s",
1170 this.defaultValue, defaultValue)
1177 protected Annotation[][] getParameterAnnotations() {
1178 return annotatedElement().getParameterAnnotations();
1182 class ConstructorAnnotationTester
1183 extends AbstractMethodAnnotationTester<Constructor<?>> {
1184 public ConstructorAnnotationTester(ClassAnnotationTester clazz,
1185 Constructor<?> constructor) {
1186 super(clazz, constructor, constructor.getName(),
1187 constructor.getParameterTypes());
1190 protected Annotation[][] getParameterAnnotations() {
1191 return annotatedElement().getParameterAnnotations();
1195 class ClassAnnotationTester extends AnnotatedElementAnnotationTester<Class<?>> {
1196 private boolean isAnnotation;
1198 private Map<Constructor<?>, ConstructorAnnotationTester> constructors =
1199 TestHelper.getMapFactory().
1200 <Constructor<?>, ConstructorAnnotationTester>createMap();
1202 private Map<Method, MethodAnnotationTester> methods =
1203 TestHelper.getMapFactory().
1204 <Method, MethodAnnotationTester>createMap();
1206 private Map<String, FieldAnnotationTester> fields =
1207 TestHelper.getMapFactory().
1208 <String, FieldAnnotationTester>createMap();
1210 public ClassAnnotationTester(Class<?> clazz, boolean isAnnotation) {
1211 super(null, clazz, clazz.getName());
1213 this.isAnnotation = isAnnotation;
1216 public ClassAnnotationTester(Class<?> clazz) {
1220 public boolean isAnnotation() {
1221 return isAnnotation;
1224 public FieldAnnotationTester addField(String name)
1225 throws SecurityException, NoSuchFieldException {
1226 FieldAnnotationTester field = new FieldAnnotationTester(this,
1227 annotatedElement().getField(name));
1229 if (fields.put(name, field) != null)
1230 throw new IllegalArgumentException("field already defined");
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);
1243 if (methods.put(reflMethod, method) != null)
1244 throw new IllegalArgumentException("method already defined");
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);
1257 if (constructors.put(reflConstructor, constructor) != null)
1258 throw new IllegalArgumentException("constructor already defined");
1263 protected void logName() {
1264 TestHelper.log("== Testing %s ==", getName());
1267 public boolean test() throws SecurityException, NoSuchMethodException {
1268 boolean ok = super.test();
1270 ok = testIsAnnotation() && ok;
1272 logHeader("Constructors");
1273 for (ConstructorAnnotationTester tester :
1274 TestHelper.sorted(constructors.values())) {
1275 ok = tester.test() && ok;
1278 logHeader("Methods");
1279 for (MethodAnnotationTester tester :
1280 TestHelper.sorted(methods.values())) {
1281 ok = tester.test() && ok;
1284 logHeader("Fields");
1285 for (FieldAnnotationTester tester :
1286 TestHelper.sorted(fields.values())) {
1287 ok = tester.test() && ok;
1294 private boolean testIsAnnotation() {
1295 logHeader("isAnnotation()");
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);
1307 /* ********* the testcases ****************************************************/
1310 * Test Annotations onto enums and their values.
1312 @AnnotationB(string = "onto a enum")
1314 @AnnotationB(string = "onto a enum field")
1321 * Test Annotations on Annotations and their methods. Test Annotation on itself.
1323 @Retention(value = RetentionPolicy.RUNTIME)
1326 string = "onto itself",
1327 classes = {AnnotationA.class, Class.class},
1328 enumeration = EnumA.VALUE2)
1329 @interface AnnotationA {
1332 string = "onto a method of itself")
1335 Class<?>[] classes() default {EnumA.class, Object[][].class};
1336 EnumA enumeration() default EnumA.VALUE1;
1340 * This Annotation will be inherited as Annotation of a derived class.
1341 * Inheritance applies only for class annotations, not for methods or fields.
1344 @Retention(value = RetentionPolicy.RUNTIME)
1345 @interface AnnotationB {
1347 Class<?> clazz() default AnnotationB.class;
1351 * Test all possible types of enum fields.
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 {};
1380 * This annotation will not be stored into the class file.
1382 @interface AnnotationD {
1386 * Test annotations onto a class.
1388 @AnnotationB(string = "onto a class", clazz = Foo.class)
1389 @AnnotationA(integer = 3, string = "onto a class")
1392 * Test annotations onto a field.
1394 @AnnotationA(integer = 4, string = "onto a field")
1398 * Test annotations onto a constructor.
1400 @AnnotationA(integer = 9, string = "onto a constructor")
1405 * Test annotations onto a method.
1408 * Test annotations onto a parameter.
1411 @AnnotationA(integer = 5, string = "onto a method")
1415 string = "onto a parameter")
1421 * Test annotations onto a static method.
1424 * Test annotations onto a parameter.
1427 @AnnotationA(integer = 7, string = "onto a static method")
1428 public static int staticMethod(
1431 string = "onto a parameter of a static method")
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.
1444 class Bar extends Foo {
1446 * Test that superclass field annotations will not be visible here.
1451 * Test that superclass constructor annotations will not be visible here.
1457 * Test that superclass method (and parameter) annotations will not be
1460 public int method(int x) {
1465 * Test that superclass method (and parameter) annotations will not be
1468 public static int staticMethod(int x) {
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.
1478 @AnnotationB(string = "onto a derived class", clazz = Baz.class)
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'},
1494 aIntArray = {5, 6, 7},
1495 aLongArray = {8l, 9l},
1496 aFloatArray = {10.10f, 11.11f, 12.12f},
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 {
1507 /* ********* running the testcases ********************************************/
1508 public class TestAnnotations {
1509 @SuppressWarnings("unchecked")
1510 public static void main(String[] args) {
1512 MethodAnnotationTester mtester;
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);
1533 classEnumA.putDeclaredAnnotation(
1535 new Entry("string", "onto a enum"),
1536 new Entry("clazz", AnnotationB.class));
1537 classEnumA.addField("VALUE1").putDeclaredAnnotation(
1539 new Entry("string", "onto a enum field"),
1540 new Entry("clazz", AnnotationB.class)
1544 classAnnotationA.putDeclaredAnnotation(
1546 new Entry("value", RetentionPolicy.RUNTIME)
1548 classAnnotationA.putDeclaredAnnotation(
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)
1556 classAnnotationA.addMethod("integer", null).putDeclaredAnnotation(
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)
1564 classAnnotationA.addMethod("classes",
1565 new Class<?>[] {EnumA.class, Object[][].class});
1566 classAnnotationA.addMethod("enumeration", EnumA.VALUE1);
1569 classAnnotationB.putDeclaredAnnotation(Inherited.class);
1570 classAnnotationB.putDeclaredAnnotation(
1572 new Entry("value", RetentionPolicy.RUNTIME)
1574 classAnnotationB.addMethod("clazz", AnnotationB.class);
1577 classAnnotationC.putDeclaredAnnotation(
1579 new Entry("value", RetentionPolicy.RUNTIME)
1583 classFoo.putDeclaredAnnotation(
1585 new Entry("string", "onto a class"),
1586 new Entry("clazz", Foo.class)
1588 classFoo.putDeclaredAnnotation(
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)
1596 classFoo.addField("afield").putDeclaredAnnotation(
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)
1604 mtester = classFoo.addMethod("method", null, int.class);
1605 mtester.putDeclaredAnnotation(
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)
1613 mtester.putParameterAnnotation(0,
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)
1621 mtester = classFoo.addMethod("staticMethod", null, int.class);
1622 mtester.putDeclaredAnnotation(
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)
1630 mtester.putParameterAnnotation(0,
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)
1638 classFoo.addConstructor().putDeclaredAnnotation(
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)
1648 classBar.putInheritedAnnotation(
1650 new Entry("string", "onto a class"),
1651 new Entry("clazz", Foo.class)
1653 classBar.putDeclaredAnnotation(
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[] {})
1680 classBar.addField("afield");
1681 classBar.addMethod("method", null, int.class);
1682 classBar.addMethod("staticMethod", null, int.class);
1683 classBar.addConstructor();
1686 classBaz.putDeclaredAnnotation(
1688 new Entry("string", "onto a derived class"),
1689 new Entry("clazz", Baz.class)
1691 classBaz.putDeclaredAnnotation(
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[] {
1725 new AnnotationTester(
1726 SuppressWarnings.class,
1727 new Entry("value", new String[] {
1728 "unused", "deprecation"}))})
1730 classBaz.addField("afield").putDeclaredAnnotation(
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)
1738 mtester = classBaz.addMethod("method", null, int.class);
1739 mtester.putDeclaredAnnotation(
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)
1747 mtester.putParameterAnnotation(0,
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)
1755 mtester = classBaz.addMethod("staticMethod", null, int.class);
1756 mtester.putDeclaredAnnotation(
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)
1764 mtester.putParameterAnnotation(0,
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)
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();
1786 TestHelper.printStatistics();