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 33 /** 34 * Returns the underlying Java method 35 */ getMethod()36 public Method getMethod() { 37 return method; 38 } 39 40 /** 41 * Returns the result of invoking this method on {@code target} with 42 * parameters {@code params}. {@link InvocationTargetException}s thrown are 43 * unwrapped, and their causes rethrown. 44 */ invokeExplosively(final Object target, final Object... params)45 public Object invokeExplosively(final Object target, final Object... params) 46 throws Throwable { 47 return new ReflectiveCallable() { 48 @Override 49 protected Object runReflectiveCall() throws Throwable { 50 return method.invoke(target, params); 51 } 52 }.run(); 53 } 54 55 /** 56 * Returns the method's name 57 */ 58 @Override 59 public String getName() { 60 return method.getName(); 61 } 62 63 /** 64 * Adds to {@code errors} if this method: 65 * <ul> 66 * <li>is not public, or 67 * <li>takes parameters, or 68 * <li>returns something other than void, or 69 * <li>is static (given {@code isStatic is false}), or 70 * <li>is not static (given {@code isStatic is true}). 71 * </ul> 72 */ 73 public void validatePublicVoidNoArg(boolean isStatic, List<Throwable> errors) { 74 validatePublicVoid(isStatic, errors); 75 if (method.getParameterTypes().length != 0) { 76 errors.add(new Exception("Method " + method.getName() + " should have no parameters")); 77 } 78 } 79 80 81 /** 82 * Adds to {@code errors} if this method: 83 * <ul> 84 * <li>is not public, or 85 * <li>returns something other than void, or 86 * <li>is static (given {@code isStatic is false}), or 87 * <li>is not static (given {@code isStatic is true}). 88 * </ul> 89 */ 90 public void validatePublicVoid(boolean isStatic, List<Throwable> errors) { 91 if (isStatic() != isStatic) { 92 String state = isStatic ? "should" : "should not"; 93 errors.add(new Exception("Method " + method.getName() + "() " + state + " be static")); 94 } 95 if (!isPublic()) { 96 errors.add(new Exception("Method " + method.getName() + "() should be public")); 97 } 98 if (method.getReturnType() != Void.TYPE) { 99 errors.add(new Exception("Method " + method.getName() + "() should be void")); 100 } 101 } 102 103 @Override 104 protected int getModifiers() { 105 return method.getModifiers(); 106 } 107 108 /** 109 * Returns the return type of the method 110 */ 111 public Class<?> getReturnType() { 112 return method.getReturnType(); 113 } 114 115 /** 116 * Returns the return type of the method 117 */ 118 @Override 119 public Class<?> getType() { 120 return getReturnType(); 121 } 122 123 /** 124 * Returns the class where the method is actually declared 125 */ 126 @Override 127 public Class<?> getDeclaringClass() { 128 return method.getDeclaringClass(); 129 } 130 131 public void validateNoTypeParametersOnArgs(List<Throwable> errors) { 132 new NoGenericTypeParametersValidator(method).validate(errors); 133 } 134 135 @Override 136 public boolean isShadowedBy(FrameworkMethod other) { 137 if (!other.getName().equals(getName())) { 138 return false; 139 } 140 if (other.getParameterTypes().length != getParameterTypes().length) { 141 return false; 142 } 143 for (int i = 0; i < other.getParameterTypes().length; i++) { 144 if (!other.getParameterTypes()[i].equals(getParameterTypes()[i])) { 145 return false; 146 } 147 } 148 return true; 149 } 150 151 @Override 152 public boolean equals(Object obj) { 153 if (!FrameworkMethod.class.isInstance(obj)) { 154 return false; 155 } 156 return ((FrameworkMethod) obj).method.equals(method); 157 } 158 159 @Override 160 public int hashCode() { 161 return method.hashCode(); 162 } 163 164 /** 165 * Returns true if this is a no-arg method that returns a value assignable 166 * to {@code type} 167 * 168 * @deprecated This is used only by the Theories runner, and does not 169 * use all the generic type info that it ought to. It will be replaced 170 * with a forthcoming ParameterSignature#canAcceptResultOf(FrameworkMethod) 171 * once Theories moves to junit-contrib. 172 */ 173 @Deprecated 174 public boolean producesType(Type type) { 175 return getParameterTypes().length == 0 && type instanceof Class<?> 176 && ((Class<?>) type).isAssignableFrom(method.getReturnType()); 177 } 178 179 private Class<?>[] getParameterTypes() { 180 return method.getParameterTypes(); 181 } 182 183 /** 184 * Returns the annotations on this method 185 */ 186 public Annotation[] getAnnotations() { 187 return method.getAnnotations(); 188 } 189 190 /** 191 * Returns the annotation of type {@code annotationType} on this method, if 192 * one exists. 193 */ 194 public <T extends Annotation> T getAnnotation(Class<T> annotationType) { 195 return method.getAnnotation(annotationType); 196 } 197 198 @Override 199 public String toString() { 200 return method.toString(); 201 } 202 } 203