KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > tc > aspectwerkz > reflect > impl > asm > AsmClassInfo


1 /*
2  * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright notice. All rights reserved.
3  */

4 package com.tc.aspectwerkz.reflect.impl.asm;
5
6
7 import com.tc.backport175.bytecode.AnnotationElement;
8 import com.tc.backport175.bytecode.AnnotationReader;
9 import com.tc.asm.*;
10
11 import com.tc.aspectwerkz.exception.WrappedRuntimeException;
12 import com.tc.aspectwerkz.reflect.impl.java.JavaClassInfo;
13 import com.tc.aspectwerkz.reflect.ClassInfo;
14 import com.tc.aspectwerkz.reflect.StaticInitializationInfo;
15 import com.tc.aspectwerkz.reflect.ConstructorInfo;
16 import com.tc.aspectwerkz.reflect.MethodInfo;
17 import com.tc.aspectwerkz.reflect.StaticInitializationInfoImpl;
18 import com.tc.aspectwerkz.reflect.FieldInfo;
19 import com.tc.aspectwerkz.transform.TransformationConstants;
20 import com.tc.aspectwerkz.transform.inlining.AsmHelper;
21 import com.tc.aspectwerkz.transform.inlining.AsmNullAdapter;
22 import com.tc.aspectwerkz.util.ContextClassLoader;
23
24 import java.io.IOException JavaDoc;
25 import java.io.InputStream JavaDoc;
26 import java.lang.ref.WeakReference JavaDoc;
27 import java.lang.reflect.Array JavaDoc;
28 import java.lang.reflect.Modifier JavaDoc;
29 import java.util.ArrayList JavaDoc;
30 import java.util.HashMap JavaDoc;
31 import java.util.List JavaDoc;
32
33 /**
34  * Implementation of the ClassInfo interface utilizing the ASM bytecode library for the info retriaval.
35  * <p/>
36  * Annotations are lazily gathered, unless required to visit them at the same time as we visit methods and fields.
37  * <p/>
38  * This implementation guarantees that the method, fields and constructors can be retrieved in the same order as they were in the bytecode
39  * (it can depends of the compiler and might not be the order of the source code - f.e. IBM compiler)
40  *
41  * @author <a HREF="mailto:jboner@codehaus.org">Jonas BonŽr </a>
42  * @author <a HREF="mailto:alex@gnilux.com">Alexandre Vasseur </a>
43  */

44 public class AsmClassInfo implements ClassInfo {
45
46   protected final static String JavaDoc[] EMPTY_STRING_ARRAY = new String JavaDoc[0];
47
48   protected final static List JavaDoc EMPTY_LIST = new ArrayList JavaDoc();
49
50   /**
51    * The class loader wrapped in a weak ref.
52    */

53   private final WeakReference JavaDoc m_loaderRef;
54
55   /**
56    * The name of the class (with dots and not slashes)
57    */

58   private String JavaDoc m_name;
59
60   /**
61    * The signature of the class.
62    */

63   private String JavaDoc m_signature;
64
65   /**
66    * The internal generics signature for this class.
67    */

68   private String JavaDoc m_genericsSignature;
69
70   /**
71    * The modifiers.
72    */

73   private int m_modifiers;
74
75   /**
76    * Is the class an interface.
77    */

78   private boolean m_isInterface = false;
79
80   /**
81    * Is the class a primitive type.
82    */

83   private boolean m_isPrimitive = false;
84
85   /**
86    * Is the class of type array.
87    */

88   private boolean m_isArray = false;
89
90   /**
91    * Flag for the static initializer method.
92    */

93   private boolean m_hasStaticInitializer = false;
94
95   /**
96    * Lazy instance that represents the static initializer if present, else null
97    */

98   private StaticInitializationInfo m_staticInitializer = null;
99
100   /**
101    * A list with the <code>ConstructorInfo</code> instances.
102    * When visiting the bytecode, we keep track of the order of the visit.
103    * The first time the getConstructors() gets called, we build an array and then reuse it directly.
104    */

105   private final HashMap JavaDoc m_constructors = new HashMap JavaDoc();
106   private ArrayList JavaDoc m_sortedConstructorHashes = new ArrayList JavaDoc();
107   private ConstructorInfo[] m_constructorsLazy = null;
108
109
110   /**
111    * A list with the <code>MethodInfo</code> instances.
112    * When visiting the bytecode, we keep track of the order of the visit.
113    * The first time the getMethods() gets called, we build an array and then reuse it directly.
114    */

115   private final HashMap JavaDoc m_methods = new HashMap JavaDoc();
116   private ArrayList JavaDoc m_sortedMethodHashes = new ArrayList JavaDoc();
117   private MethodInfo[] m_methodsLazy = null;
118
119   /**
120    * A list with the <code>FieldInfo</code> instances.
121    * When visiting the bytecode, we keep track of the order of the visit.
122    * The first time the getFields() gets called, we build an array and then reuse it directly.
123    */

124   private final HashMap JavaDoc m_fields = new HashMap JavaDoc();
125   private ArrayList JavaDoc m_sortedFieldHashes = new ArrayList JavaDoc();
126   private FieldInfo[] m_fieldsLazy = null;
127
128   /**
129    * A list with the interfaces class names.
130    */

131   private String JavaDoc[] m_interfaceClassNames = null;
132
133   /**
134    * A list with the interfaces.
135    */

136   private ClassInfo[] m_interfaces = null;
137
138   /**
139    * The super class name.
140    */

141   private String JavaDoc m_superClassName = null;
142
143   /**
144    * The super class.
145    */

146   private ClassInfo m_superClass = null;
147
148   /**
149    * The annotation reader.
150    * Lazily instantiated from backport.
151    */

152   private AnnotationReader m_annotationReader = null;
153
154   /**
155    * The component type name if array type. Can be an array itself.
156    */

157   private String JavaDoc m_componentTypeName = null;
158
159   /**
160    * The component type if array type. Can be an array itself.
161    */

162   private ClassInfo m_componentType = null;
163
164   /**
165    * The class info repository.
166    */

167   private final AsmClassInfoRepository m_classInfoRepository;
168
169   /**
170    * Creates a new ClassInfo instance.
171    *
172    * @param bytecode
173    * @param loader
174    */

175   AsmClassInfo(final byte[] bytecode, final ClassLoader JavaDoc loader) {
176     if (bytecode == null) {
177       throw new IllegalArgumentException JavaDoc("bytecode can not be null");
178     }
179     m_loaderRef = new WeakReference JavaDoc(loader);
180     m_classInfoRepository = AsmClassInfoRepository.getRepository(loader);
181     try {
182       ClassReader cr = new ClassReader(bytecode);
183       ClassInfoClassAdapter visitor = new ClassInfoClassAdapter();
184       cr.accept(visitor, false);
185     } catch (Throwable JavaDoc t) {
186       t.printStackTrace();
187     }
188     m_classInfoRepository.addClassInfo(this);
189   }
190
191   /**
192    * Creates a new ClassInfo instance.
193    *
194    * @param resourceStream
195    * @param loader
196    */

197   AsmClassInfo(final InputStream JavaDoc resourceStream, final ClassLoader JavaDoc loader) {
198     if (resourceStream == null) {
199       throw new IllegalArgumentException JavaDoc("resource stream can not be null");
200     }
201     m_loaderRef = new WeakReference JavaDoc(loader);
202     m_classInfoRepository = AsmClassInfoRepository.getRepository(loader);
203     try {
204       ClassReader cr = new ClassReader(resourceStream);
205       ClassInfoClassAdapter visitor = new ClassInfoClassAdapter();
206       cr.accept(visitor, false);
207     } catch (Throwable JavaDoc t) {
208       t.printStackTrace();
209     }
210     m_classInfoRepository.addClassInfo(this);
211   }
212
213   /**
214    * Create a ClassInfo based on a component type and a given dimension Due to java.lang.reflect. behavior, the
215    * ClassInfo is almost empty. It is not an interface, only subclass of java.lang.Object, no methods, fields, or
216    * constructor, no annotation.
217    *
218    * @param className
219    * @param loader
220    * @param componentInfo
221    */

222   AsmClassInfo(final String JavaDoc className,
223                final ClassLoader JavaDoc loader,
224                final ClassInfo componentInfo) {
225     m_loaderRef = new WeakReference JavaDoc(loader);
226     m_name = className.replace('/', '.');
227     m_classInfoRepository = AsmClassInfoRepository.getRepository(loader);
228     m_isArray = true;
229     m_componentType = componentInfo;
230     m_componentTypeName = componentInfo.getName();
231     m_modifiers = componentInfo.getModifiers() | Modifier.ABSTRACT | Modifier.FINAL;
232     m_isInterface = false;//as in java.reflect
233
m_superClass = JavaClassInfo.getClassInfo(Object JavaDoc.class);
234     m_superClassName = m_superClass.getName();
235     m_interfaceClassNames = new String JavaDoc[0];
236     m_interfaces = new ClassInfo[0];
237     m_signature = AsmHelper.getClassDescriptor(this);
238     m_classInfoRepository.addClassInfo(this);
239   }
240
241   /**
242    * Returns a completely new class info for a specific class. Does not cache.
243    *
244    * @param bytecode
245    * @param loader
246    * @return the class info
247    */

248   public static ClassInfo newClassInfo(final byte[] bytecode, final ClassLoader JavaDoc loader) {
249     final String JavaDoc className = AsmClassInfo.retrieveClassNameFromBytecode(bytecode);
250     AsmClassInfoRepository repository = AsmClassInfoRepository.getRepository(loader);
251     repository.removeClassInfo(className);
252     return new AsmClassInfo(bytecode, loader);
253   }
254
255   /**
256    * Returns the class info for a specific class.
257    *
258    * @param className
259    * @param loader
260    * @return the class info
261    */

262   public static ClassInfo getClassInfo(final String JavaDoc className, final ClassLoader JavaDoc loader) {
263     final String JavaDoc javaClassName = getJavaClassName(className);
264     AsmClassInfoRepository repository = AsmClassInfoRepository.getRepository(loader);
265     ClassInfo classInfo = repository.getClassInfo(javaClassName);
266     if (classInfo == null) {
267       classInfo = createClassInfoFromStream(javaClassName, loader);
268     }
269     return classInfo;
270   }
271
272   /**
273    * Returns the class info for a specific class.
274    *
275    * @param bytecode
276    * @param loader
277    * @return the class info
278    */

279   public static ClassInfo getClassInfo(final byte[] bytecode, final ClassLoader JavaDoc loader) {
280     final String JavaDoc className = AsmClassInfo.retrieveClassNameFromBytecode(bytecode);
281     AsmClassInfoRepository repository = AsmClassInfoRepository.getRepository(loader);
282     ClassInfo classInfo = repository.getClassInfo(className);
283     if (classInfo == null) {
284       classInfo = new AsmClassInfo(bytecode, loader);
285     }
286     return classInfo;
287   }
288
289   /**
290    * Returns the class info for a specific class.
291    *
292    * @param className
293    * @param bytecode
294    * @param loader
295    * @return the class info
296    */

297   public static ClassInfo getClassInfo(final String JavaDoc className, final byte[] bytecode, final ClassLoader JavaDoc loader) {
298     AsmClassInfoRepository repository = AsmClassInfoRepository.getRepository(loader);
299     ClassInfo classInfo = repository.getClassInfo(className.replace('.', '/'));
300     if (classInfo == null) {
301       classInfo = new AsmClassInfo(bytecode, loader);
302     }
303     return classInfo;
304   }
305
306   /**
307    * Returns the class info for a specific class.
308    *
309    * @param stream
310    * @param loader
311    * @return the class info
312    */

313   public static ClassInfo getClassInfo(final String JavaDoc name, final InputStream JavaDoc stream, final ClassLoader JavaDoc loader) {
314     try {
315       ClassReader cr = new ClassReader(stream);
316       // keep a copy of the bytecode, since me way want to "reuse the stream"
317
byte[] bytes = cr.b;
318       ClassNameRetrievalClassAdapter visitor = new ClassNameRetrievalClassAdapter();
319       cr.accept(visitor, true);
320       final String JavaDoc className = visitor.getClassName();
321       AsmClassInfoRepository repository = AsmClassInfoRepository.getRepository(loader);
322       ClassInfo classInfo = repository.getClassInfo(className);
323       if (classInfo == null) {
324         classInfo = new AsmClassInfo(bytes, loader);
325       }
326       return classInfo;
327     } catch (IOException JavaDoc e) {
328       throw new WrappedRuntimeException("Can't get ClassInfo for "+name, e);
329     }
330   }
331
332   /**
333    * Marks the class as dirty (since it has been modified and needs to be rebuild).
334    *
335    * @param className
336    */

337   public static void markDirty(final String JavaDoc className, final ClassLoader JavaDoc loader) {
338     AsmClassInfoRepository.getRepository(loader).removeClassInfo(className);
339   }
340
341   /**
342    * Retrieves the class name from the bytecode of a class.
343    *
344    * @param bytecode
345    * @return the class name
346    */

347   public static String JavaDoc retrieveClassNameFromBytecode(final byte[] bytecode) {
348     ClassReader cr = new ClassReader(bytecode);
349     ClassNameRetrievalClassAdapter visitor = new ClassNameRetrievalClassAdapter();
350     cr.accept(visitor, true);
351     return visitor.getClassName();
352   }
353
354   /**
355    * Checks if the class is a of a primitive type, if so create and return the class for the type else return null.
356    *
357    * @param className
358    * @return the class for the primitive type or null
359    */

360   public static Class JavaDoc getPrimitiveClass(final String JavaDoc className) {
361     if (className.equals("void")) {
362       return void.class;
363     } else if (className.equals("long")) {
364       return long.class;
365     } else if (className.equals("int")) {
366       return int.class;
367     } else if (className.equals("short")) {
368       return short.class;
369     } else if (className.equals("double")) {
370       return double.class;
371     } else if (className.equals("float")) {
372       return float.class;
373     } else if (className.equals("byte")) {
374       return byte.class;
375     } else if (className.equals("boolean")) {
376       return boolean.class;
377     } else if (className.equals("char")) {
378       return char.class;
379     } else {
380       return null;
381     }
382   }
383
384   /**
385    * Returns the annotations.
386    *
387    * @return the annotations
388    */

389   public AnnotationElement.Annotation[] getAnnotations() {
390     return getAnnotationReader().getAnnotationElements();
391   }
392
393   /**
394    * Returns the name of the class.
395    *
396    * @return the name of the class
397    */

398   public String JavaDoc getName() {
399     return m_name;
400   }
401
402   /**
403    * Returns the signature for the class.
404    *
405    * @return the signature for the class
406    */

407   public String JavaDoc getSignature() {
408     return m_signature;
409   }
410
411   /**
412    * Returns the internal generics signature for the element.
413    *
414    * @return the internal generics signature for the element
415    */

416   public String JavaDoc getGenericsSignature() {
417     return m_genericsSignature;
418   }
419
420   /**
421    * Returns the class modifiers.
422    *
423    * @return the class modifiers
424    */

425   public int getModifiers() {
426     return m_modifiers;
427   }
428
429   /**
430    * Returns the class loader that loaded this class.
431    *
432    * @return the class loader
433    */

434   public ClassLoader JavaDoc getClassLoader() {
435     return (ClassLoader JavaDoc) m_loaderRef.get();
436   }
437
438   /**
439    * Checks if the class has a static initalizer.
440    *
441    * @return
442    */

443   public boolean hasStaticInitializer() {
444     return m_hasStaticInitializer;
445   }
446
447   /**
448    * Return the static initializer info or null if not present
449    *
450    * @see org.codehaus.aspectwerkz.reflect.ClassInfo#staticInitializer()
451    */

452   public StaticInitializationInfo staticInitializer() {
453     if (hasStaticInitializer() && m_staticInitializer == null) {
454       m_staticInitializer = new StaticInitializationInfoImpl(this);
455     }
456     return m_staticInitializer;
457   }
458
459   /**
460    * Returns a constructor info by its hash.
461    *
462    * @param hash
463    * @return
464    */

465   public ConstructorInfo getConstructor(final int hash) {
466     ConstructorInfo constructor = (ConstructorInfo) m_constructors.get(new Integer JavaDoc(hash));
467     if (constructor == null && getSuperclass() != null) {
468       constructor = getSuperclass().getConstructor(hash);
469     }
470     return constructor;
471   }
472
473   /**
474    * Returns a list with all the constructors info.
475    *
476    * @return the constructors info
477    */

478   public synchronized ConstructorInfo[] getConstructors() {
479     if (m_constructorsLazy == null) {
480       ConstructorInfo[] constructorInfos = new ConstructorInfo[m_sortedConstructorHashes.size()];
481       for (int i = 0; i < m_sortedConstructorHashes.size(); i++) {
482         constructorInfos[i] = (ConstructorInfo) m_constructors.get(m_sortedConstructorHashes.get(i));
483       }
484       m_constructorsLazy = constructorInfos;
485     }
486     return m_constructorsLazy;
487   }
488
489   /**
490    * Returns a method info by its hash.
491    *
492    * @param hash
493    * @return
494    */

495   public MethodInfo getMethod(final int hash) {
496     MethodInfo method = (MethodInfo) m_methods.get(new Integer JavaDoc(hash));
497     if (method == null) {
498       for (int i = 0; i < getInterfaces().length; i++) {
499         method = getInterfaces()[i].getMethod(hash);
500         if (method != null) {
501           break;
502         }
503       }
504     }
505     if (method == null && getSuperclass() != null) {
506       method = getSuperclass().getMethod(hash);
507     }
508     return method;
509   }
510
511   /**
512    * Returns a list with all the methods info.
513    *
514    * @return the methods info
515    */

516   public synchronized MethodInfo[] getMethods() {
517     if (m_methodsLazy == null) {
518       MethodInfo[] methodInfos = new MethodInfo[m_sortedMethodHashes.size()];
519       for (int i = 0; i < m_sortedMethodHashes.size(); i++) {
520         methodInfos[i] = (MethodInfo) m_methods.get(m_sortedMethodHashes.get(i));
521       }
522       m_methodsLazy = methodInfos;
523     }
524     return m_methodsLazy;
525   }
526
527   /**
528    * Returns a field info by its hash.
529    *
530    * @param hash
531    * @return
532    */

533   public FieldInfo getField(final int hash) {
534     FieldInfo field = (FieldInfo) m_fields.get(new Integer JavaDoc(hash));
535     if (field == null && getSuperclass() != null) {
536       field = getSuperclass().getField(hash);
537     }
538     if (field == null) {
539       // Trying to find constants in Interfaces
540
ClassInfo[] interfaces = getInterfaces();
541       for (int i = 0; i < interfaces.length; i++) {
542         ClassInfo ifc = interfaces[i];
543         field = ifc.getField(hash);
544         if (field != null)
545           break;
546       }
547     }
548     return field;
549   }
550
551   /**
552    * Returns a list with all the field info.
553    *
554    * @return the field info
555    */

556   public FieldInfo[] getFields() {
557     if (m_fieldsLazy == null) {
558       FieldInfo[] fieldInfos = new FieldInfo[m_sortedFieldHashes.size()];
559       for (int i = 0; i < m_sortedFieldHashes.size(); i++) {
560         fieldInfos[i] = (FieldInfo) m_fields.get(m_sortedFieldHashes.get(i));
561       }
562       m_fieldsLazy = fieldInfos;
563     }
564     return m_fieldsLazy;
565   }
566
567   /**
568    * Returns the interfaces.
569    *
570    * @return the interfaces
571    */

572   public synchronized ClassInfo[] getInterfaces() {
573     if (m_interfaces == null) {
574       m_interfaces = new ClassInfo[m_interfaceClassNames.length];
575       for (int i = 0; i < m_interfaceClassNames.length; i++) {
576         m_interfaces[i] = AsmClassInfo.getClassInfo(m_interfaceClassNames[i], (ClassLoader JavaDoc) m_loaderRef.get());
577       }
578     }
579     return m_interfaces;
580   }
581
582   /**
583    * Returns the super class.
584    *
585    * @return the super class
586    */

587   public ClassInfo getSuperclass() {
588     if (m_superClass == null && m_superClassName != null) {
589       m_superClass = AsmClassInfo.getClassInfo(m_superClassName, (ClassLoader JavaDoc) m_loaderRef.get());
590     }
591     return m_superClass;
592   }
593
594   /**
595    * Returns the component type if array type else null.
596    *
597    * @return the component type
598    */

599   public ClassInfo getComponentType() {
600     if (isArray() && (m_componentTypeName == null)) {
601       m_componentType = AsmClassInfo.getClassInfo(m_componentTypeName, (ClassLoader JavaDoc) m_loaderRef.get());
602     }
603     return m_componentType;
604   }
605
606   /**
607    * Is the class an interface.
608    *
609    * @return
610    */

611   public boolean isInterface() {
612     return m_isInterface;
613   }
614
615   /**
616    * Is the class a primitive type.
617    *
618    * @return
619    */

620   public boolean isPrimitive() {
621     return m_isPrimitive;
622   }
623
624   /**
625    * Is the class an array type.
626    *
627    * @return
628    */

629   public boolean isArray() {
630     return m_isArray;
631   }
632
633   /**
634    * @see java.lang.Object#equals(java.lang.Object)
635    */

636   public boolean equals(Object JavaDoc o) {
637     if (this == o) {
638       return true;
639     }
640     if (!(o instanceof ClassInfo)) {
641       return false;
642     }
643     ClassInfo classInfo = (ClassInfo) o;
644     return m_name.equals(classInfo.getName());
645   }
646
647   /**
648    * @see java.lang.Object#hashCode()
649    */

650   public int hashCode() {
651     return m_name.hashCode();
652   }
653
654   public String JavaDoc toString() {
655     return m_name;
656   }
657
658   /**
659    * Create a ClassInfo based on a component type which can be himself an array
660    *
661    * @param className
662    * @param loader
663    * @param componentClassInfo
664    * @return
665    */

666   public static ClassInfo getArrayClassInfo(final String JavaDoc className,
667                                             final ClassLoader JavaDoc loader,
668                                             final ClassInfo componentClassInfo) {
669     return new AsmClassInfo(className, loader, componentClassInfo);
670   }
671
672   /**
673    * Creates a ClassInfo based on the stream retrieved from the class loader through
674    * <code>getResourceAsStream</code>.
675    *
676    * @param name java name as in source code
677    * @param loader
678    */

679   private static ClassInfo createClassInfoFromStream(final String JavaDoc name,
680                                                      final ClassLoader JavaDoc loader) {
681     final String JavaDoc className = name.replace('.', '/');
682
683     // to handle primitive type we need to know the array dimension
684
if (name.indexOf('/') < 0) {
685       // it might be one
686
// gets its non array component type and the dimension
687
int dimension = 0;
688       for (int i = className.indexOf('['); i > 0; i = className.indexOf('[', i + 1)) {
689         dimension++;
690       }
691       String JavaDoc unidimComponentName = className;
692       if (dimension > 0) {
693         int unidimComponentTypeIndex = className.indexOf('[');
694         unidimComponentName = className.substring(0, unidimComponentTypeIndex);
695       }
696       Class JavaDoc primitiveClass = AsmClassInfo.getPrimitiveClass(unidimComponentName);
697       if (primitiveClass != null && primitiveClass.isPrimitive()) {
698         if (dimension == 0) {
699           return JavaClassInfo.getClassInfo(primitiveClass);
700         } else {
701           Class JavaDoc arrayClass = Array.newInstance(primitiveClass, new int[dimension]).getClass();
702           return JavaClassInfo.getClassInfo(arrayClass);
703         }
704       }
705     }
706
707     // for non primitive, we need to chain component type ala java.lang.reflect
708
// to support multi. dim. arrays
709
int componentTypeIndex = className.lastIndexOf('[');
710     String JavaDoc componentName = className;
711     boolean isArray = false;
712     if (componentTypeIndex > 0) {
713       componentName = className.substring(0, componentTypeIndex);
714       isArray = true;
715     }
716
717     ClassInfo componentInfo = null;
718
719     // is component yet another array ie this name is a multi dim array ?
720
if (componentName.indexOf('[') > 0) {
721       componentInfo = getClassInfo(componentName, loader);
722     } else {
723       InputStream JavaDoc componentClassAsStream = null;
724       if (loader != null) {
725         componentClassAsStream = loader.getResourceAsStream(componentName + ".class");
726       } else {
727         // boot class loader, fall back to system classloader that will see it anyway
728
componentClassAsStream = ClassLoader.getSystemClassLoader().getResourceAsStream(
729                 componentName + ".class");
730       }
731       if (componentClassAsStream == null) {
732         // might be more than one dimension
733
if (componentName.indexOf('[') > 0) {
734           return getClassInfo(componentName, loader);
735         }
736         System.out.println(
737                 "AW::WARNING - could not load class ["
738                         + componentName
739                         + "] as a resource in loader ["
740                         + loader
741                         + "]"
742         );
743         componentInfo = new ClassInfo.NullClassInfo();
744       }
745       try {
746         componentInfo = AsmClassInfo.getClassInfo(componentName, componentClassAsStream, loader);
747       } finally {
748         try {
749           componentClassAsStream.close();
750         } catch (Exception JavaDoc e) {
751           // ignore
752
}
753       }
754     }
755
756     if (!isArray) {
757       return componentInfo;
758     } else {
759       return AsmClassInfo.getArrayClassInfo(className, loader, componentInfo);
760     }
761   }
762
763 // /**
764
// * Creates a string with the annotation key value pairs.
765
// *
766
// * @param annotation
767
// * @return the string
768
// */
769
// private static String createAnnotationKeyValueString(final Annotation annotation) {
770
// List elementValues = annotation.elementValues;
771
// StringBuffer annotationValues = new StringBuffer();
772
// if (elementValues.size() != 0) {
773
// int i = 0;
774
// for (Iterator iterator = elementValues.iterator(); iterator.hasNext();) {
775
// Object[] keyValuePair = (Object[]) iterator.next();
776
// annotationValues.append((String) keyValuePair[0]);
777
// annotationValues.append('=');
778
// annotationValues.append(keyValuePair[1].toString());
779
// if (i < elementValues.size() - 1) {
780
// annotationValues.append(',');
781
// }
782
// }
783
// }
784
// return annotationValues.toString();
785
// }
786

787   /**
788    * ASM bytecode visitor that retrieves the class name from the bytecode.
789    *
790    * @author <a HREF="mailto:jboner@codehaus.org">Jonas BonŽr </a>
791    */

792   public static class ClassNameRetrievalClassAdapter extends AsmNullAdapter.NullClassAdapter {
793
794     private String JavaDoc m_className;
795
796     public void visit(final int version,
797                       final int access,
798                       final String JavaDoc name,
799                       final String JavaDoc desc,
800                       final String JavaDoc superName,
801                       final String JavaDoc[] interfaces) {
802       m_className = name.replace('/', '.');
803     }
804
805     public String JavaDoc getClassName() {
806       return m_className;
807     }
808   }
809
810   /**
811    * ASM bytecode visitor that gathers info about the class.
812    *
813    * @author <a HREF="mailto:jboner@codehaus.org">Jonas BonŽr </a>
814    */

815   private class ClassInfoClassAdapter extends AsmNullAdapter.NullClassAdapter {
816
817     public void visit(final int version,
818                       final int access,
819                       final String JavaDoc name,
820                       final String JavaDoc signature,
821                       final String JavaDoc superName,
822                       final String JavaDoc[] interfaces) {
823
824       m_modifiers = access;
825       m_name = name.replace('/', '.');
826       m_genericsSignature = signature;
827       m_isInterface = Modifier.isInterface(m_modifiers);
828       // special case for java.lang.Object, which does not extend anything
829
m_superClassName = superName == null ? null : superName.replace('/', '.');
830       m_interfaceClassNames = new String JavaDoc[interfaces.length];
831       for (int i = 0; i < interfaces.length; i++) {
832         m_interfaceClassNames[i] = interfaces[i].replace('/', '.');
833       }
834       // FIXME this algo for array types does most likely NOT WORK (since
835
// I assume that ASM is handling arrays
836
// using the internal desriptor format '[L' and the algo is using '[]')
837
if (m_name.endsWith("[]")) {
838         m_isArray = true;
839         int index = m_name.indexOf('[');
840         m_componentTypeName = m_name.substring(0, index);
841       } else if (m_name.equals("long")
842               || m_name.equals("int")
843               || m_name.equals("short")
844               || m_name.equals("double")
845               || m_name.equals("float")
846               || m_name.equals("byte")
847               || m_name.equals("boolean")
848               || m_name.equals("char")) {
849         m_isPrimitive = true;
850       }
851     }
852
853     public FieldVisitor visitField(final int access,
854                                    final String JavaDoc name,
855                                    final String JavaDoc desc,
856                                    final String JavaDoc signature,
857                                    final Object JavaDoc value) {
858       final FieldStruct struct = new FieldStruct();
859       struct.modifiers = access;
860       struct.name = name;
861       struct.desc = desc;
862       struct.signature = signature;
863       struct.value = value;
864       AsmFieldInfo fieldInfo = new AsmFieldInfo(struct, m_name, (ClassLoader JavaDoc) m_loaderRef.get());
865       Integer JavaDoc hash = new Integer JavaDoc(AsmHelper.calculateFieldHash(name, desc));
866       m_fields.put(hash, fieldInfo);
867       m_sortedFieldHashes.add(hash);
868       return AsmNullAdapter.NullFieldAdapter.NULL_FIELD_ADAPTER;
869     }
870
871     public MethodVisitor visitMethod(final int access,
872                                      final String JavaDoc name,
873                                      final String JavaDoc desc,
874                                      final String JavaDoc signature,
875                                      final String JavaDoc[] exceptions) {
876       final MethodStruct struct = new MethodStruct();
877       struct.modifiers = access;
878       struct.name = name;
879       struct.desc = desc;
880       struct.signature = signature;
881       struct.exceptions = exceptions;
882       Integer JavaDoc hash = new Integer JavaDoc(AsmHelper.calculateMethodHash(name, desc));
883       // the methodInfo that should be updated when we will visit the method parameter names info if needed.
884
AsmMethodInfo methodInfo = null;
885       if (name.equals(TransformationConstants.CLINIT_METHOD_NAME)) {
886         m_hasStaticInitializer = true;
887       } else {
888         AsmMemberInfo memberInfo = null;
889         if (name.equals(TransformationConstants.INIT_METHOD_NAME)) {
890           memberInfo = new AsmConstructorInfo(struct, m_name, (ClassLoader JavaDoc) m_loaderRef.get());
891           m_constructors.put(hash, memberInfo);
892           m_sortedConstructorHashes.add(hash);
893         } else {
894           memberInfo = new AsmMethodInfo(struct, m_name, (ClassLoader JavaDoc) m_loaderRef.get());
895           m_methods.put(hash, memberInfo);
896           m_sortedMethodHashes.add(hash);
897           methodInfo = (AsmMethodInfo) memberInfo;
898         }
899       }
900       if (methodInfo != null) {
901         // visit the method to access the parameter names as required to support Aspect with bindings
902
// TODO: should we make this optional - similar to m_lazyAttributes ?
903
Type[] parameterTypes = Type.getArgumentTypes(desc);
904         if (parameterTypes.length > 0) {
905           MethodVisitor methodParameterNamesVisitor = new MethodParameterNamesCodeAdapter(
906                   Modifier.isStatic(access),
907                   parameterTypes.length, methodInfo
908           );
909           return methodParameterNamesVisitor;
910         } else {
911           methodInfo.m_parameterNames = EMPTY_STRING_ARRAY;
912         }
913       }
914       return AsmNullAdapter.NullMethodAdapter.NULL_METHOD_ADAPTER;
915     }
916
917     public void visitEnd() {
918       m_signature = AsmHelper.getClassDescriptor(AsmClassInfo.this);
919     }
920   }
921
922   /**
923    * Extracts method parameter names as they appear in the source code from debug infos
924    *
925    * @author <a HREF="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
926    */

927   static class MethodParameterNamesCodeAdapter extends AsmNullAdapter.NullMethodAdapter {
928     private final boolean m_isStatic;
929     private final int m_parameterCount;
930     private AsmMethodInfo m_methodInfo;
931     private int m_signatureParameterRegisterDepth = 0;
932
933     public MethodParameterNamesCodeAdapter(boolean isStatic, int parameterCount, AsmMethodInfo methodInfo) {
934       m_isStatic = isStatic;
935       m_parameterCount = parameterCount;
936       m_methodInfo = methodInfo;
937       m_methodInfo.m_parameterNames = new String JavaDoc[m_parameterCount];
938
939       // compute the max index of the arguments that appear in the method signature
940
// including "this" on register 0 for non static methods
941
// a long or double needs 2 registers
942
if (!m_isStatic) {
943         m_signatureParameterRegisterDepth++;// index 0 = this
944
}
945       m_signatureParameterRegisterDepth += AsmHelper.getRegisterDepth(
946               Type.getArgumentTypes(m_methodInfo.m_member.desc)
947       );
948     }
949
950     /**
951      * Do not assume to visit the local variable with index always increasing since it is a wrong assumption
952      * [ see f.e. test.args.ArgsAspect.withArray advice ]
953      *
954      * @param name
955      * @param desc
956      * @param sig
957      * @param start
958      * @param end
959      * @param index the index of the argument on the stack
960      */

961     public void visitLocalVariable(String JavaDoc name, String JavaDoc desc, String JavaDoc sig, Label start, Label end, int index) {
962       if (index < m_signatureParameterRegisterDepth) {
963         // this is not a local variable
964
if (index == 0) {
965           if (!m_isStatic) {
966             //skip this
967
} else {
968             m_methodInfo.pushParameterNameFromRegister(index, name);
969           }
970         } else {
971           m_methodInfo.pushParameterNameFromRegister(index, name);
972         }
973       } else {
974         // skip code block locals
975
}
976     }
977   }
978
979   /**
980    * Converts the class name from VM type class name to Java type class name.
981    *
982    * @param className the VM type class name
983    * @return the Java type class name
984    */

985   private static String JavaDoc getJavaClassName(final String JavaDoc className) {
986     String JavaDoc javaClassName;
987     if (className.startsWith("[")) {
988       javaClassName = Type.getType(className).getClassName();
989     } else {
990       javaClassName = className.replace('/', '.');
991     }
992     return javaClassName;
993   }
994
995   /**
996    * Returns the annotation reader
997    *
998    * @return
999    */

1000  public AnnotationReader getAnnotationReader() {
1001    if (m_annotationReader == null) {
1002      ClassLoader JavaDoc loader = ContextClassLoader.getLoaderOrSystemLoader((ClassLoader JavaDoc) m_loaderRef.get());
1003      m_annotationReader = AnnotationReader.getReaderFor(m_name, loader);
1004    }
1005    return m_annotationReader;
1006  }
1007}
Popular Tags