View Javadoc

1   /*
2    * Copyright 2010 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.callbackparams.internal;
18  
19  import java.lang.reflect.Constructor;
20  import java.lang.reflect.Modifier;
21  import java.util.ArrayList;
22  import java.util.List;
23  import org.apache.bcel.generic.Type;
24  import org.callbackparams.internal.template.TestrunCallbacks;
25  import org.callbackparams.support.ClassBytecodeBuilder;
26  
27  class TestrunCallbacksConstructors {
28  
29      private final Class topClassInRebytedPackage;
30      private final List constructorParamTypes;
31  
32      TestrunCallbacksConstructors(Class topClassInRebytedPackage) {
33          this.topClassInRebytedPackage = topClassInRebytedPackage;
34          this.constructorParamTypes = initConstructorParamTypes();
35      }
36  
37      private List initConstructorParamTypes() {
38          Class superClass = topClassInRebytedPackage.getSuperclass();
39          final Constructor[] superClassConstructors =
40                  superClass.getDeclaredConstructors();
41          List constructorParamTypes0 =
42                  new ArrayList(superClassConstructors.length);
43          for (int i = 0 ; i < superClassConstructors.length ; ++i) {
44              final Constructor c = superClassConstructors[i];
45              if (false == isAccessible(c)) {
46                  continue;
47              }
48              final Class[] paramTypes = c.getParameterTypes();
49              if (areParamterTypesAccessible(paramTypes)) {
50                  constructorParamTypes0.add(Type.getTypes(paramTypes));
51              }
52          }
53          return constructorParamTypes0;
54      }
55  
56      private boolean isAccessible(Constructor c) {
57          int modifier = c.getModifiers();
58          return Modifier.isPublic(modifier) || Modifier.isProtected(modifier);
59      }
60  
61      private boolean areParamterTypesAccessible(final Class[] paramTypes) {
62          for (int i = 0 ; i < paramTypes.length ; ++i) {
63              if (false == isParameterTypeAccessible(paramTypes[i])) {
64                  return false;
65              }
66          }
67          return true;
68      }
69  
70      private boolean isParameterTypeAccessible(Class param) {
71          if (param.isPrimitive()) {
72              return true;
73          } else if (param.isArray()) {
74              return isParameterTypeAccessible(param.getComponentType());
75          } else {
76              return isClassAccessible(param);
77          }
78      }
79  
80      private boolean isClassAccessible(Class classOrInterf) {
81          final int modifiers = classOrInterf.getModifiers();
82          if (Modifier.isProtected(modifiers)) {
83              return classOrInterf.isAssignableFrom(topClassInRebytedPackage)
84                      || classOrInterf.getDeclaringClass()
85                      .isAssignableFrom(topClassInRebytedPackage);
86          } else if (false == Modifier.isPublic(modifiers)) {
87              return false;
88          } else if (classOrInterf.isAssignableFrom(topClassInRebytedPackage)) {
89              return true;
90          } else {
91              Class enclosingClass = classOrInterf.getDeclaringClass();
92              return null == enclosingClass || isClassAccessible(enclosingClass);
93          }
94      }
95  
96      boolean needsConstructorModifications(String className) {
97          return topClassInRebytedPackage.getName().equals(className)
98                  || TestrunCallbacks.class.getName().equals(className);
99      }
100 
101     void modifyConstructors(String className, ClassBytecodeBuilder cbb) {
102         if (topClassInRebytedPackage.getName().equals(className)) {
103             cbb.setNewSuperClass(TestrunCallbacks.class.getName());
104 
105         } else if (TestrunCallbacks.class.getName().equals(className)) {
106             cbb.setupTransparentConstructors(constructorParamTypes,
107                     topClassInRebytedPackage.getSuperclass().getName());
108 
109         } else {
110             /* No constructor-modifications are needed ... */
111         }
112     }
113 }