View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.surefire.common.junit3;
20  
21  import java.lang.reflect.Constructor;
22  import java.lang.reflect.InvocationTargetException;
23  import java.lang.reflect.Method;
24  import java.lang.reflect.Modifier;
25  
26  import org.apache.maven.surefire.api.util.ReflectionUtils;
27  
28  /**
29   * Reflection facade for JUnit3 classes
30   *
31   */
32  public final class JUnit3Reflector {
33      private static final String TEST_CASE = "junit.framework.Test";
34  
35      private static final String TEST_RESULT = "junit.framework.TestResult";
36  
37      private static final String TEST_LISTENER = "junit.framework.TestListener";
38  
39      private static final String TEST = "junit.framework.Test";
40  
41      private static final String ADD_LISTENER_METHOD = "addListener";
42  
43      private static final String RUN_METHOD = "run";
44  
45      private static final String TEST_SUITE = "junit.framework.TestSuite";
46  
47      private static final Class<?>[] EMPTY_CLASS_ARRAY = {};
48  
49      private static final Object[] EMPTY_OBJECT_ARRAY = {};
50  
51      private final Class<?>[] interfacesImplementedByDynamicProxy;
52  
53      private final Class<?> testResultClass;
54  
55      private final Method addListenerMethod;
56  
57      private final Method testInterfaceRunMethod;
58  
59      private final Class<?> testInterface;
60  
61      private final Class<?> testCase;
62  
63      private final Constructor<?> testsSuiteConstructor;
64  
65      public JUnit3Reflector(ClassLoader testClassLoader) {
66          testResultClass = ReflectionUtils.tryLoadClass(testClassLoader, TEST_RESULT);
67          testCase = ReflectionUtils.tryLoadClass(testClassLoader, TEST_CASE);
68          testInterface = ReflectionUtils.tryLoadClass(testClassLoader, TEST);
69          interfacesImplementedByDynamicProxy =
70                  new Class[] {ReflectionUtils.tryLoadClass(testClassLoader, TEST_LISTENER)};
71          Class<?>[] constructorParamTypes = {Class.class};
72  
73          Class<?> testSuite = ReflectionUtils.tryLoadClass(testClassLoader, TEST_SUITE);
74  
75          // The interface implemented by the dynamic proxy (TestListener), happens to be
76          // the same as the param types of TestResult.addTestListener
77  
78          if (isJUnit3Available()) {
79              testsSuiteConstructor = ReflectionUtils.getConstructor(testSuite, constructorParamTypes);
80              addListenerMethod = tryGetMethod(testResultClass, ADD_LISTENER_METHOD, interfacesImplementedByDynamicProxy);
81              testInterfaceRunMethod = getMethod(testInterface, RUN_METHOD, testResultClass);
82          } else {
83              testsSuiteConstructor = null;
84              addListenerMethod = null;
85              testInterfaceRunMethod = null;
86          }
87      }
88  
89      // Switch to reflectionutils when building with 2.7.2
90      private static Method tryGetMethod(Class<?> clazz, String methodName, Class<?>... parameters) {
91          try {
92              return clazz.getMethod(methodName, parameters);
93          } catch (NoSuchMethodException e) {
94              return null;
95          }
96      }
97  
98      private static Method getMethod(Class<?> clazz, String methodName, Class<?>... parameters) {
99          try {
100             return clazz.getMethod(methodName, parameters);
101         } catch (NoSuchMethodException e) {
102             throw new RuntimeException("When finding method " + methodName, e);
103         }
104     }
105 
106     public Object constructTestObject(Class<?> testClass)
107             throws IllegalAccessException, InvocationTargetException, NoSuchMethodException, InstantiationException {
108         Object testObject = createInstanceFromSuiteMethod(testClass);
109 
110         if (testObject == null && testCase.isAssignableFrom(testClass)) {
111             testObject = testsSuiteConstructor.newInstance(testClass);
112         }
113 
114         if (testObject == null) {
115             Constructor<?> testConstructor = getTestConstructor(testClass);
116 
117             if (testConstructor.getParameterTypes().length == 0) {
118                 testObject = testConstructor.newInstance(EMPTY_OBJECT_ARRAY);
119             } else {
120                 testObject = testConstructor.newInstance(testClass.getName());
121             }
122         }
123         return testObject;
124     }
125 
126     private static Object createInstanceFromSuiteMethod(Class<?> testClass)
127             throws IllegalAccessException, InvocationTargetException {
128         Object testObject = null;
129         try {
130             Method suiteMethod = testClass.getMethod("suite", EMPTY_CLASS_ARRAY);
131 
132             if (Modifier.isPublic(suiteMethod.getModifiers()) && Modifier.isStatic(suiteMethod.getModifiers())) {
133                 testObject = suiteMethod.invoke(null, EMPTY_OBJECT_ARRAY);
134             }
135         } catch (NoSuchMethodException e) {
136             // No suite method
137         }
138         return testObject;
139     }
140 
141     private static Constructor<?> getTestConstructor(Class<?> testClass) throws NoSuchMethodException {
142         try {
143             return testClass.getConstructor(String.class);
144         } catch (NoSuchMethodException e) {
145             return testClass.getConstructor(EMPTY_CLASS_ARRAY);
146         }
147     }
148 
149     public Class<?>[] getInterfacesImplementedByDynamicProxy() {
150         return interfacesImplementedByDynamicProxy;
151     }
152 
153     public Class<?> getTestResultClass() {
154         return testResultClass;
155     }
156 
157     public Method getAddListenerMethod() {
158         return addListenerMethod;
159     }
160 
161     public Method getTestInterfaceRunMethod() {
162         return testInterfaceRunMethod;
163     }
164 
165     public Class<?> getTestInterface() {
166         return testInterface;
167     }
168 
169     public Method getRunMethod(Class<?> testClass) {
170         return getMethod(testClass, RUN_METHOD, getTestResultClass());
171     }
172 
173     public boolean isJUnit3Available() {
174         return testResultClass != null;
175     }
176 }