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
32 import java.lang.annotation.Annotation;
33 import java.lang.annotation.Inherited;
34 import java.lang.annotation.Retention;
35 import java.lang.annotation.RetentionPolicy;
36 import java.lang.reflect.AnnotatedElement;
37 import java.lang.reflect.Array;
38 import java.lang.reflect.Constructor;
39 import java.lang.reflect.Method;
40 import java.lang.reflect.Field;
41 import java.util.ArrayList;
42 import java.util.Arrays;
43 import java.util.Collection;
44 import java.util.Collections;
45 import java.util.Comparator;
46 import java.util.List;
48 import java.util.HashMap;
49 import java.util.SortedSet;
50 import java.util.TreeMap;
51 import java.util.LinkedHashMap;
53 import java.util.HashSet;
54 import java.util.TreeSet;
55 import java.util.LinkedHashSet;
57 /* ********* helper classes for the tests *************************************/
65 private IndexingType indexingType;
67 public MapFactory(IndexingType indexingType) {
68 this.indexingType = indexingType;
71 public <K, V> Map<K, V> createMap() {
72 switch (indexingType) {
73 case HASH: return new HashMap<K, V>();
74 case LINKED_HASH: return new LinkedHashMap<K, V>();
75 case TREE: return new TreeMap<K, V>();
77 throw new IllegalArgumentException(
78 "Illegal indexing type: " + indexingType);
82 public <K, V> Map<K, V> createMap(Map<? extends K,? extends V> map) {
83 switch (indexingType) {
84 case HASH: return new HashMap<K, V>(map);
85 case LINKED_HASH: return new LinkedHashMap<K, V>(map);
86 case TREE: return new TreeMap<K, V>(map);
88 throw new IllegalArgumentException(
89 "Illegal indexing type: " + indexingType);
95 private IndexingType indexingType;
97 public SetFactory(IndexingType indexingType) {
98 this.indexingType = indexingType;
101 public <E> Set<E> createSet() {
102 switch (indexingType) {
103 case HASH: return new HashSet<E>();
104 case TREE: return new TreeSet<E>();
105 case LINKED_HASH: return new LinkedHashSet<E>();
107 throw new IllegalArgumentException(
108 "Illegal indexing type: " + indexingType);
112 public <E> Set<E> createSet(E[] keys) {
113 Set<E> set = createSet();
122 public <E> Set<E> createSet(Collection<? extends E> collection) {
123 switch (indexingType) {
124 case HASH: return new HashSet<E>(collection);
125 case TREE: return new TreeSet<E>(collection);
126 case LINKED_HASH: return new LinkedHashSet<E>(collection);
128 throw new IllegalArgumentException(
129 "Illegal indexing type: " + indexingType);
135 private static MapFactory mapFactory = new MapFactory(IndexingType.HASH);
136 private static SetFactory setFactory = new SetFactory(IndexingType.HASH);
138 private static long testCount = 0;
139 private static long failCount = 0;
141 public static MapFactory getMapFactory() {
145 public static SetFactory getSetFactory() {
149 public static void clear() {
154 public static long getTestCount() {
158 public static long getFailCount() {
162 public static void printStatistics() {
163 System.out.printf(" passed: %8d\n", testCount - failCount);
164 System.out.printf(" failed: %8d\n", failCount);
165 System.out.printf(" ----------------\n");
166 System.out.printf(" sum: %8d\n", testCount);
169 public static void log() {
170 System.out.println();
173 public static void log(String msg) {
174 System.out.println(msg);
177 public static void log(String fmt, Object... args) {
178 System.out.printf(fmt + "\n", args);
181 public static boolean ok(boolean test, String msg) {
182 return ok(test, "%s", msg);
185 public static boolean ok(boolean test, String fmt, Object... args) {
189 System.out.printf("[ OK ] " + fmt + "\n", args);
193 System.out.printf("[ FAIL ] " + fmt + "\n", args);
198 public static boolean okx(boolean test, String what, String fmt,
199 String errfmt, Object[] args, Object... errargs) {
201 return ok(test, fmt + ": %s\n error: " + errfmt, concat(
202 concat(args, what), errargs));
204 return ok(test, fmt + ": %s", concat(args, what));
207 /* helper methods: */
208 @SuppressWarnings("unchecked")
209 public static <T> T[] concat(T[] firstArray, T... moreElements) {
210 return concat2(firstArray, moreElements);
213 @SuppressWarnings("unchecked")
214 public static <T> T[] concat2(T[] firstArray, T[]... moreArrays) {
215 int length = firstArray.length;
217 for (T[] array : moreArrays) {
218 length += array.length;
221 T[] result = (T[]) Array.newInstance(firstArray.getClass()
222 .getComponentType(), length);
224 System.arraycopy(firstArray, 0, result, 0, firstArray.length);
226 int pos = firstArray.length;
227 for (T[] array : moreArrays) {
228 System.arraycopy(array, 0, result, pos, array.length);
235 public static <T> String str(T object) {
237 if (object == null) {
241 else if (object.getClass().isArray()) {
242 StringBuilder buf = new StringBuilder();
243 int length = Array.getLength(object);
248 buf.append(str(Array.get(object, 0)));
250 for (int i = 1; i < length; ++i) {
252 buf.append(str(Array.get(object, i)));
258 return buf.toString();
261 else if (object instanceof String) {
262 String s = object.toString();
263 StringBuilder buf = new StringBuilder();
267 for (int i = 0; i < s.length(); ++i) {
268 char ch = s.charAt(i);
298 return buf.toString();
300 /* escape Character */
301 else if (object instanceof Character) {
302 switch ((Character) object) {
318 return "'" + object + "'";
322 else if (object instanceof Class) {
323 return ((Class<?>) object).getName();
326 return object.toString();
329 public static <E extends Comparable<? super E>> Collection<E> sorted(
330 Collection<E> collection) {
331 if (collection instanceof SortedSet) {
335 List<E> reply = new ArrayList<E>(collection);
336 Collections.sort(reply);
342 public static <E> Collection<E> sorted(
343 Collection<E> collection,
344 Comparator<? super E> comparator) {
345 if (collection instanceof SortedSet) {
349 List<E> reply = new ArrayList<E>(collection);
350 Collections.sort(reply, comparator);
356 public static <E extends Comparable<? super E>> E[] sorted(E[] values) {
361 public static <E> E[] sorted(
363 Comparator<? super E> comparator) {
364 Arrays.sort(values, comparator);
369 class Entry implements Map.Entry<String, Object> {
373 public Entry(String key, Object value) {
378 public String getKey() {
382 public Object getValue() {
386 public Object setValue(Object value) {
392 public int hashCode() {
393 return (key != null ? key.hashCode() << 8 : 0)
394 ^ (val != null ? val.hashCode() : 0);
397 public boolean equals(Object other) {
398 if (other != null && other instanceof Entry) {
399 Entry otherEntry = (Entry) other;
401 return (key == null ? otherEntry.key == null :
402 key.equals(otherEntry.key))
403 && (val == null ? otherEntry.val == null :
404 val.equals(otherEntry.val));
411 class AnnotationTester implements Comparable<AnnotationTester> {
412 private Class<? extends Annotation> annotationType;
414 private Map<String, Object> values =
415 TestHelper.getMapFactory().<String, Object>createMap();
417 public AnnotationTester(Class<? extends Annotation> annotationType,
418 Map<String, Object> values) {
419 this.annotationType = annotationType;
420 this.values.putAll(values);
425 public AnnotationTester(Class<? extends Annotation> annotationType) {
426 this.annotationType = annotationType;
431 public AnnotationTester(Class<? extends Annotation> annotationType,
432 Map.Entry<String, Object>... values) {
433 this.annotationType = annotationType;
435 for (Map.Entry<String, Object> value : values) {
436 if (this.values.put(value.getKey(), value.getValue()) != null)
437 throw new IllegalArgumentException(
438 "duplicated key: " + TestHelper.str(value.getKey()));
444 public Class<? extends Annotation> annotationType() {
445 return annotationType;
448 private void checkValues() {
449 for (String methodName : values.keySet()) {
451 annotationType.getDeclaredMethod(methodName);
452 } catch (NoSuchMethodException e) {
453 throw new IllegalArgumentException(
454 "annotation " + annotationType.getName() +
455 " has no method of name " + methodName + "()", e);
459 for (Method method : annotationType.getDeclaredMethods()) {
460 Object value = values.get(method.getName());
461 Class<?> returnType = method.getReturnType();
462 Class<?> valueType = value.getClass();
465 throw new IllegalArgumentException(
466 "annotation method of name " + method.getName() +
467 "() needs an expected value");
468 } else if (value instanceof AnnotationTester) {
469 AnnotationTester tester = (AnnotationTester) value;
471 if (!tester.annotationType().equals(returnType)) {
472 throw new IllegalArgumentException(
473 "illegal value type for annotation method " +
474 method.getName() + "()");
476 } else if (!returnType.isInstance(value)) {
477 if (returnType.isArray()
478 && returnType.getComponentType().isAnnotation()) {
479 if (!valueType.isArray()
480 || !isSubclassOf(valueType.getComponentType(),
481 AnnotationTester.class)) {
482 throw new IllegalArgumentException(
483 "illegal value type for annotation method " +
484 method.getName() + "()");
487 for (AnnotationTester tester : (AnnotationTester[]) value) {
488 if (!tester.annotationType().equals(
489 returnType.getComponentType())) {
490 throw new IllegalArgumentException(
491 "illegal value type for annotation method " +
492 method.getName() + "()");
495 } else if (!returnType.isPrimitive()
496 || !valueType.equals(getBoxingType(returnType))) {
497 throw new IllegalArgumentException(
498 "illegal value type for annotation method " +
499 method.getName() + "()");
505 public static boolean isSubclassOf(Class<?> subClass, Class<?> superClass) {
507 if (subClass.equals(superClass)) {
510 subClass = subClass.getSuperclass();
511 } while (subClass != null);
516 private static Map<Class<?>, Class<?>> boxingMap =
517 TestHelper.getMapFactory().<Class<?>, Class<?>>createMap();
520 boxingMap.put(byte.class, Byte.class);
521 boxingMap.put(char.class, Character.class);
522 boxingMap.put(short.class, Short.class);
523 boxingMap.put(long.class, Long.class);
524 boxingMap.put(int.class, Integer.class);
525 boxingMap.put(float.class, Float.class);
526 boxingMap.put(double.class, Double.class);
529 public static Class<?> getBoxingType(Class<?> primitiveType) {
530 Class<?> type = boxingMap.get(primitiveType);
533 throw new IllegalArgumentException(
534 "illegal type for boxing: " + primitiveType.getName());
540 public int hashCode() {
541 return (annotationType.hashCode() << 8) ^ values.hashCode();
544 public boolean equals(Object other) {
546 if (other instanceof AnnotationTester) {
547 AnnotationTester otherAnnotationTester =
548 (AnnotationTester) other;
550 if (!otherAnnotationTester.annotationType.equals(annotationType) ||
551 otherAnnotationTester.values.size() != values.size())
554 for (Map.Entry<String, Object> entry : values.entrySet()) {
555 if (!otherAnnotationTester.values.containsKey(entry.getKey()) ||
556 !otherAnnotationTester.values.get(
557 entry.getKey()).equals(entry.getValue()))
562 } else if (other instanceof Annotation) {
563 Annotation anno = (Annotation) other;
564 Method[] annotationFields = anno.annotationType()
565 .getDeclaredMethods();
567 if (!annotationType.equals(anno.annotationType())
568 || annotationFields.length != values.size())
571 for (Method method : annotationFields) {
572 if (!values.get(method.getName()).equals(
573 method.getDefaultValue()))
583 public String toString() {
584 StringBuilder buf = new StringBuilder();
587 buf.append(annotationType.getName());
591 for (Map.Entry<String, Object> entry : values.entrySet()) {
592 buf.append(entry.getKey());
594 buf.append(TestHelper.str(entry.getValue()));
597 if (i < values.size()) {
603 return buf.toString();
606 private final static Object[] EMPTY_OBJECT_ARRAY = new Object[] {};
608 protected boolean ok(boolean test, String what, String errfmt,
610 return TestHelper.okx(test, what, annotationType.getName(), errfmt,
611 EMPTY_OBJECT_ARRAY, errargs);
614 public boolean test(Annotation annotation) throws SecurityException,
615 NoSuchMethodException {
617 Method[] declaredMedthods = annotation.annotationType()
618 .getDeclaredMethods();
620 TestHelper.log(" * Testing %s", annotationType.getName());
622 ok = ok(annotationType.equals(annotation.annotationType()),
623 "test annotationType", "expected %s but got %s",
624 annotationType, annotation.annotationType());
627 ok = ok(declaredMedthods.length == values.size(),
628 "test annotation methods count", "expected %d but got %d",
629 values.size(), declaredMedthods.length)
632 for (String methodName : TestHelper.sorted(values.keySet())) {
633 Object expected = values.get(methodName);
638 got = annotation.getClass().getMethod(methodName).invoke(
640 } catch (Exception e) {
645 "test invocation of the annotation method " +
647 "exception occured while invokation: %s",
648 ex != null ? ex.getMessage() : "")
652 ex.printStackTrace();
654 ok = ok(got != null, "test return value of " + methodName +
655 "() != null", "got null!")
658 ok = ok(equals(got, expected), "test return value of "
659 + methodName + "()", "expected %s (type: %s) but"
660 + " got %s (type: %s)", TestHelper.str(got), got
661 .getClass().getName(), TestHelper.str(expected),
662 expected.getClass().getName())
671 public static boolean equals(Object a, Object b) {
675 else if (a instanceof Annotation && b instanceof AnnotationTester) {
676 return equals((Annotation) a, (AnnotationTester) b);
678 else if (b instanceof Annotation && a instanceof AnnotationTester) {
679 return equals((Annotation) b, (AnnotationTester) a);
681 else if (a.getClass().isArray()) {
682 if (!b.getClass().isArray()) {
686 int alen = Array.getLength(a);
687 int blen = Array.getLength(b);
693 for (int i = 0; i < alen; ++i) {
694 if (!equals(Array.get(a, i), Array.get(b, i))) {
706 public static boolean equals(Annotation annoation, AnnotationTester tester) {
707 if (!tester.annotationType().equals(annoation.annotationType())) {
712 for (Map.Entry<String, Object> bEntry : tester.values.entrySet()) {
713 Object aValue = annoation.getClass().getMethod(bEntry.getKey())
716 if (!equals(bEntry.getValue(), aValue)) {
720 } catch (Exception e) {
721 // TODO: better error handling?
729 public int compareTo(AnnotationTester other) {
730 return annotationType.getName().compareTo(
731 other.annotationType().getName());
735 abstract class AnnotatedElementAnnotationTester<T extends AnnotatedElement>
736 implements Comparable<AnnotatedElementAnnotationTester<? extends AnnotatedElement>> {
737 protected ClassAnnotationTester declaringClass;
741 private Map<Class<? extends Annotation>, AnnotationTester> annotations =
742 TestHelper.getMapFactory().
743 <Class<? extends Annotation>, AnnotationTester>createMap();
745 private Map<Class<? extends Annotation>, AnnotationTester> declaredAnnotations =
746 TestHelper.getMapFactory().
747 <Class<? extends Annotation>, AnnotationTester>createMap();
749 protected final static Object[] EMPTY_OBJECT_ARRAY = new Object[] {};
751 public AnnotatedElementAnnotationTester(
752 ClassAnnotationTester clazz,
755 this.declaringClass = clazz;
756 this.element = element;
760 public T annotatedElement() {
764 public String getName() {
768 public int compareTo(
769 AnnotatedElementAnnotationTester<? extends AnnotatedElement> other) {
770 return name.compareTo(other.getName());
773 private static Comparator<Annotation> annotationComparator =
774 new Comparator<Annotation>() {
775 public int compare(Annotation o1, Annotation o2) {
776 return o1.annotationType().getName().compareTo(
777 o2.annotationType().getName());
781 protected static Annotation[] sorted(Annotation[] annotations) {
782 return TestHelper.sorted(annotations, annotationComparator);
785 protected boolean ok(
786 boolean test, String what,
787 String errfmt, Object... errargs) {
788 return TestHelper.okx(test, what, name, errfmt,
789 EMPTY_OBJECT_ARRAY, errargs);
792 protected void logName() {
793 TestHelper.log("-- Testing %s --", getName());
796 protected void logHeader(String fmt, Object... args) {
797 TestHelper.log("-- " + getName() + ": Testing " + fmt + " --", args);
800 protected void log() {
804 public void putInheritedAnnotation(
805 Class<? extends Annotation> annotationType,
806 Map.Entry<String, Object>... values) {
807 if (annotations.containsKey(annotationType))
808 throw new IllegalArgumentException(
809 "Annotation already exists: " + annotationType.getName());
811 annotations.put(annotationType,
812 new AnnotationTester(annotationType, values));
815 public void putInheritedAnnotation(
816 Class<? extends Annotation> annotationType,
817 Map<String, Object> values) {
818 if (annotations.containsKey(annotationType))
819 throw new IllegalArgumentException(
820 "Annotation already exists: " + annotationType.getName());
822 annotations.put(annotationType,
823 new AnnotationTester(annotationType, values));
826 public void putDeclaredAnnotation(
827 Class<? extends Annotation> annotationType,
828 Map.Entry<String, Object>... values) {
829 if (annotations.containsKey(annotationType))
830 throw new IllegalArgumentException(
831 "Annotation already exists: " + annotationType.getName());
833 AnnotationTester tester = new AnnotationTester(annotationType, values);
835 annotations.put(annotationType, tester);
836 declaredAnnotations.put(annotationType, tester);
839 public void putDeclaredAnnotation(
840 Class<? extends Annotation> annotationType,
841 Map<String, Object> values) {
842 if (annotations.containsKey(annotationType))
843 throw new IllegalArgumentException(
844 "Annotation already exists: " + annotationType.getName());
846 AnnotationTester tester = new AnnotationTester(annotationType, values);
848 annotations.put(annotationType, tester);
849 declaredAnnotations.put(annotationType, tester);
852 public boolean test() throws SecurityException, NoSuchMethodException {
857 ok = testGetDeclaredAnnotations();
858 ok = testGetAnnotations() && ok;
859 ok = testGetAnnotation() && ok;
860 ok = testIsAnnotationPresent() && ok;
866 private boolean testGetDeclaredAnnotations() throws SecurityException,
867 NoSuchMethodException {
868 Annotation[] declaredAnnotations = element.getDeclaredAnnotations();
870 Set<Class<? extends Annotation>> annoTypes =
871 TestHelper.getSetFactory().<Class<? extends Annotation>>createSet();
873 logHeader("getDeclaredAnnotations()");
875 ok = ok(this.declaredAnnotations.size() == declaredAnnotations.length,
876 "test declared annotations count", "expected %d but got %d",
877 this.declaredAnnotations.size(), declaredAnnotations.length)
880 for (Annotation anno : sorted(declaredAnnotations)) {
881 AnnotationTester tester = this.annotations.get(
882 anno.annotationType());
884 ok = ok(!annoTypes.contains(anno.annotationType()),
885 "test unique occurrence of the annotation type " +
886 anno.annotationType().getName(),
887 "duplicated annotation!") && ok;
889 annoTypes.add(anno.annotationType());
891 ok = ok(tester != null, "test if annotation " +
892 anno.annotationType().getName() + " should be there",
893 "wrong annotation") && ok;
895 if (tester != null) {
896 ok = tester.test(anno) && ok;
903 private boolean testGetAnnotations() throws SecurityException,
904 NoSuchMethodException {
905 Annotation[] annotations = element.getAnnotations();
907 Set<Class<? extends Annotation>> annoTypes =
908 TestHelper.getSetFactory().<Class<? extends Annotation>>createSet();
910 logHeader("getAnnotations()");
912 ok = ok(this.annotations.size() == annotations.length,
913 "test annotations count", "expected %d but got %d",
914 this.annotations.size(), annotations.length)
917 for (Annotation anno : sorted(annotations)) {
918 AnnotationTester tester = this.annotations.get(anno
921 ok = ok(!annoTypes.contains(anno.annotationType()),
922 "test unique occurrence of the annotation type " +
923 anno.annotationType().getName(),
924 "duplicated annotation!")
927 annoTypes.add(anno.annotationType());
929 ok = ok(tester != null, "test if annotation " +
930 anno.annotationType().getName() + " should be there",
934 if (tester != null) {
935 ok = tester.test(anno) && ok;
942 private boolean testGetAnnotation() throws SecurityException,
943 NoSuchMethodException {
946 logHeader("getAnnotation(Class<? extends Annotation>)");
948 for (AnnotationTester tester : TestHelper.sorted(annotations.values())) {
949 Class<? extends Annotation> annotationType = tester
951 Annotation anno = element.getAnnotation(annotationType);
953 ok = ok(anno != null, "try to get required annotation " +
954 annotationType.getName() +
955 " using getAnnotation(Class<? extends Annotation>)",
956 "annotation dose not exist")
960 ok = tester.test(anno) && ok;
967 private boolean testIsAnnotationPresent() {
970 logHeader("isAnnotationPresent(Class<? extends Annotation>)");
972 for (AnnotationTester tester : TestHelper.sorted(annotations.values())) {
973 Class<? extends Annotation> annotationType =
974 tester.annotationType();
976 ok = ok(element.isAnnotationPresent(annotationType),
977 "test if annotation " + annotationType.getName() +
978 " is present using isAnnotationPresent()",
979 "annotation dose not exist")
987 class FieldAnnotationTester extends AnnotatedElementAnnotationTester<Field> {
988 public FieldAnnotationTester(ClassAnnotationTester clazz, Field field) {
989 super(clazz, field, field.getDeclaringClass().getName() + "." +
994 abstract class AbstractMethodAnnotationTester<T extends AnnotatedElement>
995 extends AnnotatedElementAnnotationTester<T> {
996 private Map<Class<? extends Annotation>, AnnotationTester>[] parameterAnnotations;
998 @SuppressWarnings("unchecked")
999 public AbstractMethodAnnotationTester(ClassAnnotationTester clazz,
1000 T element, String name, Class<?>[] parameterTypes) {
1001 super(clazz, element,
1002 methodName(clazz.annotatedElement(), name, parameterTypes));
1004 parameterAnnotations = new Map[parameterTypes.length];
1006 MapFactory mapFactory = TestHelper.getMapFactory();
1008 for (int i = 0; i < parameterTypes.length; ++i) {
1009 parameterAnnotations[i] = mapFactory.
1010 <Class<? extends Annotation>, AnnotationTester>createMap();
1014 private static String methodName(Class<?> declaringClass, String name,
1015 Class<?>[] parameterTypes) {
1016 StringBuilder buf = new StringBuilder(128);
1018 buf.append(declaringClass.getName());
1023 if (parameterTypes.length > 0) {
1024 buf.append(parameterTypes[0].getName());
1026 for (int i = 1; i < parameterTypes.length; ++i) {
1028 buf.append(parameterTypes[i].getName());
1034 return buf.toString();
1037 abstract protected Annotation[][] getParameterAnnotations();
1039 public void putParameterAnnotation(int index,
1040 Class<? extends Annotation> annotationType,
1041 Map.Entry<String, Object>... values) {
1042 if (parameterAnnotations[index].containsKey(annotationType))
1043 throw new IllegalArgumentException(
1044 "Annotation already exists: " + annotationType.getName());
1046 parameterAnnotations[index].put(
1048 new AnnotationTester(annotationType, values));
1051 public void putParameterAnnotation(int index,
1052 Class<? extends Annotation> annotationType,
1053 Map<String, Object> values) {
1054 if (parameterAnnotations[index].containsKey(annotationType))
1055 throw new IllegalArgumentException(
1056 "Annotation already exists: " + annotationType.getName());
1058 parameterAnnotations[index].put(
1060 new AnnotationTester(annotationType, values));
1063 public boolean test() throws SecurityException, NoSuchMethodException {
1064 boolean ok = super.test();
1066 ok = testParameterAnnotations() && ok;
1071 private boolean testParameterAnnotations() throws SecurityException,
1072 NoSuchMethodException {
1074 Annotation[][] parameterAnnotations = getParameterAnnotations();
1076 logHeader("getParameterAnnotations()");
1079 this.parameterAnnotations.length == parameterAnnotations.length,
1080 "test parameter count", "expected %d but got %d",
1081 this.parameterAnnotations.length, parameterAnnotations.length)
1084 if (this.parameterAnnotations.length == parameterAnnotations.length) {
1085 for (int i = 0; i < parameterAnnotations.length; ++i) {
1086 Set<Class<? extends Annotation>> annoTypes =
1087 TestHelper.getSetFactory().
1088 <Class<? extends Annotation>>createSet();
1091 this.parameterAnnotations[i].size() == parameterAnnotations[i].length,
1092 "test parameter annotations count for parameter " + i,
1093 "expected %d but got %d",
1094 Integer.valueOf(this.parameterAnnotations.length),
1095 Integer.valueOf(parameterAnnotations.length))
1098 for (Annotation anno : sorted(parameterAnnotations[i])) {
1099 AnnotationTester tester =
1100 this.parameterAnnotations[i].get(anno.annotationType());
1102 ok = ok(!annoTypes.contains(anno.annotationType()),
1103 "test unique occurrence of the annotation type " +
1104 anno.annotationType().getName(),
1105 "duplicated annotation!")
1108 annoTypes.add(anno.annotationType());
1110 ok = ok(tester != null, "test if annotation of type " +
1111 anno.annotationType().getName() +
1112 " should be defined for parameter " + i,
1113 "no, it shouldn't be!")
1116 if (tester != null) {
1117 ok = tester.test(anno) && ok;
1127 class MethodAnnotationTester extends AbstractMethodAnnotationTester<Method> {
1128 private Object defaultValue = null;
1130 public MethodAnnotationTester(ClassAnnotationTester clazz, Method method) {
1131 super(clazz, method, method.getName(), method.getParameterTypes());
1134 public MethodAnnotationTester(ClassAnnotationTester clazz, Method method,
1135 Object defaultValue) {
1136 this(clazz, method);
1137 setDefaultValue(defaultValue);
1140 public void setDefaultValue(Object value) {
1141 if (value != null && !declaringClass.isAnnotation())
1142 throw new IllegalArgumentException(
1143 "cannot set annotation default value of a method " +
1144 "of a non-annotation class.");
1146 defaultValue = value;
1149 public Object getDefaultValue() {
1150 return defaultValue;
1153 public boolean test() throws SecurityException, NoSuchMethodException {
1154 boolean ok = testGetDefaultValue();
1156 return super.test() && ok;
1159 private boolean testGetDefaultValue() {
1161 Object defaultValue = annotatedElement().getDefaultValue();
1163 logHeader("getDefaultValue()");
1165 if (this.defaultValue == null) {
1166 ok = ok(defaultValue == null, "test for annotation " +
1167 "default value", "there is one, but it should NOT be one!")
1170 ok = ok(defaultValue != null, "test for annotation " +
1171 "default value", "there is NONE, but it should be one!")
1174 ok = ok(AnnotationTester.equals(this.defaultValue, defaultValue),
1175 "test default value", "expected %s but got %s",
1176 this.defaultValue, defaultValue)
1183 protected Annotation[][] getParameterAnnotations() {
1184 return annotatedElement().getParameterAnnotations();
1188 class ConstructorAnnotationTester
1189 extends AbstractMethodAnnotationTester<Constructor<?>> {
1190 public ConstructorAnnotationTester(ClassAnnotationTester clazz,
1191 Constructor<?> constructor) {
1192 super(clazz, constructor, constructor.getName(),
1193 constructor.getParameterTypes());
1196 protected Annotation[][] getParameterAnnotations() {
1197 return annotatedElement().getParameterAnnotations();
1201 class ClassAnnotationTester extends AnnotatedElementAnnotationTester<Class<?>> {
1202 private boolean isAnnotation;
1204 private Map<Constructor<?>, ConstructorAnnotationTester> constructors =
1205 TestHelper.getMapFactory().
1206 <Constructor<?>, ConstructorAnnotationTester>createMap();
1208 private Map<Method, MethodAnnotationTester> methods =
1209 TestHelper.getMapFactory().
1210 <Method, MethodAnnotationTester>createMap();
1212 private Map<String, FieldAnnotationTester> fields =
1213 TestHelper.getMapFactory().
1214 <String, FieldAnnotationTester>createMap();
1216 public ClassAnnotationTester(Class<?> clazz, boolean isAnnotation) {
1217 super(null, clazz, clazz.getName());
1219 this.isAnnotation = isAnnotation;
1222 public ClassAnnotationTester(Class<?> clazz) {
1226 public boolean isAnnotation() {
1227 return isAnnotation;
1230 public FieldAnnotationTester addField(String name)
1231 throws SecurityException, NoSuchFieldException {
1232 FieldAnnotationTester field = new FieldAnnotationTester(this,
1233 annotatedElement().getField(name));
1235 if (fields.put(name, field) != null)
1236 throw new IllegalArgumentException("field already defined");
1241 public MethodAnnotationTester addMethod(String name, Object defalutValue,
1242 Class<?>... parameterTypes) throws SecurityException,
1243 NoSuchMethodException {
1244 Method reflMethod = annotatedElement().getMethod(
1245 name, parameterTypes);
1246 MethodAnnotationTester method = new MethodAnnotationTester(this,
1247 reflMethod, defalutValue);
1249 if (methods.put(reflMethod, method) != null)
1250 throw new IllegalArgumentException("method already defined");
1255 public ConstructorAnnotationTester addConstructor(
1256 Class<?>... parameterTypes) throws SecurityException,
1257 NoSuchMethodException {
1258 Constructor<?> reflConstructor =
1259 annotatedElement().getConstructor(parameterTypes);
1260 ConstructorAnnotationTester constructor =
1261 new ConstructorAnnotationTester(this, reflConstructor);
1263 if (constructors.put(reflConstructor, constructor) != null)
1264 throw new IllegalArgumentException("constructor already defined");
1269 protected void logName() {
1270 TestHelper.log("== Testing %s ==", getName());
1273 public boolean test() throws SecurityException, NoSuchMethodException {
1274 boolean ok = super.test();
1276 ok = testIsAnnotation() && ok;
1278 logHeader("Constructors");
1279 for (ConstructorAnnotationTester tester :
1280 TestHelper.sorted(constructors.values())) {
1281 ok = tester.test() && ok;
1284 logHeader("Methods");
1285 for (MethodAnnotationTester tester :
1286 TestHelper.sorted(methods.values())) {
1287 ok = tester.test() && ok;
1290 logHeader("Fields");
1291 for (FieldAnnotationTester tester :
1292 TestHelper.sorted(fields.values())) {
1293 ok = tester.test() && ok;
1300 private boolean testIsAnnotation() {
1301 logHeader("isAnnotation()");
1303 return TestHelper.okx(
1304 isAnnotation == annotatedElement().isAnnotation(),
1305 "test if the isAnnotation attribute is set properly",
1306 annotatedElement().getName(),
1307 (isAnnotation ? "class should be an annotation, but isn't!"
1308 : "class should NOT be an annotation, but it is!"),
1309 EMPTY_OBJECT_ARRAY);
1313 /* ********* the testcases ****************************************************/
1316 * Test Annotations onto enums and their values.
1318 @AnnotationB(string = "onto a enum")
1320 @AnnotationB(string = "onto a enum field")
1327 * Test Annotations on Annotations and their methods. Test Annotation on itself.
1329 @Retention(value = RetentionPolicy.RUNTIME)
1332 string = "onto itself",
1333 classes = {AnnotationA.class, Class.class},
1334 enumeration = EnumA.VALUE2)
1335 @interface AnnotationA {
1338 string = "onto a method of itself")
1341 Class<?>[] classes() default {EnumA.class, Object[][].class};
1342 EnumA enumeration() default EnumA.VALUE1;
1346 * This Annotation will be inherited as Annotation of a derived class.
1347 * Inheritance applies only for class annotations, not for methods or fields.
1350 @Retention(value = RetentionPolicy.RUNTIME)
1351 @interface AnnotationB {
1353 Class<?> clazz() default AnnotationB.class;
1357 * Test all possible types of enum fields.
1359 @Retention(value = RetentionPolicy.RUNTIME)
1360 @interface AnnotationC {
1361 byte aByte() default 100;
1362 char aChar() default 'Ăź';
1363 short aShort() default 88;
1364 int aInt() default Integer.MIN_VALUE;
1365 long aLong() default Long.MAX_VALUE;
1366 float aFloat() default 23.42f;
1367 double aDouble() default 555.0815d;
1368 String aString() default "Ă„Ă–Ăś";
1369 EnumA aEnum() default EnumA.VALUE2;
1370 Class<?> aClass() default EnumA.class;
1371 SuppressWarnings aAnnotation() default @SuppressWarnings("unchecked");
1372 byte[] aByteArray() default {(byte)255};
1373 char[] aCharArray() default {'ä', 'ö', 'ü'};
1374 short[] aShortArray() default {512};
1375 int[] aIntArray() default {640, 480};
1376 long[] aLongArray() default {1204l, 2048l};
1377 float[] aFloatArray() default {0.0f};
1378 double[] aDoubleArray() default {-2.2d, -3.3d};
1379 String[] aStringArray() default {""};
1380 EnumA[] aEnumArray() default EnumA.VALUE1;
1381 Class<?>[] aClassArray() default void.class;
1382 SuppressWarnings[] aAnnotationArray() default {};
1386 * This annotation will not be stored into the class file.
1388 @interface AnnotationD {
1392 * Test annotations onto a class.
1394 @AnnotationB(string = "onto a class", clazz = Foo.class)
1395 @AnnotationA(integer = 3, string = "onto a class")
1398 * Test annotations onto a field.
1400 @AnnotationA(integer = 4, string = "onto a field")
1404 * Test annotations onto a constructor.
1406 @AnnotationA(integer = 9, string = "onto a constructor")
1411 * Test annotations onto a method.
1414 * Test annotations onto a parameter.
1417 @AnnotationA(integer = 5, string = "onto a method")
1421 string = "onto a parameter")
1427 * Test annotations onto a static method.
1430 * Test annotations onto a parameter.
1433 @AnnotationA(integer = 7, string = "onto a static method")
1434 public static int staticMethod(
1437 string = "onto a parameter of a static method")
1444 * Test inheritance of annotations. Test all possible annotation field types as
1445 * default values. Test if an annotation without RetentionPolicy.RUNTIME is
1446 * really not visible at runtime.
1450 class Bar extends Foo {
1452 * Test that superclass field annotations will not be visible here.
1457 * Test that superclass constructor annotations will not be visible here.
1463 * Test that superclass method (and parameter) annotations will not be
1466 public int method(int x) {
1471 * Test that superclass method (and parameter) annotations will not be
1474 public static int staticMethod(int x) {
1480 * Test availability of annotations of inherited fields/methods. Test all
1481 * possible annotation field types. Test if not overloaded (=inherited)
1482 * methods/fields still have their annotations.
1484 @AnnotationB(string = "onto a derived class", clazz = Baz.class)
1493 aString = "a string",
1494 aEnum = EnumA.VALUE3,
1495 aClass = Class.class,
1496 aAnnotation = @SuppressWarnings("unchecked"),
1497 aByteArray = {0, 1, 2, 3},
1498 aCharArray = {'a', 'b', 'c'},
1500 aIntArray = {5, 6, 7},
1501 aLongArray = {8l, 9l},
1502 aFloatArray = {10.10f, 11.11f, 12.12f},
1504 aStringArray = {"a string","another string"},
1505 aEnumArray = {EnumA.VALUE3, EnumA.VALUE3},
1506 aClassArray = {Class.class, Integer.class, Long.class},
1507 aAnnotationArray = {
1508 @SuppressWarnings(value = "unchecked"),
1509 @SuppressWarnings(value = {"unused", "deprecation"})})
1510 class Baz extends Foo {
1513 /* ********* running the testcases ********************************************/
1514 public class TestAnnotations {
1515 @SuppressWarnings("unchecked")
1516 public static void main(String[] args) {
1518 MethodAnnotationTester mtester;
1521 ClassAnnotationTester classEnumA =
1522 new ClassAnnotationTester(EnumA.class);
1523 ClassAnnotationTester classAnnotationA =
1524 new ClassAnnotationTester(AnnotationA.class, true);
1525 ClassAnnotationTester classAnnotationB =
1526 new ClassAnnotationTester(AnnotationB.class, true);
1527 ClassAnnotationTester classAnnotationC =
1528 new ClassAnnotationTester(AnnotationC.class, true);
1529 ClassAnnotationTester classAnnotationD =
1530 new ClassAnnotationTester(AnnotationD.class, true);
1531 ClassAnnotationTester classFoo =
1532 new ClassAnnotationTester(Foo.class);
1533 ClassAnnotationTester classBar =
1534 new ClassAnnotationTester(Bar.class);
1535 ClassAnnotationTester classBaz =
1536 new ClassAnnotationTester(Baz.class);
1539 classEnumA.putDeclaredAnnotation(
1541 new Entry("string", "onto a enum"),
1542 new Entry("clazz", AnnotationB.class));
1543 classEnumA.addField("VALUE1").putDeclaredAnnotation(
1545 new Entry("string", "onto a enum field"),
1546 new Entry("clazz", AnnotationB.class)
1550 classAnnotationA.putDeclaredAnnotation(
1552 new Entry("value", RetentionPolicy.RUNTIME)
1554 classAnnotationA.putDeclaredAnnotation(
1556 new Entry("integer", 1),
1557 new Entry("string", "onto itself"),
1558 new Entry("classes", new Class<?>[] {
1559 AnnotationA.class, Class.class}),
1560 new Entry("enumeration", EnumA.VALUE2)
1562 classAnnotationA.addMethod("integer", null).putDeclaredAnnotation(
1564 new Entry("integer", 2),
1565 new Entry("string", "onto a method of itself"),
1566 new Entry("classes", new Class<?>[] {
1567 EnumA.class, Object[][].class }),
1568 new Entry("enumeration", EnumA.VALUE1)
1570 classAnnotationA.addMethod("classes",
1571 new Class<?>[] {EnumA.class, Object[][].class});
1572 classAnnotationA.addMethod("enumeration", EnumA.VALUE1);
1575 classAnnotationB.putDeclaredAnnotation(Inherited.class);
1576 classAnnotationB.putDeclaredAnnotation(
1578 new Entry("value", RetentionPolicy.RUNTIME)
1580 classAnnotationB.addMethod("clazz", AnnotationB.class);
1583 classAnnotationC.putDeclaredAnnotation(
1585 new Entry("value", RetentionPolicy.RUNTIME)
1589 classFoo.putDeclaredAnnotation(
1591 new Entry("string", "onto a class"),
1592 new Entry("clazz", Foo.class)
1594 classFoo.putDeclaredAnnotation(
1596 new Entry("integer", 3),
1597 new Entry("string", "onto a class"),
1598 new Entry("classes", new Class<?>[] {
1599 EnumA.class, Object[][].class}),
1600 new Entry("enumeration", EnumA.VALUE1)
1602 classFoo.addField("afield").putDeclaredAnnotation(
1604 new Entry("integer", 4),
1605 new Entry("string", "onto a field"),
1606 new Entry("classes", new Class<?>[] {
1607 EnumA.class, Object[][].class}),
1608 new Entry("enumeration", EnumA.VALUE1)
1610 mtester = classFoo.addMethod("method", null, int.class);
1611 mtester.putDeclaredAnnotation(
1613 new Entry("integer", 5),
1614 new Entry("string", "onto a method"),
1615 new Entry("classes", new Class<?>[] {
1616 EnumA.class, Object[][].class}),
1617 new Entry("enumeration", EnumA.VALUE1)
1619 mtester.putParameterAnnotation(0,
1621 new Entry("integer", 6),
1622 new Entry("string", "onto a parameter"),
1623 new Entry("classes", new Class<?>[] {
1624 EnumA.class, Object[][].class}),
1625 new Entry("enumeration", EnumA.VALUE1)
1627 mtester = classFoo.addMethod("staticMethod", null, int.class);
1628 mtester.putDeclaredAnnotation(
1630 new Entry("integer", 7),
1631 new Entry("string", "onto a static method"),
1632 new Entry("classes", new Class<?>[] {
1633 EnumA.class, Object[][].class }),
1634 new Entry("enumeration", EnumA.VALUE1)
1636 mtester.putParameterAnnotation(0,
1638 new Entry("integer", 8),
1639 new Entry("string", "onto a parameter of a static method"),
1640 new Entry("classes", new Class<?>[] {
1641 EnumA.class, Object[][].class}),
1642 new Entry("enumeration", EnumA.VALUE1)
1644 classFoo.addConstructor().putDeclaredAnnotation(
1646 new Entry("integer", 9),
1647 new Entry("string", "onto a constructor"),
1648 new Entry("classes", new Class<?>[] {
1649 EnumA.class, Object[][].class}),
1650 new Entry("enumeration", EnumA.VALUE1)
1654 classBar.putInheritedAnnotation(
1656 new Entry("string", "onto a class"),
1657 new Entry("clazz", Foo.class)
1659 classBar.putDeclaredAnnotation(
1661 new Entry("aByte", (byte)100),
1662 new Entry("aChar", (char)'Ăź'),
1663 new Entry("aShort", (short)88),
1664 new Entry("aInt", Integer.MIN_VALUE),
1665 new Entry("aLong", Long.MAX_VALUE),
1666 new Entry("aFloat", (float)23.42f),
1667 new Entry("aDouble", (double)555.0815d),
1668 new Entry("aString", "Ă„Ă–Ăś"),
1669 new Entry("aEnum", EnumA.VALUE2),
1670 new Entry("aClass", EnumA.class),
1671 new Entry("aAnnotation", new AnnotationTester(
1672 SuppressWarnings.class,
1673 new Entry("value", new String[] {"unchecked"}))),
1674 new Entry("aByteArray", new byte[] {(byte) 255}),
1675 new Entry("aCharArray", new char[] {'ä', 'ö', 'ü'}),
1676 new Entry("aShortArray", new short[] {512}),
1677 new Entry("aIntArray", new int[] {640, 480}),
1678 new Entry("aLongArray", new long[] {1204l, 2048l}),
1679 new Entry("aFloatArray", new float[] {0.0f}),
1680 new Entry("aDoubleArray", new double[] {-2.2d, -3.3d}),
1681 new Entry("aStringArray", new String[] {""}),
1682 new Entry("aEnumArray", new EnumA[] {EnumA.VALUE1}),
1683 new Entry("aClassArray", new Class<?>[] {void.class}),
1684 new Entry("aAnnotationArray", new AnnotationTester[] {})
1686 classBar.addField("afield");
1687 classBar.addMethod("method", null, int.class);
1688 classBar.addMethod("staticMethod", null, int.class);
1689 classBar.addConstructor();
1692 classBaz.putDeclaredAnnotation(
1694 new Entry("string", "onto a derived class"),
1695 new Entry("clazz", Baz.class)
1697 classBaz.putDeclaredAnnotation(
1699 new Entry("aByte", (byte)0),
1700 new Entry("aChar", (char)'a'),
1701 new Entry("aShort", (short)1),
1702 new Entry("aInt", (int)2),
1703 new Entry("aLong", (long)3l),
1704 new Entry("aFloat", (float)4.4f),
1705 new Entry("aDouble", (double)5.5d),
1706 new Entry("aString", "a string"),
1707 new Entry("aEnum", EnumA.VALUE3),
1708 new Entry("aClass", Class.class),
1709 new Entry("aAnnotation", new AnnotationTester(
1710 SuppressWarnings.class,
1711 new Entry("value",new String[] {"unchecked"}))),
1712 new Entry("aByteArray", new byte[] {0, 1, 2, 3}),
1713 new Entry("aCharArray", new char[] {'a', 'b', 'c'}),
1714 new Entry("aShortArray", new short[] {4}),
1715 new Entry("aIntArray", new int[] {5, 6, 7}),
1716 new Entry("aLongArray", new long[] {8l, 9l}),
1717 new Entry("aFloatArray", new float[] {
1718 10.10f, 11.11f, 12.12f}),
1719 new Entry("aDoubleArray", new double[] {}),
1720 new Entry("aStringArray", new String[] {
1721 "a string", "another string"}),
1722 new Entry("aEnumArray", new EnumA[] {
1723 EnumA.VALUE3, EnumA.VALUE3}),
1724 new Entry("aClassArray", new Class<?>[] {
1725 Class.class, Integer.class, Long.class}),
1726 new Entry("aAnnotationArray", new AnnotationTester[] {
1727 new AnnotationTester(
1728 SuppressWarnings.class,
1729 new Entry("value", new String[] {
1731 new AnnotationTester(
1732 SuppressWarnings.class,
1733 new Entry("value", new String[] {
1734 "unused", "deprecation"}))})
1736 classBaz.addField("afield").putDeclaredAnnotation(
1738 new Entry("integer", 4),
1739 new Entry("string", "onto a field"),
1740 new Entry("classes", new Class<?>[] {
1741 EnumA.class, Object[][].class}),
1742 new Entry("enumeration", EnumA.VALUE1)
1744 mtester = classBaz.addMethod("method", null, int.class);
1745 mtester.putDeclaredAnnotation(
1747 new Entry("integer", 5),
1748 new Entry("string", "onto a method"),
1749 new Entry("classes", new Class<?>[] {
1750 EnumA.class, Object[][].class }),
1751 new Entry("enumeration", EnumA.VALUE1)
1753 mtester.putParameterAnnotation(0,
1755 new Entry("integer", 6),
1756 new Entry("string", "onto a parameter"),
1757 new Entry("classes", new Class<?>[] {
1758 EnumA.class, Object[][].class }),
1759 new Entry("enumeration", EnumA.VALUE1)
1761 mtester = classBaz.addMethod("staticMethod", null, int.class);
1762 mtester.putDeclaredAnnotation(
1764 new Entry("integer", 7),
1765 new Entry("string", "onto a static method"),
1766 new Entry("classes", new Class<?>[] {
1767 EnumA.class, Object[][].class}),
1768 new Entry("enumeration", EnumA.VALUE1)
1770 mtester.putParameterAnnotation(0,
1772 new Entry("integer", 8),
1773 new Entry("string", "onto a parameter of a static method"),
1774 new Entry("classes", new Class<?>[] {
1775 EnumA.class, Object[][].class}),
1776 new Entry("enumeration", EnumA.VALUE1)
1779 ok = classEnumA.test();
1780 ok = classAnnotationA.test() && ok;
1781 ok = classAnnotationB.test() && ok;
1782 ok = classAnnotationC.test() && ok;
1783 ok = classAnnotationD.test() && ok;
1784 ok = classFoo.test() && ok;
1785 ok = classBar.test() && ok;
1786 ok = classBaz.test() && ok;
1787 } catch (Exception e) {
1788 ok = TestHelper.ok(false, "exception free execution\n");
1789 e.printStackTrace();
1792 TestHelper.printStatistics();