KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > codehaus > aspectwerkz > reflect > ClassInfoHelper


1 /**************************************************************************************
2  * Copyright (c) Jonas Bonér, Alexandre Vasseur. All rights reserved. *
3  * http://aspectwerkz.codehaus.org *
4  * ---------------------------------------------------------------------------------- *
5  * The software in this package is published under the terms of the LGPL license *
6  * a copy of which has been included with this distribution in the license.txt file. *
7  **************************************************************************************/

8 package org.codehaus.aspectwerkz.reflect;
9
10 import java.util.List JavaDoc;
11 import java.util.ArrayList JavaDoc;
12 import java.util.Collections JavaDoc;
13 import java.util.Iterator JavaDoc;
14 import java.util.Set JavaDoc;
15 import java.util.HashSet JavaDoc;
16 import java.util.Map JavaDoc;
17 import java.util.HashMap JavaDoc;
18
19 import org.codehaus.aspectwerkz.transform.TransformationConstants;
20 import org.codehaus.aspectwerkz.reflect.impl.asm.AsmClassInfo;
21
22 /**
23  * Utility method for manipulating and managing ClassInfo hierarchies.
24  *
25  * @author <a HREF="mailto:jboner@codehaus.org">Jonas Bonér </a>
26  * @author <a HREF="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
27  */

28 public class ClassInfoHelper {
29     private static final ArrayList JavaDoc EMPTY_ARRAY_LIST = new ArrayList JavaDoc();
30     private static final String JavaDoc OBJECT_CLASS_NAME = "java.lang.Object";
31
32     /**
33      * Checks if a class has a certain class as super class or interface, somewhere up in the class hierarchy.
34      *
35      * @param classInfo the meta-data for the class to parse
36      * @param superclassName the name of the super class or interface
37      * @return true if we have a parse else false
38      */

39     public static boolean instanceOf(final ClassInfo classInfo, final String JavaDoc superclassName) {
40         return implementsInterface(classInfo, superclassName) || extendsSuperClass(classInfo, superclassName);
41     }
42
43     /**
44      * Checks if a class implements a certain inteface, somewhere up in the class hierarchy, excluding
45      * itself.
46      *
47      * @param classInfo
48      * @param interfaceName
49      * @return true if we have a parse else false
50      */

51     public static boolean implementsInterface(final ClassInfo classInfo, final String JavaDoc interfaceName) {
52         if ((classInfo == null) || (interfaceName == null)) {
53             return false;
54         } else {
55             //TODO: we could lookup in names onlny FIRST to not trigger lazy getInterfaces() stuff
56
ClassInfo[] interfaces = classInfo.getInterfaces();
57             for (int i = 0; i < interfaces.length; i++) {
58                 ClassInfo anInterface = interfaces[i];
59                 if (interfaceName.equals(anInterface.getName())) {
60                     return true;
61                 } else if (ClassInfoHelper.implementsInterface(anInterface, interfaceName)) {
62                     return true;
63                 }
64             }
65             return ClassInfoHelper.implementsInterface(classInfo.getSuperclass(), interfaceName);
66         }
67     }
68
69     /**
70      * Checks if a class has a certain class as super class, somewhere up in the class hierarchy.
71      *
72      * @param classInfo the meta-data for the class to parse
73      * @param className the name of the super class
74      * @return true if we have a parse else false
75      */

76     public static boolean extendsSuperClass(final ClassInfo classInfo, final String JavaDoc className) {
77         if ((classInfo == null) || (className == null)) {
78             return false;
79             // TODO odd comparison
80
// } else if (classInfo.getName().equals(null)) {
81
// return true;
82
} else if (className.equals(classInfo.getName())) {
83             return true;
84         } else {
85             return ClassInfoHelper.extendsSuperClass(classInfo.getSuperclass(), className);
86         }
87     }
88
89     /**
90      * Creates a method list of all the methods in the class and super classes, including package private ones.
91      * Inherited methods are last in the list.
92      *
93      * @param klass the class with the methods
94      * @return the sorted method list
95      */

96     public static List JavaDoc createMethodList(final ClassInfo klass) {
97         if (klass == null) {
98             return EMPTY_ARRAY_LIST;
99         }
100
101         // get this klass methods
102
List JavaDoc methods = new ArrayList JavaDoc();
103         MethodInfo[] methodInfos = klass.getMethods();
104         for (int i = 0; i < methodInfos.length; i++) {
105             MethodInfo methodInfo = methodInfos[i];
106             if (isUserDefinedMethod(methodInfo)) {
107                 methods.add(methodInfo);
108             }
109         }
110
111         // get all the inherited methods, as long as they are user defined ones
112

113         ClassInfo superClass = klass.getSuperclass();
114         if (!superClass.getName().equals(OBJECT_CLASS_NAME)) {
115             List JavaDoc parentMethods = createMethodList(superClass);
116             // merge the method list (parent discovered methods are not added if overrided in this klass)
117
for (Iterator JavaDoc iterator = parentMethods.iterator(); iterator.hasNext();) {
118                 MethodInfo parentMethod = (MethodInfo) iterator.next();
119                 if (!methods.contains(parentMethod)) { // TODO seems to work but ? since tied to declaringTypeName
120
methods.add(parentMethod);
121                 }
122             }
123         }
124         return methods;
125     }
126
127 // /**
128
// * Creates a sorted method list of all the methods in the class and super classes, including package private ones.
129
// *
130
// * @param klass the class with the methods
131
// * @return the sorted method list
132
// */
133
// public static List createSortedMethodList(final ClassInfo klass) {
134
// final List methods = createMethodList(klass);
135
//
136
// // Note: sorting is only use to maintain mixin consistency
137
// //Alex2Jonas - why sort should be needed ??? Collections.sort(methods, MethodComparator.getInstance(MethodComparator.METHOD_INFO));
138
//
139
// return methods;
140
// }
141

142     /**
143      * Collects the methods from all the interface and its super interfaces.
144      *
145      * @param interfaceClassInfo
146      * @return list of methods declared in given class interfaces
147      */

148     public static List JavaDoc collectMethodsFromInterface(final ClassInfo interfaceClassInfo) {
149         final List JavaDoc interfaceDeclaredMethods = new ArrayList JavaDoc();
150         final List JavaDoc sortedMethodList = createMethodList(interfaceClassInfo);
151         for (Iterator JavaDoc it = sortedMethodList.iterator(); it.hasNext();) {
152             MethodInfo methodInfo = (MethodInfo) it.next();
153             if (methodInfo.getDeclaringType().getName().equals(OBJECT_CLASS_NAME)) {
154                 continue;
155             }
156             interfaceDeclaredMethods.add(methodInfo);
157         }
158         // grab methods from all super classes' interfaces
159
ClassInfo superClass = interfaceClassInfo.getSuperclass();
160         if (superClass != null && !superClass.getName().equals(OBJECT_CLASS_NAME)) {
161             interfaceDeclaredMethods.addAll(collectMethodsFromInterfacesImplementedBy(superClass));
162         }
163         return interfaceDeclaredMethods;
164     }
165
166     /**
167      * Collects the methods from all the interfaces of the class and its super interfaces.
168      *
169      * @param classInfo
170      * @return list of methods declared in given class interfaces
171      */

172     public static List JavaDoc collectMethodsFromInterfacesImplementedBy(final ClassInfo classInfo) {
173         final List JavaDoc interfaceDeclaredMethods = new ArrayList JavaDoc();
174         ClassInfo[] interfaces = classInfo.getInterfaces();
175
176         // grab methods from all interfaces and their super interfaces
177
for (int i = 0; i < interfaces.length; i++) {
178             final List JavaDoc sortedMethodList = createMethodList(interfaces[i]);
179             for (Iterator JavaDoc it = sortedMethodList.iterator(); it.hasNext();) {
180                 MethodInfo methodInfo = (MethodInfo) it.next();
181                 if (methodInfo.getDeclaringType().getName().equals(OBJECT_CLASS_NAME)) {
182                     continue;
183                 }
184                 interfaceDeclaredMethods.add(methodInfo);
185             }
186         }
187         // grab methods from all super classes' interfaces
188
ClassInfo superClass = classInfo.getSuperclass();
189         if (superClass != null && !superClass.getName().equals(OBJECT_CLASS_NAME)) {
190             interfaceDeclaredMethods.addAll(collectMethodsFromInterfacesImplementedBy(superClass));
191         }
192         return interfaceDeclaredMethods;
193     }
194
195     /**
196      * Creates a method list of all the methods in the class and super classes, if and only
197      * if those are part of the given list of interfaces declared methods.
198      *
199      * @param klass the class with the methods
200      * @param interfaceDeclaredMethods the list of interface declared methods
201      * @return the sorted method list
202      */

203     public static List JavaDoc createInterfaceDefinedMethodList(final ClassInfo klass,
204                                                               final List JavaDoc interfaceDeclaredMethods) {
205         if (klass == null) {
206             throw new IllegalArgumentException JavaDoc("class to sort method on can not be null");
207         }
208         // get all methods including the inherited methods
209
List JavaDoc methodList = new ArrayList JavaDoc();
210         for (Iterator JavaDoc iterator = createMethodList(klass).iterator(); iterator.hasNext();) {
211             MethodInfo methodInfo = (MethodInfo) iterator.next();
212             if (isDeclaredByInterface(methodInfo, interfaceDeclaredMethods)) {
213                 methodList.add(methodInfo);
214             }
215         }
216         return methodList;
217     }
218
219     /**
220      * Returns true if the method is not of on java.lang.Object and is not an AW generated one
221      *
222      * @param method
223      * @return
224      */

225     private static boolean isUserDefinedMethod(final MethodInfo method) {
226         if (!method.getName().startsWith(TransformationConstants.SYNTHETIC_MEMBER_PREFIX)
227             && !method.getName().startsWith(TransformationConstants.ORIGINAL_METHOD_PREFIX)
228             && !method.getName().startsWith(TransformationConstants.ASPECTWERKZ_PREFIX)) {
229             return true;
230         } else {
231             return false;
232         }
233     }
234
235     /**
236      * Returns true if the method is declared by one of the given method declared in an interface class
237      *
238      * @param method
239      * @param interfaceDeclaredMethods
240      * @return
241      */

242     private static boolean isDeclaredByInterface(final MethodInfo method, final List JavaDoc interfaceDeclaredMethods) {
243         boolean match = false;
244         for (Iterator JavaDoc iterator = interfaceDeclaredMethods.iterator(); iterator.hasNext();) {
245             MethodInfo methodIt = (MethodInfo) iterator.next();
246             if (method.getName().equals(methodIt.getName())) {
247                 // TODO - using param type NAME should be enough - optimize
248
if (method.getParameterTypes().length == methodIt.getParameterTypes().length) {
249                     boolean matchArgs = true;
250                     for (int i = 0; i < method.getParameterTypes().length; i++) {
251                         ClassInfo parameterType = method.getParameterTypes()[i];
252                         if (parameterType.getName().equals(methodIt.getParameterTypes()[i].getName())) {
253                             ;
254                         } else {
255                             matchArgs = false;
256                             break;
257                         }
258                     }
259                     if (matchArgs) {
260                         match = true;
261                         break;
262                     }
263                 }
264             }
265         }
266         return match;
267     }
268
269     /**
270      * Collects all the interface from the given class including the one from its super class.
271      *
272      * @param classInfo
273      * @return list of interface classInfo declared in given class and its hierarchy in correct order
274      */

275     public static List JavaDoc collectInterfaces(final ClassInfo classInfo) {
276         final List JavaDoc interfaceList = new ArrayList JavaDoc();
277         final Set JavaDoc interfaceNames = new HashSet JavaDoc();
278         for (int i = 0; i < classInfo.getInterfaces().length; i++) {
279             ClassInfo interfaceInfo = classInfo.getInterfaces()[i];
280             interfaceList.add(interfaceInfo);
281             interfaceNames.add(interfaceInfo.getName());
282         }
283         for (ClassInfo superClass = classInfo.getSuperclass(); superClass != null; superClass =
284                                                                                    superClass.getSuperclass()) {
285             for (int i = 0; i < superClass.getInterfaces().length; i++) {
286                 ClassInfo interfaceInfo = superClass.getInterfaces()[i];
287                 if (!interfaceNames.contains(interfaceInfo.getName())) {
288                     interfaceList.add(interfaceInfo);
289                     interfaceNames.add(interfaceInfo.getName());
290                 }
291             }
292         }
293         return interfaceList;
294     }
295
296     /**
297      * Checks if a set of interfaces has any clashes, meaning any methods with the same name and signature.
298      *
299      * @param interfacesToAdd
300      * @param loader
301      * @return boolean
302      */

303     public static boolean hasMethodClash(final Set JavaDoc interfacesToAdd, final ClassLoader JavaDoc loader) {
304         // build up the validation structure
305
Map JavaDoc methodMap = new HashMap JavaDoc();
306         for (Iterator JavaDoc it = interfacesToAdd.iterator(); it.hasNext();) {
307             ClassInfo classInfo = AsmClassInfo.getClassInfo((String JavaDoc) it.next(), loader);
308
309             List JavaDoc methods = collectMethodsFromInterface(classInfo);
310
311             for (Iterator JavaDoc it2 = methods.iterator(); it2.hasNext();) {
312                 MethodInfo methodInfo = (MethodInfo) it2.next();
313                 String JavaDoc key = methodInfo.getName() + ':' + methodInfo.getSignature();
314                 if (!methodMap.containsKey(key)) {
315                     methodMap.put(key, new ArrayList JavaDoc());
316                 }
317                 ((List JavaDoc) methodMap.get(key)).add(classInfo.getName());
318             }
319         }
320
321         // validate the structure
322
for (Iterator JavaDoc it = methodMap.entrySet().iterator(); it.hasNext();) {
323             Map.Entry JavaDoc entry = (Map.Entry JavaDoc) it.next();
324             String JavaDoc key = (String JavaDoc) entry.getKey();
325             List JavaDoc interfaceNames = (List JavaDoc) entry.getValue();
326             if (interfaceNames.size() > 1) {
327                 StringBuffer JavaDoc msg = new StringBuffer JavaDoc();
328                 msg.append("can not add interfaces [");
329                 for (Iterator JavaDoc it2 = interfaceNames.iterator(); it2.hasNext();) {
330                     String JavaDoc interfaceName = (String JavaDoc) it2.next();
331                     msg.append(interfaceName);
332                     if (it2.hasNext()) {
333                         msg.append(',');
334                     }
335                 }
336                 msg.append("] since they all have method [");
337                 msg.append(key);
338                 msg.append(']');
339                 System.out.println("AW::WARNING - " + msg.toString());
340                 return true;
341             }
342         }
343         return false;
344     }
345 }
Popular Tags