View Javadoc
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       */
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       */
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       */
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 }