1 package org.junit.runners.model; 2 3 import java.lang.annotation.Annotation; 4 import java.lang.reflect.InvocationTargetException; 5 import java.lang.reflect.Method; 6 import java.lang.reflect.Type; 7 import java.util.List; 8 9 import org.junit.internal.runners.model.ReflectiveCallable; 10 11 /** 12 * Represents a method on a test class to be invoked at the appropriate point in 13 * test execution. These methods are usually marked with an annotation (such as 14 * {@code @Test}, {@code @Before}, {@code @After}, {@code @BeforeClass}, 15 * {@code @AfterClass}, etc.) 16 * 17 * @since 4.5 18 */ 19 public class FrameworkMethod extends FrameworkMember<FrameworkMethod> { 20 private final Method method; 21 22 /** 23 * Returns a new {@code FrameworkMethod} for {@code method} 24 */ FrameworkMethod(Method method)25 public FrameworkMethod(Method method) { 26 if (method == null) { 27 throw new NullPointerException( 28 "FrameworkMethod cannot be created without an underlying method."); 29 } 30 this.method = method; 31 32 if (isPublic()) { 33 // This method could be a public method in a package-scope base class 34 try { 35 method.setAccessible(true); 36 } catch (SecurityException e) { 37 // We may get an IllegalAccessException when we try to call the method 38 } 39 } 40 } 41 42 /** 43 * Returns the underlying Java method 44 */ getMethod()45 public Method getMethod() { 46 return method; 47 } 48 49 /** 50 * Returns the result of invoking this method on {@code target} with 51 * parameters {@code params}. {@link InvocationTargetException}s thrown are 52 * unwrapped, and their causes rethrown. 53 */ invokeExplosively(final Object target, final Object... params)54 public Object invokeExplosively(final Object target, final Object... params) 55 throws Throwable { 56 return new ReflectiveCallable() { 57 @Override 58 protected Object runReflectiveCall() throws Throwable { 59 return method.invoke(target, params); 60 } 61 }.run(); 62 } 63 64 /** 65 * Returns the method's name 66 */ 67 @Override 68 public String getName() { 69 return method.getName(); 70 } 71 72 /** 73 * Adds to {@code errors} if this method: 74 * <ul> 75 * <li>is not public, or 76 * <li>takes parameters, or 77 * <li>returns something other than void, or 78 * <li>is static (given {@code isStatic is false}), or 79 * <li>is not static (given {@code isStatic is true}). 80 * </ul> 81 */ 82 public void validatePublicVoidNoArg(boolean isStatic, List<Throwable> errors) { 83 validatePublicVoid(isStatic, errors); 84 if (method.getParameterTypes().length != 0) { 85 errors.add(new Exception("Method " + method.getName() + " should have no parameters")); 86 } 87 } 88 89 90 /** 91 * Adds to {@code errors} if this method: 92 * <ul> 93 * <li>is not public, or 94 * <li>returns something other than void, or 95 * <li>is static (given {@code isStatic is false}), or 96 * <li>is not static (given {@code isStatic is true}). 97 * </ul> 98 */ 99 public void validatePublicVoid(boolean isStatic, List<Throwable> errors) { 100 if (isStatic() != isStatic) { 101 String state = isStatic ? "should" : "should not"; 102 errors.add(new Exception("Method " + method.getName() + "() " + state + " be static")); 103 } 104 if (!isPublic()) { 105 errors.add(new Exception("Method " + method.getName() + "() should be public")); 106 } 107 if (method.getReturnType() != Void.TYPE) { 108 errors.add(new Exception("Method " + method.getName() + "() should be void")); 109 } 110 } 111 112 @Override 113 protected int getModifiers() { 114 return method.getModifiers(); 115 } 116 117 /** 118 * Returns the return type of the method 119 */ 120 public Class<?> getReturnType() { 121 return method.getReturnType(); 122 } 123 124 /** 125 * Returns the return type of the method 126 */ 127 @Override 128 public Class<?> getType() { 129 return getReturnType(); 130 } 131 132 /** 133 * Returns the class where the method is actually declared 134 */ 135 @Override 136 public Class<?> getDeclaringClass() { 137 return method.getDeclaringClass(); 138 } 139 140 public void validateNoTypeParametersOnArgs(List<Throwable> errors) { 141 new NoGenericTypeParametersValidator(method).validate(errors); 142 } 143 144 @Override 145 public boolean isShadowedBy(FrameworkMethod other) { 146 if (!other.getName().equals(getName())) { 147 return false; 148 } 149 if (other.getParameterTypes().length != getParameterTypes().length) { 150 return false; 151 } 152 for (int i = 0; i < other.getParameterTypes().length; i++) { 153 if (!other.getParameterTypes()[i].equals(getParameterTypes()[i])) { 154 return false; 155 } 156 } 157 return true; 158 } 159 160 @Override 161 boolean isBridgeMethod() { 162 return method.isBridge(); 163 } 164 165 @Override 166 public boolean equals(Object obj) { 167 if (!FrameworkMethod.class.isInstance(obj)) { 168 return false; 169 } 170 return ((FrameworkMethod) obj).method.equals(method); 171 } 172 173 @Override 174 public int hashCode() { 175 return method.hashCode(); 176 } 177 178 /** 179 * Returns true if this is a no-arg method that returns a value assignable 180 * to {@code type} 181 * 182 * @deprecated This is used only by the Theories runner, and does not 183 * use all the generic type info that it ought to. It will be replaced 184 * with a forthcoming ParameterSignature#canAcceptResultOf(FrameworkMethod) 185 * once Theories moves to junit-contrib. 186 */ 187 @Deprecated 188 public boolean producesType(Type type) { 189 return getParameterTypes().length == 0 && type instanceof Class<?> 190 && ((Class<?>) type).isAssignableFrom(method.getReturnType()); 191 } 192 193 private Class<?>[] getParameterTypes() { 194 return method.getParameterTypes(); 195 } 196 197 /** 198 * Returns the annotations on this method 199 */ 200 public Annotation[] getAnnotations() { 201 return method.getAnnotations(); 202 } 203 204 /** 205 * Returns the annotation of type {@code annotationType} on this method, if 206 * one exists. 207 */ 208 public <T extends Annotation> T getAnnotation(Class<T> annotationType) { 209 return method.getAnnotation(annotationType); 210 } 211 212 @Override 213 public String toString() { 214 return method.toString(); 215 } 216 } 217