View Javadoc

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.impl.java;
9   
10  import gnu.trove.TIntObjectHashMap;
11  import org.codehaus.aspectwerkz.annotation.Annotations;
12  import org.codehaus.aspectwerkz.reflect.ClassInfo;
13  import org.codehaus.aspectwerkz.reflect.ConstructorInfo;
14  import org.codehaus.aspectwerkz.reflect.FieldInfo;
15  import org.codehaus.aspectwerkz.reflect.MethodInfo;
16  import org.codehaus.aspectwerkz.transform.TransformationUtil;
17  import org.codehaus.aspectwerkz.transform.ReflectHelper;
18  import org.codehaus.aspectwerkz.transform.TransformationConstants;
19  
20  import java.lang.reflect.Constructor;
21  import java.lang.reflect.Field;
22  import java.lang.reflect.Method;
23  import java.util.List;
24  
25  /***
26   * Implementation of the ClassInfo interface for java.lang.reflect.*.
27   * 
28   * @author <a href="mailto:jboner@codehaus.org">Jonas Bonér </a>
29   */
30  public class JavaClassInfo implements ClassInfo {
31      /***
32       * The class.
33       */
34      private final Class m_class;
35  
36      /***
37       * The name of the class.
38       */
39      private String m_name;
40  
41      /***
42       * Is the class an interface.
43       */
44      private boolean m_isInterface = false;
45  
46      /***
47       * Is the class a primitive type.
48       */
49      private boolean m_isPrimitive = false;
50  
51      /***
52       * Is the class of type array.
53       */
54      private boolean m_isArray = false;
55  
56      /***
57       * A list with the <code>ConstructorInfo</code> instances.
58       */
59      private final TIntObjectHashMap m_constructors = new TIntObjectHashMap();
60  
61      /***
62       * A list with the <code>MethodInfo</code> instances.
63       */
64      private final TIntObjectHashMap m_methods = new TIntObjectHashMap();
65  
66      /***
67       * A list with the <code>FieldInfo</code> instances.
68       */
69      private final TIntObjectHashMap m_fields = new TIntObjectHashMap();
70  
71      /***
72       * A list with the interfaces.
73       */
74      private ClassInfo[] m_interfaces = null;
75  
76      /***
77       * The super class.
78       */
79      private ClassInfo m_superClass = null;
80  
81      /***
82       * The annotations.
83       */
84      private List m_annotations = null;
85  
86      /***
87       * The component type if array type.
88       */
89      private ClassInfo m_componentType = null;
90  
91      /***
92       * The class info repository.
93       */
94      private final JavaClassInfoRepository m_classInfoRepository;
95  
96      /***
97       * Creates a new class meta data instance.
98       * 
99       * @param klass
100      */
101     JavaClassInfo(final Class klass) {
102         if (klass == null) {
103             throw new IllegalArgumentException("class can not be null");
104         }
105         m_class = klass;
106         m_classInfoRepository = JavaClassInfoRepository.getRepository(klass.getClassLoader());
107         m_isInterface = klass.isInterface();
108         if (klass.isPrimitive()) {
109             m_name = klass.getName();
110             m_isPrimitive = true;
111         } else if (klass.getComponentType() != null) {
112             m_name = convertJavaArrayTypeNameToHumanTypeName(klass.getName());
113             m_isArray = true;
114             m_interfaces = new ClassInfo[0];
115         } else {
116             m_name = klass.getName();
117             Method[] methods = m_class.getDeclaredMethods();
118             for (int i = 0; i < methods.length; i++) {
119                 Method method = methods[i];
120                 m_methods.put(ReflectHelper.calculateHash(method), new JavaMethodInfo(method, this));
121             }
122             Constructor[] constructors = m_class.getDeclaredConstructors();
123             for (int i = 0; i < constructors.length; i++) {
124                 Constructor constructor = constructors[i];
125                 m_constructors.put(ReflectHelper.calculateHash(constructor), new JavaConstructorInfo(
126                     constructor,
127                     this));
128             }
129             Field[] fields = m_class.getDeclaredFields();
130             for (int i = 0; i < fields.length; i++) {
131                 if (fields[i].getName().startsWith(TransformationConstants.ASPECTWERKZ_PREFIX)) {
132                     continue;
133                 }
134                 Field field = fields[i];
135                 m_fields.put(ReflectHelper.calculateHash(field), new JavaFieldInfo(field, this));
136             }
137         }
138         m_classInfoRepository.addClassInfo(this);
139     }
140 
141     /***
142      * Returns the class info for a specific class.
143      * 
144      * @return the class info
145      */
146     public static ClassInfo getClassInfo(final Class clazz) {
147         JavaClassInfoRepository repository = JavaClassInfoRepository.getRepository(clazz.getClassLoader());
148         ClassInfo classInfo = repository.getClassInfo(clazz.getName());
149         if (classInfo == null) {
150             classInfo = new JavaClassInfo(clazz);
151         }
152         return classInfo;
153     }
154 
155     /***
156      * Returns the annotations infos.
157      * 
158      * @return the annotations infos
159      */
160     public List getAnnotations() {
161         if (m_annotations == null) {
162             m_annotations = Annotations.getAnnotationInfos(m_class);
163         }
164         return m_annotations;
165     }
166 
167     /***
168      * Returns the name of the class.
169      * 
170      * @return the name of the class
171      */
172     public String getName() {
173         return m_name.replace('/', '.');
174     }
175 
176     /***
177      * Returns the class modifiers.
178      * 
179      * @return the class modifiers
180      */
181     public int getModifiers() {
182         return m_class.getModifiers();
183     }
184 
185     /***
186      * Returns a constructor info by its hash.
187      * 
188      * @param hash
189      * @return
190      */
191     public ConstructorInfo getConstructor(final int hash) {
192         return (ConstructorInfo) m_constructors.get(hash);
193     }
194 
195     /***
196      * Returns a list with all the constructors info.
197      * 
198      * @return the constructors info
199      */
200     public ConstructorInfo[] getConstructors() {
201         Object[] values = m_constructors.getValues();
202         ConstructorInfo[] methodInfos = new ConstructorInfo[values.length];
203         for (int i = 0; i < values.length; i++) {
204             methodInfos[i] = (ConstructorInfo) values[i];
205         }
206         return methodInfos;
207     }
208 
209     /***
210      * Returns a method info by its hash.
211      * 
212      * @param hash
213      * @return
214      */
215     public MethodInfo getMethod(final int hash) {
216         return (MethodInfo) m_methods.get(hash);
217     }
218 
219     /***
220      * Returns a list with all the methods info.
221      * 
222      * @return the methods info
223      */
224     public MethodInfo[] getMethods() {
225         Object[] values = m_methods.getValues();
226         MethodInfo[] methodInfos = new MethodInfo[values.length];
227         for (int i = 0; i < values.length; i++) {
228             methodInfos[i] = (MethodInfo) values[i];
229         }
230         return methodInfos;
231     }
232 
233     /***
234      * Returns a field info by its hash.
235      * 
236      * @param hash
237      * @return
238      */
239     public FieldInfo getField(final int hash) {
240         return (FieldInfo) m_fields.get(hash);
241     }
242 
243     /***
244      * Returns a list with all the field info.
245      * 
246      * @return the field info
247      */
248     public FieldInfo[] getFields() {
249         Object[] values = m_fields.getValues();
250         FieldInfo[] fieldInfos = new FieldInfo[values.length];
251         for (int i = 0; i < values.length; i++) {
252             fieldInfos[i] = (FieldInfo) values[i];
253         }
254         return fieldInfos;
255     }
256 
257     /***
258      * Returns the interfaces.
259      * 
260      * @return the interfaces
261      */
262     public ClassInfo[] getInterfaces() {
263         if (m_interfaces == null) {
264             Class[] interfaces = m_class.getInterfaces();
265             m_interfaces = new ClassInfo[interfaces.length];
266             for (int i = 0; i < interfaces.length; i++) {
267                 Class anInterface = interfaces[i];
268                 ClassInfo classInfo = JavaClassInfo.getClassInfo(anInterface);
269                 m_interfaces[i] = classInfo;
270                 if (!m_classInfoRepository.hasClassInfo(anInterface.getName())) {
271                     m_classInfoRepository.addClassInfo(classInfo);
272                 }
273             }
274         }
275         return m_interfaces;
276     }
277 
278     /***
279      * Returns the super class.
280      * 
281      * @return the super class
282      */
283     public ClassInfo getSuperClass() {
284         if (m_superClass == null) {
285             Class superclass = m_class.getSuperclass();
286             if (superclass != null) {
287                 if (m_classInfoRepository.hasClassInfo(superclass.getName())) {
288                     m_superClass = m_classInfoRepository.getClassInfo(superclass.getName());
289                 } else {
290                     m_superClass = JavaClassInfo.getClassInfo(superclass);
291                     m_classInfoRepository.addClassInfo(m_superClass);
292                 }
293             }
294         }
295         return m_superClass;
296     }
297 
298     /***
299      * Returns the component type if array type else null.
300      * 
301      * @return the component type
302      */
303     public ClassInfo getComponentType() {
304         if (isArray() && (m_componentType == null)) {
305             Class componentType = m_class.getComponentType();
306             if (m_classInfoRepository.hasClassInfo(componentType.getName())) {
307                 m_componentType = m_classInfoRepository.getClassInfo(componentType.getName());
308             } else {
309                 m_componentType = JavaClassInfo.getClassInfo(componentType);
310                 m_classInfoRepository.addClassInfo(m_componentType);
311             }
312         }
313         return m_componentType;
314     }
315 
316     /***
317      * Is the class an interface.
318      * 
319      * @return
320      */
321     public boolean isInterface() {
322         return m_isInterface;
323     }
324 
325     /***
326      * Is the class a primitive type.
327      * 
328      * @return
329      */
330     public boolean isPrimitive() {
331         return m_isPrimitive;
332     }
333 
334     /***
335      * Is the class an array type.
336      * 
337      * @return
338      */
339     public boolean isArray() {
340         return m_isArray;
341     }
342 
343     /***
344      * Converts an internal Java array type name ([Lblabla) to the a the format used by the expression matcher
345      * (blabla[])
346      * 
347      * @param typeName is type name
348      * @return
349      */
350     public static String convertJavaArrayTypeNameToHumanTypeName(final String typeName) {
351         int index = typeName.lastIndexOf('[');
352         if (index != -1) {
353             StringBuffer arrayType = new StringBuffer();
354             if (typeName.endsWith("I")) {
355                 arrayType.append("int");
356             } else if (typeName.endsWith("J")) {
357                 arrayType.append("long");
358             } else if (typeName.endsWith("S")) {
359                 arrayType.append("short");
360             } else if (typeName.endsWith("F")) {
361                 arrayType.append("float");
362             } else if (typeName.endsWith("D")) {
363                 arrayType.append("double");
364             } else if (typeName.endsWith("Z")) {
365                 arrayType.append("boolean");
366             } else if (typeName.endsWith("C")) {
367                 arrayType.append("char");
368             } else if (typeName.endsWith("B")) {
369                 arrayType.append("byte");
370             } else {
371                 arrayType.append(typeName.substring(index + 2, typeName.length() - 1));
372             }
373             for (int i = 0; i < (index + 1); i++) {
374                 arrayType.append("[]");
375             }
376             return arrayType.toString();
377         } else {
378             return typeName;
379         }
380     }
381 
382     public boolean equals(Object o) {
383         if (this == o) {
384             return true;
385         }
386         if (!(o instanceof ClassInfo)) {
387             return false;
388         }
389         ClassInfo classInfo = (ClassInfo) o;
390         return m_class.getName().toString().equals(classInfo.getName().toString());
391     }
392 
393     public int hashCode() {
394         return m_class.getName().toString().hashCode();
395     }
396 
397     public String toString() {
398         return getName();
399     }
400 }