1 /* tests/regression/TestAnnotations.java - checks correct functionality of the
4 Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel,
5 C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
6 E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
9 This file is part of CACAO.
11 This program is free software; you can redistribute it and/or
12 modify it under the terms of the GNU General Public License as
13 published by the Free Software Foundation; either version 2, or (at
14 your option) any later version.
16 This program is distributed in the hope that it will be useful, but
17 WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
26 Contact: cacao@cacaojvm.org
28 Authors: Mathias Panzenböck
34 import java.lang.annotation.Annotation;
35 import java.lang.annotation.Inherited;
36 import java.lang.annotation.Retention;
37 import java.lang.annotation.RetentionPolicy;
38 import java.lang.reflect.AnnotatedElement;
39 import java.lang.reflect.Array;
40 import java.lang.reflect.Constructor;
41 import java.lang.reflect.Method;
42 import java.lang.reflect.Field;
43 import java.util.ArrayList;
44 import java.util.Arrays;
45 import java.util.Collection;
46 import java.util.Collections;
47 import java.util.Comparator;
48 import java.util.List;
50 import java.util.HashMap;
51 import java.util.SortedSet;
52 import java.util.TreeMap;
53 import java.util.LinkedHashMap;
55 import java.util.HashSet;
56 import java.util.TreeSet;
57 import java.util.LinkedHashSet;
59 /* ********* helper classes for the tests *************************************/
67 private IndexingType indexingType;
69 public MapFactory(IndexingType indexingType) {
70 this.indexingType = indexingType;
73 public <K, V> Map<K, V> createMap() {
74 switch (indexingType) {
75 case HASH: return new HashMap<K, V>();
76 case LINKED_HASH: return new LinkedHashMap<K, V>();
77 case TREE: return new TreeMap<K, V>();
79 throw new IllegalArgumentException(
80 "Illegal indexing type: " + indexingType);
84 public <K, V> Map<K, V> createMap(Map<? extends K,? extends V> map) {
85 switch (indexingType) {
86 case HASH: return new HashMap<K, V>(map);
87 case LINKED_HASH: return new LinkedHashMap<K, V>(map);
88 case TREE: return new TreeMap<K, V>(map);
90 throw new IllegalArgumentException(
91 "Illegal indexing type: " + indexingType);
97 private IndexingType indexingType;
99 public SetFactory(IndexingType indexingType) {
100 this.indexingType = indexingType;
103 public <E> Set<E> createSet() {
104 switch (indexingType) {
105 case HASH: return new HashSet<E>();
106 case TREE: return new TreeSet<E>();
107 case LINKED_HASH: return new LinkedHashSet<E>();
109 throw new IllegalArgumentException(
110 "Illegal indexing type: " + indexingType);
114 public <E> Set<E> createSet(E[] keys) {
115 Set<E> set = createSet();
124 public <E> Set<E> createSet(Collection<? extends E> collection) {
125 switch (indexingType) {
126 case HASH: return new HashSet<E>(collection);
127 case TREE: return new TreeSet<E>(collection);
128 case LINKED_HASH: return new LinkedHashSet<E>(collection);
130 throw new IllegalArgumentException(
131 "Illegal indexing type: " + indexingType);
137 private static MapFactory mapFactory = new MapFactory(IndexingType.HASH);
138 private static SetFactory setFactory = new SetFactory(IndexingType.HASH);
140 private static long testCount = 0;
141 private static long failCount = 0;
143 public static MapFactory getMapFactory() {
147 public static SetFactory getSetFactory() {
151 public static void clear() {
156 public static long getTestCount() {
160 public static long getFailCount() {
164 public static void printStatistics() {
165 System.out.printf(" passed: %8d\n", testCount - failCount);
166 System.out.printf(" failed: %8d\n", failCount);
167 System.out.printf(" ----------------\n");
168 System.out.printf(" sum: %8d\n", testCount);
171 public static void log() {
172 System.out.println();
175 public static void log(String msg) {
176 System.out.println(msg);
179 public static void log(String fmt, Object... args) {
180 System.out.printf(fmt + "\n", args);
183 public static boolean ok(boolean test, String msg) {
184 return ok(test, "%s", msg);
187 public static boolean ok(boolean test, String fmt, Object... args) {
191 System.out.printf("[ OK ] " + fmt + "\n", args);
195 System.out.printf("[ FAIL ] " + fmt + "\n", args);
200 public static boolean okx(boolean test, String what, String fmt,
201 String errfmt, Object[] args, Object... errargs) {
203 return ok(test, fmt + ": %s\n error: " + errfmt, concat(
204 concat(args, what), errargs));
206 return ok(test, fmt + ": %s", concat(args, what));
209 /* helper methods: */
210 @SuppressWarnings("unchecked")
211 public static <T> T[] concat(T[] firstArray, T... moreElements) {
212 return concat2(firstArray, moreElements);
215 @SuppressWarnings("unchecked")
216 public static <T> T[] concat2(T[] firstArray, T[]... moreArrays) {
217 int length = firstArray.length;
219 for (T[] array : moreArrays) {
220 length += array.length;
223 T[] result = (T[]) Array.newInstance(firstArray.getClass()
224 .getComponentType(), length);
226 System.arraycopy(firstArray, 0, result, 0, firstArray.length);
228 int pos = firstArray.length;
229 for (T[] array : moreArrays) {
230 System.arraycopy(array, 0, result, pos, array.length);
237 public static <T> String str(T object) {
239 if (object == null) {
243 else if (object.getClass().isArray()) {
244 StringBuilder buf = new StringBuilder();
245 int length = Array.getLength(object);
250 buf.append(str(Array.get(object, 0)));
252 for (int i = 1; i < length; ++i) {
254 buf.append(str(Array.get(object, i)));
260 return buf.toString();
263 else if (object instanceof String) {
264 String s = object.toString();
265 StringBuilder buf = new StringBuilder();
269 for (int i = 0; i < s.length(); ++i) {
270 char ch = s.charAt(i);
300 return buf.toString();
302 /* escape Character */
303 else if (object instanceof Character) {
304 switch ((Character) object) {
320 return "'" + object + "'";
324 else if (object instanceof Class) {
325 return ((Class<?>) object).getName();
328 return object.toString();
331 public static <E extends Comparable<? super E>> Collection<E> sorted(
332 Collection<E> collection) {
333 if (collection instanceof SortedSet) {
337 List<E> reply = new ArrayList<E>(collection);
338 Collections.sort(reply);
344 public static <E> Collection<E> sorted(
345 Collection<E> collection,
346 Comparator<? super E> comparator) {
347 if (collection instanceof SortedSet) {
351 List<E> reply = new ArrayList<E>(collection);
352 Collections.sort(reply, comparator);
358 public static <E extends Comparable<? super E>> E[] sorted(E[] values) {
363 public static <E> E[] sorted(
365 Comparator<? super E> comparator) {
366 Arrays.sort(values, comparator);
371 class Entry implements Map.Entry<String, Object> {
375 public Entry(String key, Object value) {
380 public String getKey() {
384 public Object getValue() {
388 public Object setValue(Object value) {
394 public int hashCode() {
395 return (key != null ? key.hashCode() << 8 : 0)
396 ^ (val != null ? val.hashCode() : 0);
399 public boolean equals(Object other) {
400 if (other != null && other instanceof Entry) {
401 Entry otherEntry = (Entry) other;
403 return (key == null ? otherEntry.key == null :
404 key.equals(otherEntry.key))
405 && (val == null ? otherEntry.val == null :
406 val.equals(otherEntry.val));
413 class AnnotationTester implements Comparable<AnnotationTester> {
414 private Class<? extends Annotation> annotationType;
416 private Map<String, Object> values =
417 TestHelper.getMapFactory().<String, Object>createMap();
419 public AnnotationTester(Class<? extends Annotation> annotationType,
420 Map<String, Object> values) {
421 this.annotationType = annotationType;
422 this.values.putAll(values);
427 public AnnotationTester(Class<? extends Annotation> annotationType) {
428 this.annotationType = annotationType;
433 public AnnotationTester(Class<? extends Annotation> annotationType,
434 Map.Entry<String, Object>... values) {
435 this.annotationType = annotationType;
437 for (Map.Entry<String, Object> value : values) {
438 if (this.values.put(value.getKey(), value.getValue()) != null)
439 throw new IllegalArgumentException(
440 "duplicated key: " + TestHelper.str(value.getKey()));
446 public Class<? extends Annotation> annotationType() {
447 return annotationType;
450 private void checkValues() {
451 for (String methodName : values.keySet()) {
453 annotationType.getDeclaredMethod(methodName);
454 } catch (NoSuchMethodException e) {
455 throw new IllegalArgumentException(
456 "annotation " + annotationType.getName() +
457 " has no method of name " + methodName + "()", e);
461 for (Method method : annotationType.getDeclaredMethods()) {
462 Object value = values.get(method.getName());
463 Class<?> returnType = method.getReturnType();
464 Class<?> valueType = value.getClass();
467 throw new IllegalArgumentException(
468 "annotation method of name " + method.getName() +
469 "() needs an expected value");
470 } else if (value instanceof AnnotationTester) {
471 AnnotationTester tester = (AnnotationTester) value;
473 if (!tester.annotationType().equals(returnType)) {
474 throw new IllegalArgumentException(
475 "illegal value type for annotation method " +
476 method.getName() + "()");
478 } else if (!returnType.isInstance(value)) {
479 if (returnType.isArray()
480 && returnType.getComponentType().isAnnotation()) {
481 if (!valueType.isArray()
482 || !isSubclassOf(valueType.getComponentType(),
483 AnnotationTester.class)) {
484 throw new IllegalArgumentException(
485 "illegal value type for annotation method " +
486 method.getName() + "()");
489 for (AnnotationTester tester : (AnnotationTester[]) value) {
490 if (!tester.annotationType().equals(
491 returnType.getComponentType())) {
492 throw new IllegalArgumentException(
493 "illegal value type for annotation method " +
494 method.getName() + "()");
497 } else if (!returnType.isPrimitive()
498 || !valueType.equals(getBoxingType(returnType))) {
499 throw new IllegalArgumentException(
500 "illegal value type for annotation method " +
501 method.getName() + "()");
507 public static boolean isSubclassOf(Class<?> subClass, Class<?> superClass) {
509 if (subClass.equals(superClass)) {
512 subClass = subClass.getSuperclass();
513 } while (subClass != null);
518 private static Map<Class<?>, Class<?>> boxingMap =
519 TestHelper.getMapFactory().<Class<?>, Class<?>>createMap();
522 boxingMap.put(byte.class, Byte.class);
523 boxingMap.put(char.class, Character.class);
524 boxingMap.put(short.class, Short.class);
525 boxingMap.put(long.class, Long.class);
526 boxingMap.put(int.class, Integer.class);
527 boxingMap.put(float.class, Float.class);
528 boxingMap.put(double.class, Double.class);
531 public static Class<?> getBoxingType(Class<?> primitiveType) {
532 Class<?> type = boxingMap.get(primitiveType);
535 throw new IllegalArgumentException(
536 "illegal type for boxing: " + primitiveType.getName());
542 public int hashCode() {
543 return (annotationType.hashCode() << 8) ^ values.hashCode();
546 public boolean equals(Object other) {
548 if (other instanceof AnnotationTester) {
549 AnnotationTester otherAnnotationTester =
550 (AnnotationTester) other;
552 if (!otherAnnotationTester.annotationType.equals(annotationType) ||
553 otherAnnotationTester.values.size() != values.size())
556 for (Map.Entry<String, Object> entry : values.entrySet()) {
557 if (!otherAnnotationTester.values.containsKey(entry.getKey()) ||
558 !otherAnnotationTester.values.get(
559 entry.getKey()).equals(entry.getValue()))
564 } else if (other instanceof Annotation) {
565 Annotation anno = (Annotation) other;
566 Method[] annotationFields = anno.annotationType()
567 .getDeclaredMethods();
569 if (!annotationType.equals(anno.annotationType())
570 || annotationFields.length != values.size())
573 for (Method method : annotationFields) {
574 if (!values.get(method.getName()).equals(
575 method.getDefaultValue()))
585 public String toString() {
586 StringBuilder buf = new StringBuilder();
589 buf.append(annotationType.getName());
593 for (Map.Entry<String, Object> entry : values.entrySet()) {
594 buf.append(entry.getKey());
596 buf.append(TestHelper.str(entry.getValue()));
599 if (i < values.size()) {
605 return buf.toString();
608 private final static Object[] EMPTY_OBJECT_ARRAY = new Object[] {};
610 protected boolean ok(boolean test, String what, String errfmt,
612 return TestHelper.okx(test, what, annotationType.getName(), errfmt,
613 EMPTY_OBJECT_ARRAY, errargs);
616 public boolean test(Annotation annotation) throws SecurityException,
617 NoSuchMethodException {
619 Method[] declaredMedthods = annotation.annotationType()
620 .getDeclaredMethods();
622 TestHelper.log(" * Testing %s", annotationType.getName());
624 ok = ok(annotationType.equals(annotation.annotationType()),
625 "test annotationType", "expected %s but got %s",
626 annotationType, annotation.annotationType());
629 ok = ok(declaredMedthods.length == values.size(),
630 "test annotation methods count", "expected %d but got %d",
631 values.size(), declaredMedthods.length)
634 for (String methodName : TestHelper.sorted(values.keySet())) {
635 Object expected = values.get(methodName);
640 got = annotation.getClass().getMethod(methodName).invoke(
642 } catch (Exception e) {
647 "test invocation of the annotation method " +
649 "exception occured while invokation: %s",
650 ex != null ? ex.getMessage() : "")
654 ex.printStackTrace();
656 ok = ok(got != null, "test return value of " + methodName +
657 "() != null", "got null!")
660 ok = ok(equals(got, expected), "test return value of "
661 + methodName + "()", "expected %s (type: %s) but"
662 + " got %s (type: %s)", TestHelper.str(got), got
663 .getClass().getName(), TestHelper.str(expected),
664 expected.getClass().getName())
673 public static boolean equals(Object a, Object b) {
677 else if (a instanceof Annotation && b instanceof AnnotationTester) {
678 return equals((Annotation) a, (AnnotationTester) b);
680 else if (b instanceof Annotation && a instanceof AnnotationTester) {
681 return equals((Annotation) b, (AnnotationTester) a);
683 else if (a.getClass().isArray()) {
684 if (!b.getClass().isArray()) {
688 int alen = Array.getLength(a);
689 int blen = Array.getLength(b);
695 for (int i = 0; i < alen; ++i) {
696 if (!equals(Array.get(a, i), Array.get(b, i))) {
708 public static boolean equals(Annotation annoation, AnnotationTester tester) {
709 if (!tester.annotationType().equals(annoation.annotationType())) {
714 for (Map.Entry<String, Object> bEntry : tester.values.entrySet()) {
715 Object aValue = annoation.getClass().getMethod(bEntry.getKey())
718 if (!equals(bEntry.getValue(), aValue)) {
722 } catch (Exception e) {
723 // TODO: better error handling?
731 public int compareTo(AnnotationTester other) {
732 return annotationType.getName().compareTo(
733 other.annotationType().getName());
737 abstract class AnnotatedElementAnnotationTester<T extends AnnotatedElement>
738 implements Comparable<AnnotatedElementAnnotationTester<? extends AnnotatedElement>> {
739 protected ClassAnnotationTester declaringClass;
743 private Map<Class<? extends Annotation>, AnnotationTester> annotations =
744 TestHelper.getMapFactory().
745 <Class<? extends Annotation>, AnnotationTester>createMap();
747 private Map<Class<? extends Annotation>, AnnotationTester> declaredAnnotations =
748 TestHelper.getMapFactory().
749 <Class<? extends Annotation>, AnnotationTester>createMap();
751 protected final static Object[] EMPTY_OBJECT_ARRAY = new Object[] {};
753 public AnnotatedElementAnnotationTester(
754 ClassAnnotationTester clazz,
757 this.declaringClass = clazz;
758 this.element = element;
762 public T annotatedElement() {
766 public String getName() {
770 public int compareTo(
771 AnnotatedElementAnnotationTester<? extends AnnotatedElement> other) {
772 return name.compareTo(other.getName());
775 private static Comparator<Annotation> annotationComparator =
776 new Comparator<Annotation>() {
777 public int compare(Annotation o1, Annotation o2) {
778 return o1.annotationType().getName().compareTo(
779 o2.annotationType().getName());
783 protected static Annotation[] sorted(Annotation[] annotations) {
784 return TestHelper.sorted(annotations, annotationComparator);
787 protected boolean ok(
788 boolean test, String what,
789 String errfmt, Object... errargs) {
790 return TestHelper.okx(test, what, name, errfmt,
791 EMPTY_OBJECT_ARRAY, errargs);
794 protected void logName() {
795 TestHelper.log("-- Testing %s --", getName());
798 protected void logHeader(String fmt, Object... args) {
799 TestHelper.log("-- " + getName() + ": Testing " + fmt + " --", args);
802 protected void log() {
806 public void putInheritedAnnotation(
807 Class<? extends Annotation> annotationType,
808 Map.Entry<String, Object>... values) {
809 if (annotations.containsKey(annotationType))
810 throw new IllegalArgumentException(
811 "Annotation already exists: " + annotationType.getName());
813 annotations.put(annotationType,
814 new AnnotationTester(annotationType, values));
817 public void putInheritedAnnotation(
818 Class<? extends Annotation> annotationType,
819 Map<String, Object> values) {
820 if (annotations.containsKey(annotationType))
821 throw new IllegalArgumentException(
822 "Annotation already exists: " + annotationType.getName());
824 annotations.put(annotationType,
825 new AnnotationTester(annotationType, values));
828 public void putDeclaredAnnotation(
829 Class<? extends Annotation> annotationType,
830 Map.Entry<String, Object>... values) {
831 if (annotations.containsKey(annotationType))
832 throw new IllegalArgumentException(
833 "Annotation already exists: " + annotationType.getName());
835 AnnotationTester tester = new AnnotationTester(annotationType, values);
837 annotations.put(annotationType, tester);
838 declaredAnnotations.put(annotationType, tester);
841 public void putDeclaredAnnotation(
842 Class<? extends Annotation> annotationType,
843 Map<String, Object> values) {
844 if (annotations.containsKey(annotationType))
845 throw new IllegalArgumentException(
846 "Annotation already exists: " + annotationType.getName());
848 AnnotationTester tester = new AnnotationTester(annotationType, values);
850 annotations.put(annotationType, tester);
851 declaredAnnotations.put(annotationType, tester);
854 public boolean test() throws SecurityException, NoSuchMethodException {
859 ok = testGetDeclaredAnnotations();
860 ok = testGetAnnotations() && ok;
861 ok = testGetAnnotation() && ok;
862 ok = testIsAnnotationPresent() && ok;
868 private boolean testGetDeclaredAnnotations() throws SecurityException,
869 NoSuchMethodException {
870 Annotation[] declaredAnnotations = element.getDeclaredAnnotations();
872 Set<Class<? extends Annotation>> annoTypes =
873 TestHelper.getSetFactory().<Class<? extends Annotation>>createSet();
875 logHeader("getDeclaredAnnotations()");
877 ok = ok(this.declaredAnnotations.size() == declaredAnnotations.length,
878 "test declared annotations count", "expected %d but got %d",
879 this.declaredAnnotations.size(), declaredAnnotations.length)
882 for (Annotation anno : sorted(declaredAnnotations)) {
883 AnnotationTester tester = this.annotations.get(
884 anno.annotationType());
886 ok = ok(!annoTypes.contains(anno.annotationType()),
887 "test unique occurrence of the annotation type " +
888 anno.annotationType().getName(),
889 "duplicated annotation!") && ok;
891 annoTypes.add(anno.annotationType());
893 ok = ok(tester != null, "test if annotation " +
894 anno.annotationType().getName() + " should be there",
895 "wrong annotation") && ok;
897 if (tester != null) {
898 ok = tester.test(anno) && ok;
905 private boolean testGetAnnotations() throws SecurityException,
906 NoSuchMethodException {
907 Annotation[] annotations = element.getAnnotations();
909 Set<Class<? extends Annotation>> annoTypes =
910 TestHelper.getSetFactory().<Class<? extends Annotation>>createSet();
912 logHeader("getAnnotations()");
914 ok = ok(this.annotations.size() == annotations.length,
915 "test annotations count", "expected %d but got %d",
916 this.annotations.size(), annotations.length)
919 for (Annotation anno : sorted(annotations)) {
920 AnnotationTester tester = this.annotations.get(anno
923 ok = ok(!annoTypes.contains(anno.annotationType()),
924 "test unique occurrence of the annotation type " +
925 anno.annotationType().getName(),
926 "duplicated annotation!")
929 annoTypes.add(anno.annotationType());
931 ok = ok(tester != null, "test if annotation " +
932 anno.annotationType().getName() + " should be there",
936 if (tester != null) {
937 ok = tester.test(anno) && ok;
944 private boolean testGetAnnotation() throws SecurityException,
945 NoSuchMethodException {
948 logHeader("getAnnotation(Class<? extends Annotation>)");
950 for (AnnotationTester tester : TestHelper.sorted(annotations.values())) {
951 Class<? extends Annotation> annotationType = tester
953 Annotation anno = element.getAnnotation(annotationType);
955 ok = ok(anno != null, "try to get required annotation " +
956 annotationType.getName() +
957 " using getAnnotation(Class<? extends Annotation>)",
958 "annotation dose not exist")
962 ok = tester.test(anno) && ok;
969 private boolean testIsAnnotationPresent() {
972 logHeader("isAnnotationPresent(Class<? extends Annotation>)");
974 for (AnnotationTester tester : TestHelper.sorted(annotations.values())) {
975 Class<? extends Annotation> annotationType =
976 tester.annotationType();
978 ok = ok(element.isAnnotationPresent(annotationType),
979 "test if annotation " + annotationType.getName() +
980 " is present using isAnnotationPresent()",
981 "annotation dose not exist")
989 class FieldAnnotationTester extends AnnotatedElementAnnotationTester<Field> {
990 public FieldAnnotationTester(ClassAnnotationTester clazz, Field field) {
991 super(clazz, field, field.getDeclaringClass().getName() + "." +
996 abstract class AbstractMethodAnnotationTester<T extends AnnotatedElement>
997 extends AnnotatedElementAnnotationTester<T> {
998 private Map<Class<? extends Annotation>, AnnotationTester>[] parameterAnnotations;
1000 @SuppressWarnings("unchecked")
1001 public AbstractMethodAnnotationTester(ClassAnnotationTester clazz,
1002 T element, String name, Class<?>[] parameterTypes) {
1003 super(clazz, element,
1004 methodName(clazz.annotatedElement(), name, parameterTypes));
1006 parameterAnnotations = new Map[parameterTypes.length];
1008 MapFactory mapFactory = TestHelper.getMapFactory();
1010 for (int i = 0; i < parameterTypes.length; ++i) {
1011 parameterAnnotations[i] = mapFactory.
1012 <Class<? extends Annotation>, AnnotationTester>createMap();
1016 private static String methodName(Class<?> declaringClass, String name,
1017 Class<?>[] parameterTypes) {
1018 StringBuilder buf = new StringBuilder(128);
1020 buf.append(declaringClass.getName());
1025 if (parameterTypes.length > 0) {
1026 buf.append(parameterTypes[0].getName());
1028 for (int i = 1; i < parameterTypes.length; ++i) {
1030 buf.append(parameterTypes[i].getName());
1036 return buf.toString();
1039 abstract protected Annotation[][] getParameterAnnotations();
1041 public void putParameterAnnotation(int index,
1042 Class<? extends Annotation> annotationType,
1043 Map.Entry<String, Object>... values) {
1044 if (parameterAnnotations[index].containsKey(annotationType))
1045 throw new IllegalArgumentException(
1046 "Annotation already exists: " + annotationType.getName());
1048 parameterAnnotations[index].put(
1050 new AnnotationTester(annotationType, values));
1053 public void putParameterAnnotation(int index,
1054 Class<? extends Annotation> annotationType,
1055 Map<String, Object> values) {
1056 if (parameterAnnotations[index].containsKey(annotationType))
1057 throw new IllegalArgumentException(
1058 "Annotation already exists: " + annotationType.getName());
1060 parameterAnnotations[index].put(
1062 new AnnotationTester(annotationType, values));
1065 public boolean test() throws SecurityException, NoSuchMethodException {
1066 boolean ok = super.test();
1068 ok = testParameterAnnotations() && ok;
1073 private boolean testParameterAnnotations() throws SecurityException,
1074 NoSuchMethodException {
1076 Annotation[][] parameterAnnotations = getParameterAnnotations();
1078 logHeader("getParameterAnnotations()");
1081 this.parameterAnnotations.length == parameterAnnotations.length,
1082 "test parameter count", "expected %d but got %d",
1083 this.parameterAnnotations.length, parameterAnnotations.length)
1086 if (this.parameterAnnotations.length == parameterAnnotations.length) {
1087 for (int i = 0; i < parameterAnnotations.length; ++i) {
1088 Set<Class<? extends Annotation>> annoTypes =
1089 TestHelper.getSetFactory().
1090 <Class<? extends Annotation>>createSet();
1093 this.parameterAnnotations[i].size() == parameterAnnotations[i].length,
1094 "test parameter annotations count for parameter " + i,
1095 "expected %d but got %d",
1096 Integer.valueOf(this.parameterAnnotations.length),
1097 Integer.valueOf(parameterAnnotations.length))
1100 for (Annotation anno : sorted(parameterAnnotations[i])) {
1101 AnnotationTester tester =
1102 this.parameterAnnotations[i].get(anno.annotationType());
1104 ok = ok(!annoTypes.contains(anno.annotationType()),
1105 "test unique occurrence of the annotation type " +
1106 anno.annotationType().getName(),
1107 "duplicated annotation!")
1110 annoTypes.add(anno.annotationType());
1112 ok = ok(tester != null, "test if annotation of type " +
1113 anno.annotationType().getName() +
1114 " should be defined for parameter " + i,
1115 "no, it shouldn't be!")
1118 if (tester != null) {
1119 ok = tester.test(anno) && ok;
1129 class MethodAnnotationTester extends AbstractMethodAnnotationTester<Method> {
1130 private Object defaultValue = null;
1132 public MethodAnnotationTester(ClassAnnotationTester clazz, Method method) {
1133 super(clazz, method, method.getName(), method.getParameterTypes());
1136 public MethodAnnotationTester(ClassAnnotationTester clazz, Method method,
1137 Object defaultValue) {
1138 this(clazz, method);
1139 setDefaultValue(defaultValue);
1142 public void setDefaultValue(Object value) {
1143 if (value != null && !declaringClass.isAnnotation())
1144 throw new IllegalArgumentException(
1145 "cannot set annotation default value of a method " +
1146 "of a non-annotation class.");
1148 defaultValue = value;
1151 public Object getDefaultValue() {
1152 return defaultValue;
1155 public boolean test() throws SecurityException, NoSuchMethodException {
1156 boolean ok = testGetDefaultValue();
1158 return super.test() && ok;
1161 private boolean testGetDefaultValue() {
1163 Object defaultValue = annotatedElement().getDefaultValue();
1165 logHeader("getDefaultValue()");
1167 if (this.defaultValue == null) {
1168 ok = ok(defaultValue == null, "test for annotation " +
1169 "default value", "there is one, but it should NOT be one!")
1172 ok = ok(defaultValue != null, "test for annotation " +
1173 "default value", "there is NONE, but it should be one!")
1176 ok = ok(AnnotationTester.equals(this.defaultValue, defaultValue),
1177 "test default value", "expected %s but got %s",
1178 this.defaultValue, defaultValue)
1185 protected Annotation[][] getParameterAnnotations() {
1186 return annotatedElement().getParameterAnnotations();
1190 class ConstructorAnnotationTester
1191 extends AbstractMethodAnnotationTester<Constructor<?>> {
1192 public ConstructorAnnotationTester(ClassAnnotationTester clazz,
1193 Constructor<?> constructor) {
1194 super(clazz, constructor, constructor.getName(),
1195 constructor.getParameterTypes());
1198 protected Annotation[][] getParameterAnnotations() {
1199 return annotatedElement().getParameterAnnotations();
1203 class ClassAnnotationTester extends AnnotatedElementAnnotationTester<Class<?>> {
1204 private boolean isAnnotation;
1206 private Map<Constructor<?>, ConstructorAnnotationTester> constructors =
1207 TestHelper.getMapFactory().
1208 <Constructor<?>, ConstructorAnnotationTester>createMap();
1210 private Map<Method, MethodAnnotationTester> methods =
1211 TestHelper.getMapFactory().
1212 <Method, MethodAnnotationTester>createMap();
1214 private Map<String, FieldAnnotationTester> fields =
1215 TestHelper.getMapFactory().
1216 <String, FieldAnnotationTester>createMap();
1218 public ClassAnnotationTester(Class<?> clazz, boolean isAnnotation) {
1219 super(null, clazz, clazz.getName());
1221 this.isAnnotation = isAnnotation;
1224 public ClassAnnotationTester(Class<?> clazz) {
1228 public boolean isAnnotation() {
1229 return isAnnotation;
1232 public FieldAnnotationTester addField(String name)
1233 throws SecurityException, NoSuchFieldException {
1234 FieldAnnotationTester field = new FieldAnnotationTester(this,
1235 annotatedElement().getField(name));
1237 if (fields.put(name, field) != null)
1238 throw new IllegalArgumentException("field already defined");
1243 public MethodAnnotationTester addMethod(String name, Object defalutValue,
1244 Class<?>... parameterTypes) throws SecurityException,
1245 NoSuchMethodException {
1246 Method reflMethod = annotatedElement().getMethod(
1247 name, parameterTypes);
1248 MethodAnnotationTester method = new MethodAnnotationTester(this,
1249 reflMethod, defalutValue);
1251 if (methods.put(reflMethod, method) != null)
1252 throw new IllegalArgumentException("method already defined");
1257 public ConstructorAnnotationTester addConstructor(
1258 Class<?>... parameterTypes) throws SecurityException,
1259 NoSuchMethodException {
1260 Constructor<?> reflConstructor =
1261 annotatedElement().getConstructor(parameterTypes);
1262 ConstructorAnnotationTester constructor =
1263 new ConstructorAnnotationTester(this, reflConstructor);
1265 if (constructors.put(reflConstructor, constructor) != null)
1266 throw new IllegalArgumentException("constructor already defined");
1271 protected void logName() {
1272 TestHelper.log("== Testing %s ==", getName());
1275 public boolean test() throws SecurityException, NoSuchMethodException {
1276 boolean ok = super.test();
1278 ok = testIsAnnotation() && ok;
1280 logHeader("Constructors");
1281 for (ConstructorAnnotationTester tester :
1282 TestHelper.sorted(constructors.values())) {
1283 ok = tester.test() && ok;
1286 logHeader("Methods");
1287 for (MethodAnnotationTester tester :
1288 TestHelper.sorted(methods.values())) {
1289 ok = tester.test() && ok;
1292 logHeader("Fields");
1293 for (FieldAnnotationTester tester :
1294 TestHelper.sorted(fields.values())) {
1295 ok = tester.test() && ok;
1302 private boolean testIsAnnotation() {
1303 logHeader("isAnnotation()");
1305 return TestHelper.okx(
1306 isAnnotation == annotatedElement().isAnnotation(),
1307 "test if the isAnnotation attribute is set properly",
1308 annotatedElement().getName(),
1309 (isAnnotation ? "class should be an annotation, but isn't!"
1310 : "class should NOT be an annotation, but it is!"),
1311 EMPTY_OBJECT_ARRAY);
1315 /* ********* the testcases ****************************************************/
1318 * Test Annotations onto enums and their values.
1320 @AnnotationB(string = "onto a enum")
1322 @AnnotationB(string = "onto a enum field")
1329 * Test Annotations on Annotations and their methods. Test Annotation on itself.
1331 @Retention(value = RetentionPolicy.RUNTIME)
1334 string = "onto itself",
1335 classes = {AnnotationA.class, Class.class},
1336 enumeration = EnumA.VALUE2)
1337 @interface AnnotationA {
1340 string = "onto a method of itself")
1343 Class<?>[] classes() default {EnumA.class, Object[][].class};
1344 EnumA enumeration() default EnumA.VALUE1;
1348 * This Annotation will be inherited as Annotation of a derived class.
1349 * Inheritance applies only for class annotations, not for methods or fields.
1352 @Retention(value = RetentionPolicy.RUNTIME)
1353 @interface AnnotationB {
1355 Class<?> clazz() default AnnotationB.class;
1359 * Test all possible types of enum fields.
1361 @Retention(value = RetentionPolicy.RUNTIME)
1362 @interface AnnotationC {
1363 byte aByte() default 100;
1364 char aChar() default 'ß';
1365 short aShort() default 88;
1366 int aInt() default Integer.MIN_VALUE;
1367 long aLong() default Long.MAX_VALUE;
1368 float aFloat() default 23.42f;
1369 double aDouble() default 555.0815d;
1370 String aString() default "ÄÖÜ";
1371 EnumA aEnum() default EnumA.VALUE2;
1372 Class<?> aClass() default EnumA.class;
1373 SuppressWarnings aAnnotation() default @SuppressWarnings("unchecked");
1374 byte[] aByteArray() default {(byte)255};
1375 char[] aCharArray() default {'ä', 'ö', 'ü'};
1376 short[] aShortArray() default {512};
1377 int[] aIntArray() default {640, 480};
1378 long[] aLongArray() default {1204l, 2048l};
1379 float[] aFloatArray() default {0.0f};
1380 double[] aDoubleArray() default {-2.2d, -3.3d};
1381 String[] aStringArray() default {""};
1382 EnumA[] aEnumArray() default EnumA.VALUE1;
1383 Class<?>[] aClassArray() default void.class;
1384 SuppressWarnings[] aAnnotationArray() default {};
1388 * This annotation will not be stored into the class file.
1390 @interface AnnotationD {
1394 * Test annotations onto a class.
1396 @AnnotationB(string = "onto a class", clazz = Foo.class)
1397 @AnnotationA(integer = 3, string = "onto a class")
1400 * Test annotations onto a field.
1402 @AnnotationA(integer = 4, string = "onto a field")
1406 * Test annotations onto a constructor.
1408 @AnnotationA(integer = 9, string = "onto a constructor")
1413 * Test annotations onto a method.
1416 * Test annotations onto a parameter.
1419 @AnnotationA(integer = 5, string = "onto a method")
1423 string = "onto a parameter")
1429 * Test annotations onto a static method.
1432 * Test annotations onto a parameter.
1435 @AnnotationA(integer = 7, string = "onto a static method")
1436 public static int staticMethod(
1439 string = "onto a parameter of a static method")
1446 * Test inheritance of annotations. Test all possible annotation field types as
1447 * default values. Test if an annotation without RetentionPolicy.RUNTIME is
1448 * really not visible at runtime.
1452 class Bar extends Foo {
1454 * Test that superclass field annotations will not be visible here.
1459 * Test that superclass constructor annotations will not be visible here.
1465 * Test that superclass method (and parameter) annotations will not be
1468 public int method(int x) {
1473 * Test that superclass method (and parameter) annotations will not be
1476 public static int staticMethod(int x) {
1482 * Test availability of annotations of inherited fields/methods. Test all
1483 * possible annotation field types. Test if not overloaded (=inherited)
1484 * methods/fields still have their annotations.
1486 @AnnotationB(string = "onto a derived class", clazz = Baz.class)
1495 aString = "a string",
1496 aEnum = EnumA.VALUE3,
1497 aClass = Class.class,
1498 aAnnotation = @SuppressWarnings("unchecked"),
1499 aByteArray = {0, 1, 2, 3},
1500 aCharArray = {'a', 'b', 'c'},
1502 aIntArray = {5, 6, 7},
1503 aLongArray = {8l, 9l},
1504 aFloatArray = {10.10f, 11.11f, 12.12f},
1506 aStringArray = {"a string","another string"},
1507 aEnumArray = {EnumA.VALUE3, EnumA.VALUE3},
1508 aClassArray = {Class.class, Integer.class, Long.class},
1509 aAnnotationArray = {
1510 @SuppressWarnings(value = "unchecked"),
1511 @SuppressWarnings(value = {"unused", "deprecation"})})
1512 class Baz extends Foo {
1515 /* ********* running the testcases ********************************************/
1516 public class TestAnnotations {
1517 @SuppressWarnings("unchecked")
1518 public static void main(String[] args) {
1520 MethodAnnotationTester mtester;
1523 ClassAnnotationTester classEnumA =
1524 new ClassAnnotationTester(EnumA.class);
1525 ClassAnnotationTester classAnnotationA =
1526 new ClassAnnotationTester(AnnotationA.class, true);
1527 ClassAnnotationTester classAnnotationB =
1528 new ClassAnnotationTester(AnnotationB.class, true);
1529 ClassAnnotationTester classAnnotationC =
1530 new ClassAnnotationTester(AnnotationC.class, true);
1531 ClassAnnotationTester classAnnotationD =
1532 new ClassAnnotationTester(AnnotationD.class, true);
1533 ClassAnnotationTester classFoo =
1534 new ClassAnnotationTester(Foo.class);
1535 ClassAnnotationTester classBar =
1536 new ClassAnnotationTester(Bar.class);
1537 ClassAnnotationTester classBaz =
1538 new ClassAnnotationTester(Baz.class);
1541 classEnumA.putDeclaredAnnotation(
1543 new Entry("string", "onto a enum"),
1544 new Entry("clazz", AnnotationB.class));
1545 classEnumA.addField("VALUE1").putDeclaredAnnotation(
1547 new Entry("string", "onto a enum field"),
1548 new Entry("clazz", AnnotationB.class)
1552 classAnnotationA.putDeclaredAnnotation(
1554 new Entry("value", RetentionPolicy.RUNTIME)
1556 classAnnotationA.putDeclaredAnnotation(
1558 new Entry("integer", 1),
1559 new Entry("string", "onto itself"),
1560 new Entry("classes", new Class<?>[] {
1561 AnnotationA.class, Class.class}),
1562 new Entry("enumeration", EnumA.VALUE2)
1564 classAnnotationA.addMethod("integer", null).putDeclaredAnnotation(
1566 new Entry("integer", 2),
1567 new Entry("string", "onto a method of itself"),
1568 new Entry("classes", new Class<?>[] {
1569 EnumA.class, Object[][].class }),
1570 new Entry("enumeration", EnumA.VALUE1)
1572 classAnnotationA.addMethod("classes",
1573 new Class<?>[] {EnumA.class, Object[][].class});
1574 classAnnotationA.addMethod("enumeration", EnumA.VALUE1);
1577 classAnnotationB.putDeclaredAnnotation(Inherited.class);
1578 classAnnotationB.putDeclaredAnnotation(
1580 new Entry("value", RetentionPolicy.RUNTIME)
1582 classAnnotationB.addMethod("clazz", AnnotationB.class);
1585 classAnnotationC.putDeclaredAnnotation(
1587 new Entry("value", RetentionPolicy.RUNTIME)
1591 classFoo.putDeclaredAnnotation(
1593 new Entry("string", "onto a class"),
1594 new Entry("clazz", Foo.class)
1596 classFoo.putDeclaredAnnotation(
1598 new Entry("integer", 3),
1599 new Entry("string", "onto a class"),
1600 new Entry("classes", new Class<?>[] {
1601 EnumA.class, Object[][].class}),
1602 new Entry("enumeration", EnumA.VALUE1)
1604 classFoo.addField("afield").putDeclaredAnnotation(
1606 new Entry("integer", 4),
1607 new Entry("string", "onto a field"),
1608 new Entry("classes", new Class<?>[] {
1609 EnumA.class, Object[][].class}),
1610 new Entry("enumeration", EnumA.VALUE1)
1612 mtester = classFoo.addMethod("method", null, int.class);
1613 mtester.putDeclaredAnnotation(
1615 new Entry("integer", 5),
1616 new Entry("string", "onto a method"),
1617 new Entry("classes", new Class<?>[] {
1618 EnumA.class, Object[][].class}),
1619 new Entry("enumeration", EnumA.VALUE1)
1621 mtester.putParameterAnnotation(0,
1623 new Entry("integer", 6),
1624 new Entry("string", "onto a parameter"),
1625 new Entry("classes", new Class<?>[] {
1626 EnumA.class, Object[][].class}),
1627 new Entry("enumeration", EnumA.VALUE1)
1629 mtester = classFoo.addMethod("staticMethod", null, int.class);
1630 mtester.putDeclaredAnnotation(
1632 new Entry("integer", 7),
1633 new Entry("string", "onto a static method"),
1634 new Entry("classes", new Class<?>[] {
1635 EnumA.class, Object[][].class }),
1636 new Entry("enumeration", EnumA.VALUE1)
1638 mtester.putParameterAnnotation(0,
1640 new Entry("integer", 8),
1641 new Entry("string", "onto a parameter of a static method"),
1642 new Entry("classes", new Class<?>[] {
1643 EnumA.class, Object[][].class}),
1644 new Entry("enumeration", EnumA.VALUE1)
1646 classFoo.addConstructor().putDeclaredAnnotation(
1648 new Entry("integer", 9),
1649 new Entry("string", "onto a constructor"),
1650 new Entry("classes", new Class<?>[] {
1651 EnumA.class, Object[][].class}),
1652 new Entry("enumeration", EnumA.VALUE1)
1656 classBar.putInheritedAnnotation(
1658 new Entry("string", "onto a class"),
1659 new Entry("clazz", Foo.class)
1661 classBar.putDeclaredAnnotation(
1663 new Entry("aByte", (byte)100),
1664 new Entry("aChar", (char)'ß'),
1665 new Entry("aShort", (short)88),
1666 new Entry("aInt", Integer.MIN_VALUE),
1667 new Entry("aLong", Long.MAX_VALUE),
1668 new Entry("aFloat", (float)23.42f),
1669 new Entry("aDouble", (double)555.0815d),
1670 new Entry("aString", "ÄÖÜ"),
1671 new Entry("aEnum", EnumA.VALUE2),
1672 new Entry("aClass", EnumA.class),
1673 new Entry("aAnnotation", new AnnotationTester(
1674 SuppressWarnings.class,
1675 new Entry("value", new String[] {"unchecked"}))),
1676 new Entry("aByteArray", new byte[] {(byte) 255}),
1677 new Entry("aCharArray", new char[] {'ä', 'ö', 'ü'}),
1678 new Entry("aShortArray", new short[] {512}),
1679 new Entry("aIntArray", new int[] {640, 480}),
1680 new Entry("aLongArray", new long[] {1204l, 2048l}),
1681 new Entry("aFloatArray", new float[] {0.0f}),
1682 new Entry("aDoubleArray", new double[] {-2.2d, -3.3d}),
1683 new Entry("aStringArray", new String[] {""}),
1684 new Entry("aEnumArray", new EnumA[] {EnumA.VALUE1}),
1685 new Entry("aClassArray", new Class<?>[] {void.class}),
1686 new Entry("aAnnotationArray", new AnnotationTester[] {})
1688 classBar.addField("afield");
1689 classBar.addMethod("method", null, int.class);
1690 classBar.addMethod("staticMethod", null, int.class);
1691 classBar.addConstructor();
1694 classBaz.putDeclaredAnnotation(
1696 new Entry("string", "onto a derived class"),
1697 new Entry("clazz", Baz.class)
1699 classBaz.putDeclaredAnnotation(
1701 new Entry("aByte", (byte)0),
1702 new Entry("aChar", (char)'a'),
1703 new Entry("aShort", (short)1),
1704 new Entry("aInt", (int)2),
1705 new Entry("aLong", (long)3l),
1706 new Entry("aFloat", (float)4.4f),
1707 new Entry("aDouble", (double)5.5d),
1708 new Entry("aString", "a string"),
1709 new Entry("aEnum", EnumA.VALUE3),
1710 new Entry("aClass", Class.class),
1711 new Entry("aAnnotation", new AnnotationTester(
1712 SuppressWarnings.class,
1713 new Entry("value",new String[] {"unchecked"}))),
1714 new Entry("aByteArray", new byte[] {0, 1, 2, 3}),
1715 new Entry("aCharArray", new char[] {'a', 'b', 'c'}),
1716 new Entry("aShortArray", new short[] {4}),
1717 new Entry("aIntArray", new int[] {5, 6, 7}),
1718 new Entry("aLongArray", new long[] {8l, 9l}),
1719 new Entry("aFloatArray", new float[] {
1720 10.10f, 11.11f, 12.12f}),
1721 new Entry("aDoubleArray", new double[] {}),
1722 new Entry("aStringArray", new String[] {
1723 "a string", "another string"}),
1724 new Entry("aEnumArray", new EnumA[] {
1725 EnumA.VALUE3, EnumA.VALUE3}),
1726 new Entry("aClassArray", new Class<?>[] {
1727 Class.class, Integer.class, Long.class}),
1728 new Entry("aAnnotationArray", new AnnotationTester[] {
1729 new AnnotationTester(
1730 SuppressWarnings.class,
1731 new Entry("value", new String[] {
1733 new AnnotationTester(
1734 SuppressWarnings.class,
1735 new Entry("value", new String[] {
1736 "unused", "deprecation"}))})
1738 classBaz.addField("afield").putDeclaredAnnotation(
1740 new Entry("integer", 4),
1741 new Entry("string", "onto a field"),
1742 new Entry("classes", new Class<?>[] {
1743 EnumA.class, Object[][].class}),
1744 new Entry("enumeration", EnumA.VALUE1)
1746 mtester = classBaz.addMethod("method", null, int.class);
1747 mtester.putDeclaredAnnotation(
1749 new Entry("integer", 5),
1750 new Entry("string", "onto a method"),
1751 new Entry("classes", new Class<?>[] {
1752 EnumA.class, Object[][].class }),
1753 new Entry("enumeration", EnumA.VALUE1)
1755 mtester.putParameterAnnotation(0,
1757 new Entry("integer", 6),
1758 new Entry("string", "onto a parameter"),
1759 new Entry("classes", new Class<?>[] {
1760 EnumA.class, Object[][].class }),
1761 new Entry("enumeration", EnumA.VALUE1)
1763 mtester = classBaz.addMethod("staticMethod", null, int.class);
1764 mtester.putDeclaredAnnotation(
1766 new Entry("integer", 7),
1767 new Entry("string", "onto a static method"),
1768 new Entry("classes", new Class<?>[] {
1769 EnumA.class, Object[][].class}),
1770 new Entry("enumeration", EnumA.VALUE1)
1772 mtester.putParameterAnnotation(0,
1774 new Entry("integer", 8),
1775 new Entry("string", "onto a parameter of a static method"),
1776 new Entry("classes", new Class<?>[] {
1777 EnumA.class, Object[][].class}),
1778 new Entry("enumeration", EnumA.VALUE1)
1781 ok = classEnumA.test();
1782 ok = classAnnotationA.test() && ok;
1783 ok = classAnnotationB.test() && ok;
1784 ok = classAnnotationC.test() && ok;
1785 ok = classAnnotationD.test() && ok;
1786 ok = classFoo.test() && ok;
1787 ok = classBar.test() && ok;
1788 ok = classBaz.test() && ok;
1789 } catch (Exception e) {
1790 ok = TestHelper.ok(false, "exception free execution\n");
1791 e.printStackTrace();
1794 TestHelper.printStatistics();