7
7
import java .lang .reflect .Field ;
8
8
import java .lang .reflect .Method ;
9
9
import java .util .ArrayList ;
10
+ import java .util .Arrays ;
10
11
import java .util .Collections ;
11
- import java .util .HashMap ;
12
+ import java .util .Comparator ;
13
+ import java .util .LinkedHashMap ;
12
14
import java .util .List ;
13
15
import java .util .Map ;
14
16
24
26
*/
25
27
public class TestClass {
26
28
private final Class <?> fClass ;
27
- private final Map <Class <?>, List <FrameworkMethod >> fMethodsForAnnotations ;
28
- private final Map <Class <?>, List <FrameworkField >> fFieldsForAnnotations ;
29
+ private final Map <Class <? extends Annotation >, List <FrameworkMethod >> fMethodsForAnnotations ;
30
+ private final Map <Class <? extends Annotation >, List <FrameworkField >> fFieldsForAnnotations ;
29
31
30
32
/**
31
33
* Creates a {@code TestClass} wrapping {@code klass}. Each time this
@@ -40,22 +42,38 @@ public TestClass(Class<?> klass) {
40
42
"Test class can only have one constructor" );
41
43
}
42
44
43
- Map <Class <?>, List <FrameworkMethod >> methodsForAnnotations = new HashMap <Class <?>, List <FrameworkMethod >>();
44
- Map <Class <?>, List <FrameworkField >> fieldsForAnnotations = new HashMap <Class <?>, List <FrameworkField >>();
45
+ Map <Class <? extends Annotation >, List <FrameworkMethod >> methodsForAnnotations =
46
+ new LinkedHashMap <Class <? extends Annotation >, List <FrameworkMethod >>();
47
+ Map <Class <? extends Annotation >, List <FrameworkField >> fieldsForAnnotations =
48
+ new LinkedHashMap <Class <? extends Annotation >, List <FrameworkField >>();
49
+
45
50
for (Class <?> eachClass : getSuperClasses (fClass )) {
46
51
for (Method eachMethod : MethodSorter .getDeclaredMethods (eachClass )) {
47
52
addToAnnotationLists (new FrameworkMethod (eachMethod ), methodsForAnnotations );
48
53
}
49
- for (Field eachField : eachClass .getDeclaredFields ()) {
54
+ // ensuring fields are sorted to make sure that entries are inserted
55
+ // and read from fieldForAnnotations in a deterministic order
56
+ for (Field eachField : getSortedDeclaredFields (eachClass )) {
50
57
addToAnnotationLists (new FrameworkField (eachField ), fieldsForAnnotations );
51
58
}
52
59
}
53
- fMethodsForAnnotations = Collections .unmodifiableMap (methodsForAnnotations );
54
- fFieldsForAnnotations = Collections .unmodifiableMap (fieldsForAnnotations );
60
+
61
+ fMethodsForAnnotations = makeDeeplyUnmodifiable (methodsForAnnotations );
62
+ fFieldsForAnnotations = makeDeeplyUnmodifiable (fieldsForAnnotations );
63
+ }
64
+
65
+ private static Field [] getSortedDeclaredFields (Class <?> clazz ) {
66
+ Field [] declaredFields = clazz .getDeclaredFields ();
67
+ Arrays .sort (declaredFields , new Comparator <Field >() {
68
+ public int compare (Field field1 , Field field2 ) {
69
+ return field1 .getName ().compareTo (field2 .getName ());
70
+ }
71
+ });
72
+ return declaredFields ;
55
73
}
56
74
57
75
private static <T extends FrameworkMember <T >> void addToAnnotationLists (T member ,
58
- Map <Class <?>, List <T >> map ) {
76
+ Map <Class <? extends Annotation >, List <T >> map ) {
59
77
for (Annotation each : member .getAnnotations ()) {
60
78
Class <? extends Annotation > type = each .annotationType ();
61
79
List <T > members = getAnnotatedMembers (map , type , true );
@@ -70,6 +88,17 @@ private static <T extends FrameworkMember<T>> void addToAnnotationLists(T member
70
88
}
71
89
}
72
90
91
+ private static <T extends FrameworkMember <T >> Map <Class <? extends Annotation >, List <T >>
92
+ makeDeeplyUnmodifiable (Map <Class <? extends Annotation >, List <T >> source ) {
93
+ LinkedHashMap <Class <? extends Annotation >, List <T >> copy =
94
+ new LinkedHashMap <Class <? extends Annotation >, List <T >>();
95
+ for (Map .Entry <Class <? extends Annotation >, List <T >> entry : source .entrySet ()) {
96
+ copy .put (entry .getKey (), Collections .unmodifiableList (entry .getValue ()));
97
+ }
98
+ return Collections .unmodifiableMap (copy );
99
+ }
100
+
101
+
73
102
/**
74
103
* Returns, efficiently, all the non-overridden methods in this class and
75
104
* its superclasses that are annotated with {@code annotationClass}.
@@ -88,7 +117,27 @@ public List<FrameworkField> getAnnotatedFields(
88
117
return Collections .unmodifiableList (getAnnotatedMembers (fFieldsForAnnotations , annotationClass , false ));
89
118
}
90
119
91
- private static <T > List <T > getAnnotatedMembers (Map <Class <?>, List <T >> map ,
120
+ /**
121
+ * Gets a {@code Map} between annotations and methods that have
122
+ * the annotation in this class or its superclasses.
123
+ *
124
+ * @since 4.12
125
+ */
126
+ public Map <Class <? extends Annotation >, List <FrameworkMethod >> getAnnotationToMethods () {
127
+ return fMethodsForAnnotations ;
128
+ }
129
+
130
+ /**
131
+ * Gets a {@code Map} between annotations and fields that have
132
+ * the annotation in this class or its superclasses.
133
+ *
134
+ * @since 4.12
135
+ */
136
+ public Map <Class <? extends Annotation >, List <FrameworkField >> getAnnotationToFields () {
137
+ return fFieldsForAnnotations ;
138
+ }
139
+
140
+ private static <T > List <T > getAnnotatedMembers (Map <Class <? extends Annotation >, List <T >> map ,
92
141
Class <? extends Annotation > type , boolean fillIfAbsent ) {
93
142
if (!map .containsKey (type ) && fillIfAbsent ) {
94
143
map .put (type , new ArrayList <T >());
0 commit comments