1package org.junit.runners.model; 2 3import static java.lang.reflect.Modifier.isStatic; 4 5import java.lang.annotation.Annotation; 6import java.lang.reflect.Constructor; 7import java.lang.reflect.Field; 8import java.lang.reflect.Method; 9import java.util.ArrayList; 10import java.util.HashMap; 11import java.util.List; 12import java.util.Map; 13 14import org.junit.Assert; 15import org.junit.Before; 16import org.junit.BeforeClass; 17 18/** 19 * Wraps a class to be run, providing method validation and annotation searching 20 */ 21public class TestClass { 22 private final Class<?> fClass; 23 24 private Map<Class<?>, List<FrameworkMethod>> fMethodsForAnnotations= new HashMap<Class<?>, List<FrameworkMethod>>(); 25 26 private Map<Class<?>, List<FrameworkField>> fFieldsForAnnotations= new HashMap<Class<?>, List<FrameworkField>>(); 27 28 /** 29 * Creates a {@code TestClass} wrapping {@code klass}. Each time this 30 * constructor executes, the class is scanned for annotations, which can be 31 * an expensive process (we hope in future JDK's it will not be.) Therefore, 32 * try to share instances of {@code TestClass} where possible. 33 */ 34 public TestClass(Class<?> klass) { 35 fClass= klass; 36 if (klass != null && klass.getConstructors().length > 1) 37 throw new IllegalArgumentException( 38 "Test class can only have one constructor"); 39 40 for (Class<?> eachClass : getSuperClasses(fClass)) { 41 for (Method eachMethod : eachClass.getDeclaredMethods()) 42 addToAnnotationLists(new FrameworkMethod(eachMethod), 43 fMethodsForAnnotations); 44 for (Field eachField : eachClass.getDeclaredFields()) 45 addToAnnotationLists(new FrameworkField(eachField), 46 fFieldsForAnnotations); 47 } 48 } 49 50 private <T extends FrameworkMember<T>> void addToAnnotationLists(T member, 51 Map<Class<?>, List<T>> map) { 52 for (Annotation each : member.getAnnotations()) { 53 Class<? extends Annotation> type= each.annotationType(); 54 List<T> members= getAnnotatedMembers(map, type); 55 if (member.isShadowedBy(members)) 56 return; 57 if (runsTopToBottom(type)) 58 members.add(0, member); 59 else 60 members.add(member); 61 } 62 } 63 64 /** 65 * Returns, efficiently, all the non-overridden methods in this class and 66 * its superclasses that are annotated with {@code annotationClass}. 67 */ 68 public List<FrameworkMethod> getAnnotatedMethods( 69 Class<? extends Annotation> annotationClass) { 70 return getAnnotatedMembers(fMethodsForAnnotations, annotationClass); 71 } 72 73 /** 74 * Returns, efficiently, all the non-overridden fields in this class and its 75 * superclasses that are annotated with {@code annotationClass}. 76 */ 77 public List<FrameworkField> getAnnotatedFields( 78 Class<? extends Annotation> annotationClass) { 79 return getAnnotatedMembers(fFieldsForAnnotations, annotationClass); 80 } 81 82 private <T> List<T> getAnnotatedMembers(Map<Class<?>, List<T>> map, 83 Class<? extends Annotation> type) { 84 if (!map.containsKey(type)) 85 map.put(type, new ArrayList<T>()); 86 return map.get(type); 87 } 88 89 private boolean runsTopToBottom(Class<? extends Annotation> annotation) { 90 return annotation.equals(Before.class) 91 || annotation.equals(BeforeClass.class); 92 } 93 94 private List<Class<?>> getSuperClasses(Class<?> testClass) { 95 ArrayList<Class<?>> results= new ArrayList<Class<?>>(); 96 Class<?> current= testClass; 97 while (current != null) { 98 results.add(current); 99 current= current.getSuperclass(); 100 } 101 return results; 102 } 103 104 /** 105 * Returns the underlying Java class. 106 */ 107 public Class<?> getJavaClass() { 108 return fClass; 109 } 110 111 /** 112 * Returns the class's name. 113 */ 114 public String getName() { 115 if (fClass == null) 116 return "null"; 117 return fClass.getName(); 118 } 119 120 /** 121 * Returns the only public constructor in the class, or throws an {@code 122 * AssertionError} if there are more or less than one. 123 */ 124 125 public Constructor<?> getOnlyConstructor() { 126 Constructor<?>[] constructors= fClass.getConstructors(); 127 Assert.assertEquals(1, constructors.length); 128 return constructors[0]; 129 } 130 131 /** 132 * Returns the annotations on this class 133 */ 134 public Annotation[] getAnnotations() { 135 if (fClass == null) 136 return new Annotation[0]; 137 return fClass.getAnnotations(); 138 } 139 140 public <T> List<T> getAnnotatedFieldValues(Object test, 141 Class<? extends Annotation> annotationClass, Class<T> valueClass) { 142 List<T> results= new ArrayList<T>(); 143 for (FrameworkField each : getAnnotatedFields(annotationClass)) { 144 try { 145 Object fieldValue= each.get(test); 146 if (valueClass.isInstance(fieldValue)) 147 results.add(valueClass.cast(fieldValue)); 148 } catch (IllegalAccessException e) { 149 throw new RuntimeException( 150 "How did getFields return a field we couldn't access?", e); 151 } 152 } 153 return results; 154 } 155 156 public boolean isANonStaticInnerClass() { 157 return fClass.isMemberClass() && !isStatic(fClass.getModifiers()); 158 } 159} 160