1 package org.testng.internal.annotations; 2 3 import java.lang.annotation.Annotation; 4 import java.lang.reflect.Constructor; 5 import java.lang.reflect.Method; 6 import java.lang.reflect.Modifier; 7 import java.util.Map; 8 9 import org.testng.ITestNGMethod; 10 import org.testng.annotations.IAnnotation; 11 import org.testng.annotations.IConfigurationAnnotation; 12 import org.testng.annotations.IDataProviderAnnotation; 13 import org.testng.annotations.IExpectedExceptionsAnnotation; 14 import org.testng.annotations.IFactoryAnnotation; 15 import org.testng.annotations.IParametersAnnotation; 16 import org.testng.annotations.ITestAnnotation; 17 import org.testng.collections.Maps; 18 import org.testng.internal.TestNGMethod; 19 import org.testng.internal.Utils; 20 import org.testng.xml.XmlTest; 21 22 /** 23 * Helper methods to find @Test and @Configuration tags. They minimize 24 * the amount of casting we need to do. 25 * 26 * Created on Dec 20, 2005 27 * @author cbeust 28 */ 29 public class AnnotationHelper { 30 findTest(IAnnotationFinder finder, Class<?> cls)31 public static ITestAnnotation findTest(IAnnotationFinder finder, Class<?> cls) { 32 return finder.findAnnotation(cls, ITestAnnotation.class); 33 } 34 findTest(IAnnotationFinder finder, Method m)35 public static ITestAnnotation findTest(IAnnotationFinder finder, Method m) { 36 return finder.findAnnotation(m, ITestAnnotation.class); 37 } 38 findTest(IAnnotationFinder finder, ITestNGMethod m)39 public static ITestAnnotation findTest(IAnnotationFinder finder, ITestNGMethod m) { 40 return finder.findAnnotation(m, ITestAnnotation.class); 41 } 42 findFactory(IAnnotationFinder finder, Method m)43 public static IFactoryAnnotation findFactory(IAnnotationFinder finder, Method m) { 44 return finder.findAnnotation(m, IFactoryAnnotation.class); 45 } 46 findFactory(IAnnotationFinder finder, Constructor c)47 public static IFactoryAnnotation findFactory(IAnnotationFinder finder, Constructor c) { 48 return finder.findAnnotation(c, IFactoryAnnotation.class); 49 } 50 findTest(IAnnotationFinder finder, Constructor ctor)51 public static ITestAnnotation findTest(IAnnotationFinder finder, Constructor ctor) { 52 return finder.findAnnotation(ctor, ITestAnnotation.class); 53 } 54 findConfiguration(IAnnotationFinder finder, Constructor ctor)55 public static IConfigurationAnnotation findConfiguration(IAnnotationFinder finder, Constructor ctor) { 56 IConfigurationAnnotation result = finder.findAnnotation(ctor, IConfigurationAnnotation.class); 57 if (result == null) { 58 IConfigurationAnnotation bs = (IConfigurationAnnotation) finder.findAnnotation(ctor, IBeforeSuite.class); 59 IConfigurationAnnotation as = (IConfigurationAnnotation) finder.findAnnotation(ctor, IAfterSuite.class); 60 IConfigurationAnnotation bt = (IConfigurationAnnotation) finder.findAnnotation(ctor, IBeforeTest.class); 61 IConfigurationAnnotation at = (IConfigurationAnnotation) finder.findAnnotation(ctor, IAfterTest.class); 62 IConfigurationAnnotation bg = (IConfigurationAnnotation) finder.findAnnotation(ctor, IBeforeGroups.class); 63 IConfigurationAnnotation ag = (IConfigurationAnnotation) finder.findAnnotation(ctor, IAfterGroups.class); 64 IConfigurationAnnotation bc = (IConfigurationAnnotation) finder.findAnnotation(ctor, IBeforeClass.class); 65 IConfigurationAnnotation ac = (IConfigurationAnnotation) finder.findAnnotation(ctor, IAfterClass.class); 66 IConfigurationAnnotation bm = (IConfigurationAnnotation) finder.findAnnotation(ctor, IBeforeMethod.class); 67 IConfigurationAnnotation am = (IConfigurationAnnotation) finder.findAnnotation(ctor, IAfterMethod.class); 68 69 if (bs != null || as != null || bt != null || at != null || bg != null || ag != null 70 || bc != null || ac != null || bm != null || am != null) 71 { 72 result = createConfiguration(bs, as, bt, at, bg, ag, bc, ac, bm, am); 73 } 74 } 75 76 return result; 77 } 78 findConfiguration(IAnnotationFinder finder, Method m)79 public static IConfigurationAnnotation findConfiguration(IAnnotationFinder finder, Method m) { 80 IConfigurationAnnotation result = finder.findAnnotation(m, IConfigurationAnnotation.class); 81 if (result == null) { 82 IConfigurationAnnotation bs = (IConfigurationAnnotation) finder.findAnnotation(m, IBeforeSuite.class); 83 IConfigurationAnnotation as = (IConfigurationAnnotation) finder.findAnnotation(m, IAfterSuite.class); 84 IConfigurationAnnotation bt = (IConfigurationAnnotation) finder.findAnnotation(m, IBeforeTest.class); 85 IConfigurationAnnotation at = (IConfigurationAnnotation) finder.findAnnotation(m, IAfterTest.class); 86 IConfigurationAnnotation bg = (IConfigurationAnnotation) finder.findAnnotation(m, IBeforeGroups.class); 87 IConfigurationAnnotation ag = (IConfigurationAnnotation) finder.findAnnotation(m, IAfterGroups.class); 88 IConfigurationAnnotation bc = (IConfigurationAnnotation) finder.findAnnotation(m, IBeforeClass.class); 89 IConfigurationAnnotation ac = (IConfigurationAnnotation) finder.findAnnotation(m, IAfterClass.class); 90 IConfigurationAnnotation bm = (IConfigurationAnnotation) finder.findAnnotation(m, IBeforeMethod.class); 91 IConfigurationAnnotation am = (IConfigurationAnnotation) finder.findAnnotation(m, IAfterMethod.class); 92 93 if (bs != null || as != null || bt != null || at != null || bg != null || ag != null 94 || bc != null || ac != null || bm != null || am != null) 95 { 96 result = createConfiguration(bs, as, bt, at, bg, ag, bc, ac, bm, am); 97 } 98 } 99 100 return result; 101 } 102 createConfiguration(IConfigurationAnnotation bs, IConfigurationAnnotation as, IConfigurationAnnotation bt, IConfigurationAnnotation at, IConfigurationAnnotation bg, IConfigurationAnnotation ag, IConfigurationAnnotation bc, IConfigurationAnnotation ac, IConfigurationAnnotation bm, IConfigurationAnnotation am)103 private static IConfigurationAnnotation createConfiguration(IConfigurationAnnotation bs, IConfigurationAnnotation as, 104 IConfigurationAnnotation bt, IConfigurationAnnotation at, IConfigurationAnnotation bg, IConfigurationAnnotation ag, 105 IConfigurationAnnotation bc, IConfigurationAnnotation ac, IConfigurationAnnotation bm, IConfigurationAnnotation am) 106 { 107 ConfigurationAnnotation result = new ConfigurationAnnotation(); 108 109 if (bs != null) { 110 result.setBeforeSuite(true); 111 finishInitialize(result, bs); 112 } 113 if (as != null) { 114 result.setAfterSuite(true); 115 finishInitialize(result, as); 116 } 117 if (bt != null) { 118 result.setBeforeTest(true); 119 finishInitialize(result, bt); 120 } 121 if (at != null) { 122 result.setAfterTest(true); 123 finishInitialize(result, at); 124 } 125 if (bg != null) { 126 result.setBeforeGroups(bg.getBeforeGroups()); 127 finishInitialize(result, bg); 128 } 129 if (ag != null) { 130 result.setAfterGroups(ag.getAfterGroups()); 131 finishInitialize(result, ag); 132 } 133 if (bc != null) { 134 result.setBeforeTestClass(true); 135 finishInitialize(result, bc); 136 } 137 if (ac != null) { 138 result.setAfterTestClass(true); 139 finishInitialize(result, ac); 140 } 141 if (bm != null) { 142 result.setBeforeTestMethod(true); 143 finishInitialize(result, bm); 144 } 145 if (am != null) { 146 result.setAfterTestMethod(true); 147 finishInitialize(result, am); 148 } 149 150 return result; 151 } 152 153 @SuppressWarnings({"deprecation"}) finishInitialize(ConfigurationAnnotation result, IConfigurationAnnotation bs)154 private static void finishInitialize(ConfigurationAnnotation result, IConfigurationAnnotation bs) { 155 result.setFakeConfiguration(true); 156 result.setAlwaysRun(bs.getAlwaysRun()); 157 result.setDependsOnGroups(bs.getDependsOnGroups()); 158 result.setDependsOnMethods(bs.getDependsOnMethods()); 159 result.setDescription(bs.getDescription()); 160 result.setEnabled(bs.getEnabled()); 161 result.setGroups(bs.getGroups()); 162 result.setInheritGroups(bs.getInheritGroups()); 163 result.setParameters(bs.getParameters()); 164 result.setTimeOut(bs.getTimeOut()); 165 } 166 167 private static final Class[] ALL_ANNOTATIONS = new Class[] { 168 ITestAnnotation.class, IConfigurationAnnotation.class, 169 IBeforeClass.class, IAfterClass.class, 170 IBeforeMethod.class, IAfterMethod.class, 171 IDataProviderAnnotation.class, IExpectedExceptionsAnnotation.class, 172 IFactoryAnnotation.class, IParametersAnnotation.class, 173 IBeforeSuite.class, IAfterSuite.class, 174 IBeforeTest.class, IAfterTest.class, 175 IBeforeGroups.class, IAfterGroups.class 176 }; 177 178 public static final Class[] CONFIGURATION_CLASSES = new Class[] { 179 IConfigurationAnnotation.class, 180 IBeforeSuite.class, IAfterSuite.class, 181 IBeforeTest.class, IAfterTest.class, 182 IBeforeGroups.class, IAfterGroups.class, 183 IBeforeClass.class, IAfterClass.class, 184 IBeforeMethod.class, IAfterMethod.class 185 }; 186 getAllAnnotations()187 public static Class[] getAllAnnotations() { 188 return ALL_ANNOTATIONS; 189 } 190 191 /** 192 * Delegation method for creating the list of <CODE>ITestMethod</CODE>s to be 193 * analysed. 194 */ findMethodsWithAnnotation(Class<?> rootClass, Class<? extends IAnnotation> annotationClass, IAnnotationFinder annotationFinder, XmlTest xmlTest)195 public static ITestNGMethod[] findMethodsWithAnnotation(Class<?> rootClass, 196 Class<? extends IAnnotation> annotationClass, IAnnotationFinder annotationFinder, 197 XmlTest xmlTest) 198 { 199 // Keep a map of the methods we saw so that we ignore a method in a superclass if it's 200 // already been seen in a child class 201 Map<String, ITestNGMethod> vResult = Maps.newHashMap(); 202 203 try { 204 vResult = Maps.newHashMap(); 205 // Class[] classes = rootClass.getTestClasses(); 206 Class<?> cls = rootClass; 207 208 // 209 // If the annotation is on the class or superclass, it applies to all public methods 210 // except methods marked with @Configuration 211 // 212 213 // 214 // Otherwise walk through all the methods and keep those 215 // that have the annotation 216 // 217 // for (Class<?> cls : classes) { 218 while (null != cls) { 219 boolean hasClassAnnotation = isAnnotationPresent(annotationFinder, cls, annotationClass); 220 Method[] methods = cls.getDeclaredMethods(); 221 for (Method m : methods) { 222 boolean hasMethodAnnotation = isAnnotationPresent(annotationFinder, m, annotationClass); 223 boolean hasTestNGAnnotation = 224 isAnnotationPresent(annotationFinder, m, IFactoryAnnotation.class) || 225 isAnnotationPresent(annotationFinder, m, ITestAnnotation.class) || 226 isAnnotationPresent(annotationFinder, m, CONFIGURATION_CLASSES); 227 boolean isPublic = Modifier.isPublic(m.getModifiers()); 228 boolean isSynthetic = m.isSynthetic(); 229 if ((isPublic && hasClassAnnotation && !isSynthetic && (! hasTestNGAnnotation)) || hasMethodAnnotation) { 230 231 // Small hack to allow users to specify @Configuration classes even though 232 // a class-level @Test annotation is present. In this case, don't count 233 // that method as a @Test 234 if (isAnnotationPresent(annotationFinder, m, IConfigurationAnnotation.class) && 235 isAnnotationPresent(annotationFinder, cls, ITestAnnotation.class)) 236 { 237 Utils.log("", 3, "Method " + m + " has a configuration annotation" 238 + " and a class-level @Test. This method will only be kept as a" 239 + " configuration method."); 240 241 continue; 242 } 243 244 // Skip the method if it has a return type 245 if (m.getReturnType() != void.class && ! xmlTest.getAllowReturnValues()) { 246 Utils.log("", 2, "Method " + m + " has a @Test annotation" 247 + " but also a return value:" 248 + " ignoring it. Use <suite allow-return-values=\"true\"> to fix this"); 249 continue; 250 } 251 252 String key = createMethodKey(m); 253 if (null == vResult.get(key)) { 254 ITestNGMethod tm = new TestNGMethod(/* m.getDeclaringClass(), */ m, 255 annotationFinder, xmlTest, null); /* @@@ */ 256 vResult.put(key,tm); 257 } 258 } 259 } // for 260 // Now explore the superclass 261 cls = cls.getSuperclass(); 262 } // while 263 264 } 265 catch (SecurityException e) { 266 e.printStackTrace(); 267 } 268 ITestNGMethod[] result = vResult.values().toArray(new ITestNGMethod[vResult.size()]); 269 270 // for (Method m : result) { 271 // ppp(" METHOD FOUND: " + m); 272 // } 273 274 return result; 275 } 276 findAnnotationSuperClasses(Class<?> annotationClass, Class c)277 public static Annotation findAnnotationSuperClasses(Class<?> annotationClass, Class c) { 278 while (c != null) { 279 Annotation result = c.getAnnotation(annotationClass); 280 if (result != null) return result; 281 else c = c.getSuperclass(); 282 } 283 return null; 284 } 285 isAnnotationPresent(IAnnotationFinder annotationFinder, Method m, Class[] annotationClasses)286 private static boolean isAnnotationPresent(IAnnotationFinder annotationFinder, 287 Method m, Class[] annotationClasses) 288 { 289 for (Class a : annotationClasses) { 290 if (annotationFinder.findAnnotation(m, a) != null) { 291 return true; 292 } 293 } 294 295 return false; 296 } 297 isAnnotationPresent(IAnnotationFinder annotationFinder, Method m, Class<? extends IAnnotation> annotationClass)298 private static boolean isAnnotationPresent(IAnnotationFinder annotationFinder, Method m, 299 Class<? extends IAnnotation> annotationClass) { 300 return annotationFinder.findAnnotation(m, annotationClass) != null; 301 } 302 isAnnotationPresent(IAnnotationFinder annotationFinder, Class<?> cls, Class<? extends IAnnotation> annotationClass)303 private static boolean isAnnotationPresent(IAnnotationFinder annotationFinder, Class<?> cls, 304 Class<? extends IAnnotation> annotationClass) { 305 return annotationFinder.findAnnotation(cls, annotationClass) != null; 306 } 307 308 /** 309 * @return A hashcode representing the name of this method and its parameters, 310 * but without its class 311 */ createMethodKey(Method m)312 private static String createMethodKey(Method m) { 313 StringBuffer result = new StringBuffer(m.getName()); 314 for (Class paramClass : m.getParameterTypes()) { 315 result.append(' ').append(paramClass.toString()); 316 } 317 318 return result.toString(); 319 } 320 321 } 322