Skip to content

Commit e792dc4

Browse files
committed
Merge pull request #753 from stefanbirkner/modularize-validator
Extract annotations validation to a single class.
2 parents 15566c4 + 9d3821f commit e792dc4

11 files changed

+354
-285
lines changed

src/main/java/org/junit/runners/ParentRunner.java

+3-55
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,12 @@
1111
import java.util.Comparator;
1212
import java.util.Iterator;
1313
import java.util.List;
14-
import java.util.Map;
1514

1615
import org.junit.AfterClass;
1716
import org.junit.BeforeClass;
1817
import org.junit.ClassRule;
1918
import org.junit.Ignore;
2019
import org.junit.Rule;
21-
import org.junit.validator.AnnotationValidator;
22-
import org.junit.validator.AnnotationValidatorFactory;
23-
import org.junit.validator.ValidateWith;
2420
import org.junit.internal.AssumptionViolatedException;
2521
import org.junit.internal.runners.model.EachTestNotifier;
2622
import org.junit.internal.runners.statements.RunAfters;
@@ -36,12 +32,12 @@
3632
import org.junit.runner.manipulation.Sorter;
3733
import org.junit.runner.notification.RunNotifier;
3834
import org.junit.runner.notification.StoppedByUserException;
39-
import org.junit.runners.model.FrameworkField;
4035
import org.junit.runners.model.FrameworkMethod;
4136
import org.junit.runners.model.InitializationError;
4237
import org.junit.runners.model.RunnerScheduler;
4338
import org.junit.runners.model.Statement;
4439
import org.junit.runners.model.TestClass;
40+
import org.junit.validator.AnnotationsValidator;
4541

4642
/**
4743
* Provides most of the functionality specific to a Runner that implements a
@@ -64,8 +60,7 @@ public abstract class ParentRunner<T> extends Runner implements Filterable,
6460
// Guarded by fChildrenLock
6561
private volatile Collection<T> fFilteredChildren = null;
6662

67-
private final AnnotationValidatorFactory fAnnotationValidatorFactory =
68-
new AnnotationValidatorFactory();
63+
private final AnnotationsValidator fAnnotationsValidator= new AnnotationsValidator();
6964

7065
private volatile RunnerScheduler fScheduler = new RunnerScheduler() {
7166
public void schedule(Runnable childStatement) {
@@ -126,54 +121,7 @@ protected void collectInitializationErrors(List<Throwable> errors) {
126121
validatePublicVoidNoArgMethods(BeforeClass.class, true, errors);
127122
validatePublicVoidNoArgMethods(AfterClass.class, true, errors);
128123
validateClassRules(errors);
129-
invokeValidators(errors);
130-
}
131-
132-
private void invokeValidators(List<Throwable> errors) {
133-
invokeValidatorsOnClass(errors);
134-
invokeValidatorsOnMethods(errors);
135-
invokeValidatorsOnFields(errors);
136-
}
137-
138-
private void invokeValidatorsOnClass(List<Throwable> errors) {
139-
Annotation[] annotations = getTestClass().getAnnotations();
140-
for (Annotation annotation : annotations) {
141-
Class<? extends Annotation> annotationType = annotation.annotationType();
142-
ValidateWith validateWithAnnotation = annotationType.getAnnotation(ValidateWith.class);
143-
if (validateWithAnnotation != null) {
144-
AnnotationValidator annotationValidator =
145-
fAnnotationValidatorFactory.createAnnotationValidator(validateWithAnnotation);
146-
errors.addAll(annotationValidator.validateAnnotatedClass(getTestClass()));
147-
}
148-
}
149-
}
150-
151-
private void invokeValidatorsOnMethods(List<Throwable> errors) {
152-
Map<Class<? extends Annotation>, List<FrameworkMethod>> annotationMap = getTestClass().getAnnotationToMethods();
153-
for (Class<? extends Annotation> annotationType : annotationMap.keySet()) {
154-
ValidateWith validateWithAnnotation = annotationType.getAnnotation(ValidateWith.class);
155-
if (validateWithAnnotation != null) {
156-
for (FrameworkMethod frameworkMethod : annotationMap.get(annotationType)) {
157-
AnnotationValidator annotationValidator =
158-
fAnnotationValidatorFactory.createAnnotationValidator(validateWithAnnotation);
159-
errors.addAll(annotationValidator.validateAnnotatedMethod(frameworkMethod));
160-
}
161-
}
162-
}
163-
}
164-
165-
private void invokeValidatorsOnFields(List<Throwable> errors) {
166-
Map<Class<? extends Annotation>, List<FrameworkField>> annotationMap = getTestClass().getAnnotationToFields();
167-
for (Class<? extends Annotation> annotationType : annotationMap.keySet()) {
168-
ValidateWith validateWithAnnotation = annotationType.getAnnotation(ValidateWith.class);
169-
if (validateWithAnnotation != null) {
170-
for (FrameworkField frameworkField : annotationMap.get(annotationType)) {
171-
AnnotationValidator annotationValidator =
172-
fAnnotationValidatorFactory.createAnnotationValidator(validateWithAnnotation);
173-
errors.addAll(annotationValidator.validateAnnotatedField(frameworkField));
174-
}
175-
}
176-
}
124+
errors.addAll(fAnnotationsValidator.validateTestClass(getTestClass()));
177125
}
178126

179127
/**
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package org.junit.runners.model;
2+
3+
import java.lang.annotation.Annotation;
4+
5+
/**
6+
* A model element that may have annotations.
7+
*
8+
* @since 4.12
9+
*/
10+
public interface Annotatable {
11+
/**
12+
* Returns the model elements' annotations.
13+
*/
14+
Annotation[] getAnnotations();
15+
}

src/main/java/org/junit/runners/model/FrameworkField.java

-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ public String getName() {
2727
return getField().getName();
2828
}
2929

30-
@Override
3130
public Annotation[] getAnnotations() {
3231
return fField.getAnnotations();
3332
}

src/main/java/org/junit/runners/model/FrameworkMember.java

+2-7
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package org.junit.runners.model;
22

3-
import java.lang.annotation.Annotation;
43
import java.lang.reflect.Modifier;
54
import java.util.List;
65

@@ -9,12 +8,8 @@
98
*
109
* @since 4.7
1110
*/
12-
public abstract class FrameworkMember<T extends FrameworkMember<T>> {
13-
/**
14-
* Returns the annotations on this member
15-
*/
16-
abstract Annotation[] getAnnotations();
17-
11+
public abstract class FrameworkMember<T extends FrameworkMember<T>> implements
12+
Annotatable {
1813
abstract boolean isShadowedBy(T otherMember);
1914

2015
boolean isShadowedBy(List<T> members) {

src/main/java/org/junit/runners/model/FrameworkMethod.java

-1
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,6 @@ private Class<?>[] getParameterTypes() {
186186
/**
187187
* Returns the annotations on this method
188188
*/
189-
@Override
190189
public Annotation[] getAnnotations() {
191190
return fMethod.getAnnotations();
192191
}

src/main/java/org/junit/runners/model/TestClass.java

+54-24
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package org.junit.runners.model;
22

33
import static java.lang.reflect.Modifier.isStatic;
4+
import static org.junit.internal.MethodSorter.NAME_ASCENDING;
45

56
import java.lang.annotation.Annotation;
67
import java.lang.reflect.Constructor;
@@ -11,8 +12,10 @@
1112
import java.util.Collections;
1213
import java.util.Comparator;
1314
import java.util.LinkedHashMap;
15+
import java.util.LinkedHashSet;
1416
import java.util.List;
1517
import java.util.Map;
18+
import java.util.Set;
1619

1720
import org.junit.Assert;
1821
import org.junit.Before;
@@ -24,7 +27,10 @@
2427
*
2528
* @since 4.5
2629
*/
27-
public class TestClass {
30+
public class TestClass implements Annotatable {
31+
private static final FieldComparator FIELD_COMPARATOR = new FieldComparator();
32+
private static final MethodComparator METHOD_COMPARATOR = new MethodComparator();
33+
2834
private final Class<?> fClass;
2935
private final Map<Class<? extends Annotation>, List<FrameworkMethod>> fMethodsForAnnotations;
3036
private final Map<Class<? extends Annotation>, List<FrameworkField>> fFieldsForAnnotations;
@@ -68,11 +74,7 @@ protected void scanAnnotatedMembers(Map<Class<? extends Annotation>, List<Framew
6874

6975
private static Field[] getSortedDeclaredFields(Class<?> clazz) {
7076
Field[] declaredFields = clazz.getDeclaredFields();
71-
Arrays.sort(declaredFields, new Comparator<Field>() {
72-
public int compare(Field field1, Field field2) {
73-
return field1.getName().compareTo(field2.getName());
74-
}
75-
});
77+
Arrays.sort(declaredFields, FIELD_COMPARATOR);
7678
return declaredFields;
7779
}
7880

@@ -102,6 +104,17 @@ protected static <T extends FrameworkMember<T>> void addToAnnotationLists(T memb
102104
return Collections.unmodifiableMap(copy);
103105
}
104106

107+
/**
108+
* Returns, efficiently, all the non-overridden methods in this class and
109+
* its superclasses that are annotated}.
110+
*
111+
* @since 4.12
112+
*/
113+
public List<FrameworkMethod> getAnnotatedMethods() {
114+
List<FrameworkMethod> methods = collectValues(fMethodsForAnnotations);
115+
Collections.sort(methods, METHOD_COMPARATOR);
116+
return methods;
117+
}
105118

106119
/**
107120
* Returns, efficiently, all the non-overridden methods in this class and
@@ -114,31 +127,29 @@ public List<FrameworkMethod> getAnnotatedMethods(
114127

115128
/**
116129
* Returns, efficiently, all the non-overridden fields in this class and its
117-
* superclasses that are annotated with {@code annotationClass}.
130+
* superclasses that are annotated.
131+
*
132+
* @since 4.12
118133
*/
119-
public List<FrameworkField> getAnnotatedFields(
120-
Class<? extends Annotation> annotationClass) {
121-
return Collections.unmodifiableList(getAnnotatedMembers(fFieldsForAnnotations, annotationClass, false));
134+
public List<FrameworkField> getAnnotatedFields() {
135+
return collectValues(fFieldsForAnnotations);
122136
}
123137

124138
/**
125-
* Gets a {@code Map} between annotations and methods that have
126-
* the annotation in this class or its superclasses.
127-
*
128-
* @since 4.12
139+
* Returns, efficiently, all the non-overridden fields in this class and its
140+
* superclasses that are annotated with {@code annotationClass}.
129141
*/
130-
public Map<Class<? extends Annotation>, List<FrameworkMethod>> getAnnotationToMethods() {
131-
return fMethodsForAnnotations;
142+
public List<FrameworkField> getAnnotatedFields(
143+
Class<? extends Annotation> annotationClass) {
144+
return Collections.unmodifiableList(getAnnotatedMembers(fFieldsForAnnotations, annotationClass, false));
132145
}
133146

134-
/**
135-
* Gets a {@code Map} between annotations and fields that have
136-
* the annotation in this class or its superclasses.
137-
*
138-
* @since 4.12
139-
*/
140-
public Map<Class<? extends Annotation>, List<FrameworkField>> getAnnotationToFields() {
141-
return fFieldsForAnnotations;
147+
private <T> List<T> collectValues(Map<?, List<T>> map) {
148+
Set<T> values = new LinkedHashSet<T>();
149+
for (List<T> additionalValues : map.values()) {
150+
values.addAll(additionalValues);
151+
}
152+
return new ArrayList<T>(values);
142153
}
143154

144155
private static <T> List<T> getAnnotatedMembers(Map<Class<? extends Annotation>, List<T>> map,
@@ -240,4 +251,23 @@ public <T> List<T> getAnnotatedMethodValues(Object test,
240251
public boolean isANonStaticInnerClass() {
241252
return fClass.isMemberClass() && !isStatic(fClass.getModifiers());
242253
}
254+
255+
/**
256+
* Compares two fields by its name.
257+
*/
258+
private static class FieldComparator implements Comparator<Field> {
259+
public int compare(Field left, Field right) {
260+
return left.getName().compareTo(right.getName());
261+
}
262+
}
263+
264+
/**
265+
* Compares two methods by its name.
266+
*/
267+
private static class MethodComparator implements
268+
Comparator<FrameworkMethod> {
269+
public int compare(FrameworkMethod left, FrameworkMethod right) {
270+
return NAME_ASCENDING.compare(left.getMethod(), right.getMethod());
271+
}
272+
}
243273
}

src/main/java/org/junit/validator/AnnotationValidatorFactory.java

+4-5
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,7 @@
88
* @since 4.12
99
*/
1010
public class AnnotationValidatorFactory {
11-
12-
private static ConcurrentHashMap<ValidateWith, AnnotationValidator> fAnnotationTypeToValidatorMap =
11+
private static final ConcurrentHashMap<ValidateWith, AnnotationValidator> VALIDATORS_FOR_ANNOTATION_TYPES =
1312
new ConcurrentHashMap<ValidateWith, AnnotationValidator>();
1413

1514
/**
@@ -23,7 +22,7 @@ public class AnnotationValidatorFactory {
2322
* @since 4.12
2423
*/
2524
public AnnotationValidator createAnnotationValidator(ValidateWith validateWithAnnotation) {
26-
AnnotationValidator validator = fAnnotationTypeToValidatorMap.get(validateWithAnnotation);
25+
AnnotationValidator validator = VALIDATORS_FOR_ANNOTATION_TYPES.get(validateWithAnnotation);
2726
if (validator != null) {
2827
return validator;
2928
}
@@ -34,8 +33,8 @@ public AnnotationValidator createAnnotationValidator(ValidateWith validateWithAn
3433
}
3534
try {
3635
AnnotationValidator annotationValidator = clazz.newInstance();
37-
fAnnotationTypeToValidatorMap.putIfAbsent(validateWithAnnotation, annotationValidator);
38-
return fAnnotationTypeToValidatorMap.get(validateWithAnnotation);
36+
VALIDATORS_FOR_ANNOTATION_TYPES.putIfAbsent(validateWithAnnotation, annotationValidator);
37+
return VALIDATORS_FOR_ANNOTATION_TYPES.get(validateWithAnnotation);
3938
} catch (Exception e) {
4039
throw new RuntimeException("Exception received when creating AnnotationValidator class " + clazz.getName(), e);
4140
}

0 commit comments

Comments
 (0)