001package org.junit.runners.model; 002 003import java.lang.annotation.Annotation; 004import java.lang.reflect.InvocationTargetException; 005import java.lang.reflect.Method; 006import java.lang.reflect.Modifier; 007import java.lang.reflect.Type; 008import java.util.List; 009 010import org.junit.internal.runners.model.ReflectiveCallable; 011 012/** 013 * Represents a method on a test class to be invoked at the appropriate point in 014 * test execution. These methods are usually marked with an annotation (such as 015 * {@code @Test}, {@code @Before}, {@code @After}, {@code @BeforeClass}, 016 * {@code @AfterClass}, etc.) 017 * 018 * @since 4.5 019 */ 020public class FrameworkMethod extends FrameworkMember<FrameworkMethod> { 021 final Method fMethod; 022 023 /** 024 * Returns a new {@code FrameworkMethod} for {@code method} 025 */ 026 public FrameworkMethod(Method method) { 027 fMethod = method; 028 } 029 030 /** 031 * Returns the underlying Java method 032 */ 033 public Method getMethod() { 034 return fMethod; 035 } 036 037 /** 038 * Returns the result of invoking this method on {@code target} with 039 * parameters {@code params}. {@link InvocationTargetException}s thrown are 040 * unwrapped, and their causes rethrown. 041 */ 042 public Object invokeExplosively(final Object target, final Object... params) 043 throws Throwable { 044 return new ReflectiveCallable() { 045 @Override 046 protected Object runReflectiveCall() throws Throwable { 047 return fMethod.invoke(target, params); 048 } 049 }.run(); 050 } 051 052 /** 053 * Returns the method's name 054 */ 055 @Override 056 public String getName() { 057 return fMethod.getName(); 058 } 059 060 /** 061 * Adds to {@code errors} if this method: 062 * <ul> 063 * <li>is not public, or 064 * <li>takes parameters, or 065 * <li>returns something other than void, or 066 * <li>is static (given {@code isStatic is false}), or 067 * <li>is not static (given {@code isStatic is true}). 068 */ 069 public void validatePublicVoidNoArg(boolean isStatic, List<Throwable> errors) { 070 validatePublicVoid(isStatic, errors); 071 if (fMethod.getParameterTypes().length != 0) { 072 errors.add(new Exception("Method " + fMethod.getName() + " should have no parameters")); 073 } 074 } 075 076 077 /** 078 * Adds to {@code errors} if this method: 079 * <ul> 080 * <li>is not public, or 081 * <li>returns something other than void, or 082 * <li>is static (given {@code isStatic is false}), or 083 * <li>is not static (given {@code isStatic is true}). 084 */ 085 public void validatePublicVoid(boolean isStatic, List<Throwable> errors) { 086 if (Modifier.isStatic(fMethod.getModifiers()) != isStatic) { 087 String state = isStatic ? "should" : "should not"; 088 errors.add(new Exception("Method " + fMethod.getName() + "() " + state + " be static")); 089 } 090 if (!Modifier.isPublic(fMethod.getDeclaringClass().getModifiers())) { 091 errors.add(new Exception("Class " + fMethod.getDeclaringClass().getName() + " should be public")); 092 } 093 if (!Modifier.isPublic(fMethod.getModifiers())) { 094 errors.add(new Exception("Method " + fMethod.getName() + "() should be public")); 095 } 096 if (fMethod.getReturnType() != Void.TYPE) { 097 errors.add(new Exception("Method " + fMethod.getName() + "() should be void")); 098 } 099 } 100 101 /** 102 * Returns true if this method is static, false if not 103 */ 104 @Override 105 public boolean isStatic() { 106 return Modifier.isStatic(fMethod.getModifiers()); 107 } 108 109 /** 110 * Returns true if this method is public, false if not 111 */ 112 @Override 113 public boolean isPublic() { 114 return Modifier.isPublic(fMethod.getModifiers()); 115 } 116 117 /** 118 * Returns the return type of the method 119 */ 120 public Class<?> getReturnType() { 121 return fMethod.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 public void validateNoTypeParametersOnArgs(List<Throwable> errors) { 133 new NoGenericTypeParametersValidator(fMethod).validate(errors); 134 } 135 136 @Override 137 public boolean isShadowedBy(FrameworkMethod other) { 138 if (!other.getName().equals(getName())) { 139 return false; 140 } 141 if (other.getParameterTypes().length != getParameterTypes().length) { 142 return false; 143 } 144 for (int i = 0; i < other.getParameterTypes().length; i++) { 145 if (!other.getParameterTypes()[i].equals(getParameterTypes()[i])) { 146 return false; 147 } 148 } 149 return true; 150 } 151 152 @Override 153 public boolean equals(Object obj) { 154 if (!FrameworkMethod.class.isInstance(obj)) { 155 return false; 156 } 157 return ((FrameworkMethod) obj).fMethod.equals(fMethod); 158 } 159 160 @Override 161 public int hashCode() { 162 return fMethod.hashCode(); 163 } 164 165 /** 166 * Returns true if this is a no-arg method that returns a value assignable 167 * to {@code type} 168 * 169 * @deprecated This is used only by the Theories runner, and does not 170 * use all the generic type info that it ought to. It will be replaced 171 * with a forthcoming ParameterSignature#canAcceptResultOf(FrameworkMethod) 172 * once Theories moves to junit-contrib. 173 */ 174 @Deprecated 175 public boolean producesType(Type type) { 176 return getParameterTypes().length == 0 && type instanceof Class<?> 177 && ((Class<?>) type).isAssignableFrom(fMethod.getReturnType()); 178 } 179 180 private Class<?>[] getParameterTypes() { 181 return fMethod.getParameterTypes(); 182 } 183 184 /** 185 * Returns the annotations on this method 186 */ 187 @Override 188 public Annotation[] getAnnotations() { 189 return fMethod.getAnnotations(); 190 } 191 192 /** 193 * Returns the annotation of type {@code annotationType} on this method, if 194 * one exists. 195 */ 196 public <T extends Annotation> T getAnnotation(Class<T> annotationType) { 197 return fMethod.getAnnotation(annotationType); 198 } 199}