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