KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > codehaus > aspectwerkz > reflect > impl > asm > AsmClassInfo


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.asm;
9
10 import gnu.trove.TIntObjectHashMap;
11 import gnu.trove.TIntArrayList;
12 import org.codehaus.aspectwerkz.annotation.instrumentation.asm.AsmAnnotationHelper;
13 import org.codehaus.aspectwerkz.annotation.AnnotationInfo;
14 import org.codehaus.aspectwerkz.exception.WrappedRuntimeException;
15 import org.codehaus.aspectwerkz.reflect.ClassInfo;
16 import org.codehaus.aspectwerkz.reflect.ConstructorInfo;
17 import org.codehaus.aspectwerkz.reflect.FieldInfo;
18 import org.codehaus.aspectwerkz.reflect.MethodInfo;
19 import org.codehaus.aspectwerkz.reflect.StaticInitializationInfo;
20 import org.codehaus.aspectwerkz.reflect.StaticInitializationInfoImpl;
21 import org.codehaus.aspectwerkz.reflect.impl.java.JavaClassInfo;
22 import org.codehaus.aspectwerkz.transform.inlining.AsmHelper;
23 import org.codehaus.aspectwerkz.transform.TransformationConstants;
24 import org.codehaus.aspectwerkz.proxy.ProxyCompiler;
25 import org.objectweb.asm.Attribute;
26 import org.objectweb.asm.ClassReader;
27 import org.objectweb.asm.CodeVisitor;
28 import org.objectweb.asm.Label;
29 import org.objectweb.asm.Type;
30 import org.objectweb.asm.attrs.Annotation;
31 import org.objectweb.asm.attrs.Attributes;
32
33 import java.io.IOException JavaDoc;
34 import java.io.InputStream JavaDoc;
35 import java.lang.ref.WeakReference JavaDoc;
36 import java.lang.reflect.Array JavaDoc;
37 import java.lang.reflect.Modifier JavaDoc;
38 import java.util.ArrayList JavaDoc;
39 import java.util.List JavaDoc;
40 import java.util.Iterator JavaDoc;
41
42 /**
43  * Implementation of the ClassInfo interface utilizing the ASM bytecode library for the info retriaval.
44  * <p/>
45  * Annotations are lazily gathered, unless required to visit them at the same time as we visit methods and fields.
46  * <p/>
47  * This implementation guarantees that the method, fields and constructors can be retrieved in the same order as they were in the bytecode
48  * (it can depends of the compiler and might not be the order of the source code - f.e. IBM compiler)
49  *
50  * @author <a HREF="mailto:jboner@codehaus.org">Jonas BonŽr </a>
51  * @author <a HREF="mailto:alex@gnilux.com">Alexandre Vasseur </a>
52  */

53 public class AsmClassInfo implements ClassInfo {
54
55     protected final static String JavaDoc[] EMPTY_STRING_ARRAY = new String JavaDoc[0];
56
57     protected final static List EMPTY_LIST = new ArrayList();
58
59     private final static Attribute[] NO_ATTRIBUTES = new Attribute[0];
60
61     /**
62      * The class loader wrapped in a weak ref.
63      */

64     private final WeakReference JavaDoc m_loaderRef;
65
66     /**
67      * The name of the class (with dots and not slashes)
68      */

69     private String JavaDoc m_name;
70
71     /**
72      * The signature of the class.
73      */

74     private String JavaDoc m_signature;
75
76     /**
77      * The modifiers.
78      */

79     private int m_modifiers;
80
81     /**
82      * Is the class an interface.
83      */

84     private boolean m_isInterface = false;
85
86     /**
87      * Is the class a primitive type.
88      */

89     private boolean m_isPrimitive = false;
90
91     /**
92      * Is the class of type array.
93      */

94     private boolean m_isArray = false;
95
96     /**
97      * Flag for the static initializer method.
98      */

99     private boolean m_hasStaticInitializer = false;
100
101     /**
102      * Lazy instance that represents the static initializer if present, else null
103      */

104     private StaticInitializationInfo m_staticInitializer = null;
105
106     /**
107      * A list with the <code>ConstructorInfo</code> instances.
108      * When visiting the bytecode, we keep track of the order of the visit.
109      * The first time the getConstructors() gets called, we build an array and then reuse it directly.
110      */

111     private final TIntObjectHashMap m_constructors = new TIntObjectHashMap();
112     private TIntArrayList m_sortedConstructorHashes = new TIntArrayList();
113     private ConstructorInfo[] m_constructorsLazy = null;
114
115
116     /**
117      * A list with the <code>MethodInfo</code> instances.
118      * When visiting the bytecode, we keep track of the order of the visit.
119      * The first time the getMethods() gets called, we build an array and then reuse it directly.
120      */

121     private final TIntObjectHashMap m_methods = new TIntObjectHashMap();
122     private TIntArrayList m_sortedMethodHashes = new TIntArrayList();
123     private MethodInfo[] m_methodsLazy = null;
124
125     /**
126      * A list with the <code>FieldInfo</code> instances.
127      * When visiting the bytecode, we keep track of the order of the visit.
128      * The first time the getFields() gets called, we build an array and then reuse it directly.
129      */

130     private final TIntObjectHashMap m_fields = new TIntObjectHashMap();
131     private TIntArrayList m_sortedFieldHashes = new TIntArrayList();
132     private FieldInfo[] m_fieldsLazy = null;
133
134     /**
135      * A list with the interfaces class names.
136      */

137     private String JavaDoc[] m_interfaceClassNames = null;
138
139     /**
140      * A list with the interfaces.
141      */

142     private ClassInfo[] m_interfaces = null;
143
144     /**
145      * The super class name.
146      */

147     private String JavaDoc m_superClassName = null;
148
149     /**
150      * The super class.
151      */

152     private ClassInfo m_superClass = null;
153
154     /**
155      * The annotations.
156      * Lazily populated.
157      */

158     private List m_annotations = null;
159
160     /**
161      * The component type name if array type. Can be an array itself.
162      */

163     private String JavaDoc m_componentTypeName = null;
164
165     /**
166      * The component type if array type. Can be an array itself.
167      */

168     private ClassInfo m_componentType = null;
169
170     /**
171      * The class info repository.
172      */

173     private final AsmClassInfoRepository m_classInfoRepository;
174
175     /**
176      * Creates a new ClassInfo instance.
177      *
178      * @param bytecode
179      * @param loader
180      */

181     AsmClassInfo(final byte[] bytecode, final ClassLoader JavaDoc loader, boolean lazyAttributes) {
182         if (bytecode == null) {
183             throw new IllegalArgumentException JavaDoc("bytecode can not be null");
184         }
185         m_loaderRef = new WeakReference JavaDoc(loader);
186         m_classInfoRepository = AsmClassInfoRepository.getRepository(loader);
187         try {
188             ClassReader cr = new ClassReader(bytecode);
189             ClassInfoClassAdapter visitor = new ClassInfoClassAdapter(lazyAttributes);
190             cr.accept(visitor, lazyAttributes ? NO_ATTRIBUTES : Attributes.getDefaultAttributes(), false);
191         } catch (Throwable JavaDoc t) {
192             t.printStackTrace();
193         }
194         m_classInfoRepository.addClassInfo(this);
195     }
196
197     /**
198      * Creates a new ClassInfo instance.
199      *
200      * @param resourceStream
201      * @param loader
202      */

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

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

254     public static ClassInfo newClassInfo(final byte[] bytecode, final ClassLoader JavaDoc loader) {
255         final String JavaDoc className = AsmClassInfo.retrieveClassNameFromBytecode(bytecode);
256         AsmClassInfoRepository repository = AsmClassInfoRepository.getRepository(loader);
257         repository.removeClassInfo(className);
258         return new AsmClassInfo(bytecode, loader, true);
259     }
260
261     /**
262      * Returns the class info for a specific class.
263      *
264      * @param className
265      * @param loader
266      * @return the class info
267      */

268     public static ClassInfo getClassInfo(final String JavaDoc className, final ClassLoader JavaDoc loader) {
269         final String JavaDoc javaClassName = getJavaClassName(className);
270         AsmClassInfoRepository repository = AsmClassInfoRepository.getRepository(loader);
271         ClassInfo classInfo = repository.getClassInfo(javaClassName);
272         if (classInfo == null) {
273             classInfo = createClassInfoFromStream(javaClassName, loader, true);
274         }
275         return classInfo;
276     }
277
278     /**
279      * Returns the class info for a specific class.
280      *
281      * @param bytecode
282      * @param loader
283      * @return the class info
284      */

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

302     public static ClassInfo getClassInfo(final InputStream JavaDoc stream, final ClassLoader JavaDoc loader) {
303         try {
304             ClassReader cr = new ClassReader(stream);
305             // keep a copy of the bytecode, since me way want to "reuse the stream"
306
byte[] bytes = cr.b;
307             ClassNameRetrievalClassAdapter visitor = new ClassNameRetrievalClassAdapter();
308             cr.accept(visitor, NO_ATTRIBUTES, true);
309             final String JavaDoc className = visitor.getClassName();
310             AsmClassInfoRepository repository = AsmClassInfoRepository.getRepository(loader);
311             ClassInfo classInfo = repository.getClassInfo(className);
312             if (classInfo == null) {
313                 classInfo = new AsmClassInfo(bytes, loader, true);
314             }
315             return classInfo;
316         } catch (IOException JavaDoc e) {
317             throw new WrappedRuntimeException(e);
318         }
319     }
320
321     /**
322      * Returns the class info for a specific class.
323      *
324      * @param stream
325      * @param loader
326      * @param lazyAttributes
327      * @return the class info
328      */

329     public static ClassInfo getClassInfo(final InputStream JavaDoc stream, final ClassLoader JavaDoc loader, boolean lazyAttributes) {
330         if (lazyAttributes) {
331             return getClassInfo(stream, loader);
332         }
333         try {
334             ClassReader cr = new ClassReader(stream);
335             // keep a copy of the bytecode, since me way want to "reuse the stream"
336
byte[] bytes = cr.b;
337             ClassNameRetrievalClassAdapter visitor = new ClassNameRetrievalClassAdapter();
338             cr.accept(visitor, NO_ATTRIBUTES, true);
339             String JavaDoc className = visitor.getClassName();
340             AsmClassInfoRepository repository = AsmClassInfoRepository.getRepository(loader);
341             ClassInfo classInfo = repository.getClassInfo(className);
342             if (classInfo == null) {
343                 classInfo = new AsmClassInfo(bytes, loader, lazyAttributes);
344             }
345             return classInfo;
346         } catch (IOException JavaDoc e) {
347             throw new WrappedRuntimeException(e);
348         }
349     }
350
351     /**
352      * Marks the class as dirty (since it has been modified and needs to be rebuild).
353      *
354      * @param className
355      */

356     public static void markDirty(final String JavaDoc className, final ClassLoader JavaDoc loader) {
357         AsmClassInfoRepository.getRepository(loader).removeClassInfo(className);
358     }
359
360     /**
361      * Retrieves the class name from the bytecode of a class.
362      *
363      * @param bytecode
364      * @return the class name
365      */

366     public static String JavaDoc retrieveClassNameFromBytecode(final byte[] bytecode) {
367         ClassReader cr = new ClassReader(bytecode);
368         ClassNameRetrievalClassAdapter visitor = new ClassNameRetrievalClassAdapter();
369         cr.accept(visitor, NO_ATTRIBUTES, true);
370         return visitor.getClassName();
371     }
372
373     /**
374      * Checks if the class is a of a primitive type, if so create and return the class for the type else return null.
375      *
376      * @param className
377      * @return the class for the primitive type or null
378      */

379     public static Class JavaDoc getPrimitiveClass(final String JavaDoc className) {
380         if (className.equals("void")) {
381             return void.class;
382         } else if (className.equals("long")) {
383             return long.class;
384         } else if (className.equals("int")) {
385             return int.class;
386         } else if (className.equals("short")) {
387             return short.class;
388         } else if (className.equals("double")) {
389             return double.class;
390         } else if (className.equals("float")) {
391             return float.class;
392         } else if (className.equals("byte")) {
393             return byte.class;
394         } else if (className.equals("boolean")) {
395             return boolean.class;
396         } else if (className.equals("char")) {
397             return char.class;
398         } else {
399             return null;
400         }
401     }
402
403     /**
404      * Returns the annotations infos.
405      *
406      * @return the annotations infos
407      */

408     public List getAnnotations() {
409         if (m_annotations == null) {
410             if (isPrimitive() || isArray()) {
411                 m_annotations = EMPTY_LIST;
412             } else {
413                 try {
414                     InputStream JavaDoc in = null;
415                     ClassReader cr = null;
416                     try {
417                         if ((ClassLoader JavaDoc) m_loaderRef.get() != null) {
418                             in =
419                             ((ClassLoader JavaDoc) m_loaderRef.get()).getResourceAsStream(m_name.replace('.', '/') + ".class");
420                         } else {
421                             in = ClassLoader.getSystemClassLoader().getResourceAsStream(m_name.replace('.', '/') + ".class");
422                         }
423                         if (in == null) {
424                             in = ProxyCompiler.getProxyResourceAsStream((ClassLoader JavaDoc) m_loaderRef.get(), m_name);
425                         }
426                         cr = new ClassReader(in);
427                     } finally {
428                         try {
429                             in.close();
430                         } catch (Exception JavaDoc e) {
431                             ;
432                         }
433                     }
434                     List annotations = new ArrayList();
435                     cr.accept(
436                             new AsmAnnotationHelper.ClassAnnotationExtractor(
437                                     annotations, (ClassLoader JavaDoc) m_loaderRef.get()
438                             ),
439                             Attributes.getDefaultAttributes(),
440                             true
441                     );
442                     m_annotations = annotations;
443                 } catch (IOException JavaDoc e) {
444                     // unlikely to occur since ClassInfo relies on getResourceAsStream
445
System.err.println(
446                             "AW::WARNING could not load " + m_name + " as a resource to retrieve annotations"
447                     );
448                     m_annotations = EMPTY_LIST;
449                 }
450             }
451         }
452         return m_annotations;
453     }
454
455     /**
456      * Returns the name of the class.
457      *
458      * @return the name of the class
459      */

460     public String JavaDoc getName() {
461         return m_name;
462     }
463
464     /**
465      * Returns the signature for the class.
466      *
467      * @return the signature for the class
468      */

469     public String JavaDoc getSignature() {
470         return m_signature;
471     }
472
473     /**
474      * Returns the class modifiers.
475      *
476      * @return the class modifiers
477      */

478     public int getModifiers() {
479         return m_modifiers;
480     }
481
482     /**
483      * Returns the class loader that loaded this class.
484      *
485      * @return the class loader
486      */

487     public ClassLoader JavaDoc getClassLoader() {
488         return (ClassLoader JavaDoc) m_loaderRef.get();
489     }
490
491     /**
492      * Checks if the class has a static initalizer.
493      *
494      * @return
495      */

496     public boolean hasStaticInitializer() {
497         return m_hasStaticInitializer;
498     }
499
500     /**
501      * Return the static initializer info or null if not present
502      *
503      * @see org.codehaus.aspectwerkz.reflect.ClassInfo#staticInitializer()
504      */

505     public StaticInitializationInfo staticInitializer() {
506         if(hasStaticInitializer() && m_staticInitializer == null) {
507             m_staticInitializer = new StaticInitializationInfoImpl(this);
508         }
509         return m_staticInitializer;
510     }
511
512     /**
513      * Returns a constructor info by its hash.
514      *
515      * @param hash
516      * @return
517      */

518     public ConstructorInfo getConstructor(final int hash) {
519         ConstructorInfo constructor = (ConstructorInfo) m_constructors.get(hash);
520         if (constructor == null && getSuperclass() != null) {
521             constructor = getSuperclass().getConstructor(hash);
522         }
523         return constructor;
524     }
525
526     /**
527      * Returns a list with all the constructors info.
528      *
529      * @return the constructors info
530      */

531     public ConstructorInfo[] getConstructors() {
532         if (m_constructorsLazy == null) {
533             ConstructorInfo[] constructorInfos = new ConstructorInfo[m_sortedConstructorHashes.size()];
534             for (int i = 0; i < m_sortedConstructorHashes.size(); i++) {
535                 constructorInfos[i] = (ConstructorInfo) m_constructors.get(m_sortedConstructorHashes.get(i));
536             }
537             m_constructorsLazy = constructorInfos;
538         }
539         return m_constructorsLazy;
540     }
541
542     /**
543      * Returns a method info by its hash.
544      *
545      * @param hash
546      * @return
547      */

548     public MethodInfo getMethod(final int hash) {
549         MethodInfo method = (MethodInfo) m_methods.get(hash);
550         if (method == null) {
551             for (int i = 0; i < getInterfaces().length; i++) {
552                 method = getInterfaces()[i].getMethod(hash);
553                 if (method != null) {
554                     break;
555                 }
556             }
557         }
558         if (method == null && getSuperclass() != null) {
559             method = getSuperclass().getMethod(hash);
560         }
561         return method;
562     }
563
564     /**
565      * Returns a list with all the methods info.
566      *
567      * @return the methods info
568      */

569     public MethodInfo[] getMethods() {
570         if (m_methodsLazy == null) {
571             MethodInfo[] methodInfos = new MethodInfo[m_sortedMethodHashes.size()];
572             for (int i = 0; i < m_sortedMethodHashes.size(); i++) {
573                 methodInfos[i] = (MethodInfo) m_methods.get(m_sortedMethodHashes.get(i));
574             }
575             m_methodsLazy = methodInfos;
576         }
577         return m_methodsLazy;
578     }
579
580     /**
581      * Returns a field info by its hash.
582      *
583      * @param hash
584      * @return
585      */

586     public FieldInfo getField(final int hash) {
587         FieldInfo field = (FieldInfo) m_fields.get(hash);
588         if (field == null && getSuperclass() != null) {
589             field = getSuperclass().getField(hash);
590         }
591         return field;
592     }
593
594     /**
595      * Returns a list with all the field info.
596      *
597      * @return the field info
598      */

599     public FieldInfo[] getFields() {
600         if (m_fieldsLazy == null) {
601             FieldInfo[] fieldInfos = new FieldInfo[m_sortedFieldHashes.size()];
602             for (int i = 0; i < m_sortedFieldHashes.size(); i++) {
603                 fieldInfos[i] = (FieldInfo) m_fields.get(m_sortedFieldHashes.get(i));
604             }
605             m_fieldsLazy = fieldInfos;
606         }
607         return m_fieldsLazy;
608     }
609
610     /**
611      * Returns the interfaces.
612      *
613      * @return the interfaces
614      */

615     public ClassInfo[] getInterfaces() {
616         if (m_interfaces == null) {
617             m_interfaces = new ClassInfo[m_interfaceClassNames.length];
618             for (int i = 0; i < m_interfaceClassNames.length; i++) {
619                 m_interfaces[i] = AsmClassInfo.getClassInfo(m_interfaceClassNames[i], (ClassLoader JavaDoc) m_loaderRef.get());
620             }
621         }
622         return m_interfaces;
623     }
624
625     /**
626      * Returns the super class.
627      *
628      * @return the super class
629      */

630     public ClassInfo getSuperclass() {
631         if (m_superClass == null && m_superClassName != null) {
632             m_superClass = AsmClassInfo.getClassInfo(m_superClassName, (ClassLoader JavaDoc) m_loaderRef.get());
633         }
634         return m_superClass;
635     }
636
637     /**
638      * Returns the component type if array type else null.
639      *
640      * @return the component type
641      */

642     public ClassInfo getComponentType() {
643         if (isArray() && (m_componentTypeName == null)) {
644             m_componentType = AsmClassInfo.getClassInfo(m_componentTypeName, (ClassLoader JavaDoc) m_loaderRef.get());
645         }
646         return m_componentType;
647     }
648
649     /**
650      * Is the class an interface.
651      *
652      * @return
653      */

654     public boolean isInterface() {
655         return m_isInterface;
656     }
657
658     /**
659      * Is the class a primitive type.
660      *
661      * @return
662      */

663     public boolean isPrimitive() {
664         return m_isPrimitive;
665     }
666
667     /**
668      * Is the class an array type.
669      *
670      * @return
671      */

672     public boolean isArray() {
673         return m_isArray;
674     }
675
676     /**
677      * @see java.lang.Object#equals(java.lang.Object)
678      */

679     public boolean equals(Object JavaDoc o) {
680         if (this == o) {
681             return true;
682         }
683         if (!(o instanceof ClassInfo)) {
684             return false;
685         }
686         ClassInfo classInfo = (ClassInfo) o;
687         return m_name.equals(classInfo.getName());
688     }
689
690     /**
691      * @see java.lang.Object#hashCode()
692      */

693     public int hashCode() {
694         return m_name.hashCode();
695     }
696
697     public String JavaDoc toString() {
698         return m_name;
699     }
700
701     /**
702      * Create a ClassInfo based on a component type which can be himself an array
703      *
704      * @param className
705      * @param loader
706      * @param componentClassInfo
707      * @return
708      */

709     public static ClassInfo getArrayClassInfo(final String JavaDoc className,
710                                               final ClassLoader JavaDoc loader,
711                                               final ClassInfo componentClassInfo) {
712         return new AsmClassInfo(className, loader, componentClassInfo);
713     }
714
715     /**
716      * Creates a ClassInfo based on the stream retrieved from the class loader through
717      * <code>getResourceAsStream</code>.
718      *
719      * @param name java name as in source code
720      * @param loader
721      * @param lazyAttributes
722      */

723     private static ClassInfo createClassInfoFromStream(final String JavaDoc name,
724                                                        final ClassLoader JavaDoc loader,
725                                                        boolean lazyAttributes) {
726         final String JavaDoc className = name.replace('.', '/');
727
728         // to handle primitive type we need to know the array dimension
729
if (name.indexOf('/') < 0) {
730             // it might be one
731
// gets its non array component type and the dimension
732
int dimension = 0;
733             for (int i = className.indexOf('['); i > 0; i = className.indexOf('[', i+1)) {
734                 dimension++;
735             }
736             String JavaDoc unidimComponentName = className;
737             if (dimension > 0) {
738                 int unidimComponentTypeIndex = className.indexOf('[');
739                 unidimComponentName = className.substring(0, unidimComponentTypeIndex);
740             }
741             Class JavaDoc primitiveClass = AsmClassInfo.getPrimitiveClass(unidimComponentName);
742             if (primitiveClass != null && primitiveClass.isPrimitive()) {
743                 if (dimension == 0) {
744                     return JavaClassInfo.getClassInfo(primitiveClass);
745                 } else {
746                     Class JavaDoc arrayClass = Array.newInstance(primitiveClass, new int[dimension]).getClass();
747                     return JavaClassInfo.getClassInfo(arrayClass);
748                 }
749             }
750         }
751
752         // for non primitive, we need to chain component type ala java.lang.reflect
753
// to support multi. dim. arrays
754
int componentTypeIndex = className.lastIndexOf('[');
755         String JavaDoc componentName = className;
756         boolean isArray = false;
757         if (componentTypeIndex > 0) {
758             componentName = className.substring(0, componentTypeIndex);
759             isArray = true;
760         }
761
762         ClassInfo componentInfo = null;
763
764         // is component yet another array ie this name is a multi dim array ?
765
if (componentName.indexOf('[') > 0) {
766             componentInfo = getClassInfo(componentName, loader);
767         } else {
768             InputStream JavaDoc componentClassAsStream = null;
769             if (loader != null) {
770                 componentClassAsStream = loader.getResourceAsStream(componentName + ".class");
771             } else {
772                 // boot class loader, fall back to system classloader that will see it anyway
773
componentClassAsStream = ClassLoader.getSystemClassLoader().getResourceAsStream(componentName + ".class");
774             }
775             if (componentClassAsStream == null) {
776                 // might be more than one dimension
777
if (componentName.indexOf('[') > 0) {
778                     return getClassInfo(componentName, loader);
779                 }
780                 System.out.println(
781                         "AW::WARNING - could not load class ["
782                         + componentName
783                         + "] as a resource in loader ["
784                         + loader
785                         + "]"
786                 );
787                 componentInfo = new ClassInfo.NullClassInfo();
788             }
789             try {
790                 componentInfo = AsmClassInfo.getClassInfo(componentClassAsStream, loader, lazyAttributes);
791             } finally {
792                 try {
793                     componentClassAsStream.close();
794                 } catch (Exception JavaDoc e) {
795                     ;
796                 }
797             }
798         }
799
800         if (!isArray) {
801             return componentInfo;
802         } else {
803             return AsmClassInfo.getArrayClassInfo(className, loader, componentInfo);
804         }
805     }
806
807 // /**
808
// * Creates a string with the annotation key value pairs.
809
// *
810
// * @param annotation
811
// * @return the string
812
// */
813
// private static String createAnnotationKeyValueString(final Annotation annotation) {
814
// List elementValues = annotation.elementValues;
815
// StringBuffer annotationValues = new StringBuffer();
816
// if (elementValues.size() != 0) {
817
// int i = 0;
818
// for (Iterator iterator = elementValues.iterator(); iterator.hasNext();) {
819
// Object[] keyValuePair = (Object[]) iterator.next();
820
// annotationValues.append((String) keyValuePair[0]);
821
// annotationValues.append('=');
822
// annotationValues.append(keyValuePair[1].toString());
823
// if (i < elementValues.size() - 1) {
824
// annotationValues.append(',');
825
// }
826
// }
827
// }
828
// return annotationValues.toString();
829
// }
830

831     /**
832      * ASM bytecode visitor that retrieves the class name from the bytecode.
833      *
834      * @author <a HREF="mailto:jboner@codehaus.org">Jonas BonŽr </a>
835      */

836     public static class ClassNameRetrievalClassAdapter extends AsmAnnotationHelper.NullClassAdapter {
837
838         private String JavaDoc m_className;
839
840         public void visit(final int version,
841                           final int access,
842                           final String JavaDoc name,
843                           final String JavaDoc superName,
844                           final String JavaDoc[] interfaces,
845                           final String JavaDoc sourceFile) {
846             m_className = name.replace('/', '.');
847         }
848
849         public String JavaDoc getClassName() {
850             return m_className;
851         }
852     }
853
854     /**
855      * ASM bytecode visitor that gathers info about the class.
856      *
857      * @author <a HREF="mailto:jboner@codehaus.org">Jonas BonŽr </a>
858      */

859     private class ClassInfoClassAdapter extends AsmAnnotationHelper.NullClassAdapter {
860
861         public boolean m_lazyAttributes = true;
862
863         public ClassInfoClassAdapter(boolean lazyAttributes) {
864             m_lazyAttributes = lazyAttributes;
865         }
866
867         public void visit(final int version,
868                           final int access,
869                           final String JavaDoc name,
870                           final String JavaDoc superName,
871                           final String JavaDoc[] interfaces,
872                           final String JavaDoc sourceFile) {
873
874             m_name = name.replace('/', '.');
875             m_modifiers = access;
876             m_isInterface = Modifier.isInterface(m_modifiers);
877             // special case for java.lang.Object, which does not extend anything
878
m_superClassName = superName == null ? null : superName.replace('/', '.');
879             m_interfaceClassNames = new String JavaDoc[interfaces.length];
880             for (int i = 0; i < interfaces.length; i++) {
881                 m_interfaceClassNames[i] = interfaces[i].replace('/', '.');
882             }
883             // FIXME this algo for array types does most likely NOT WORK (since
884
// I assume that ASM is handling arrays
885
// using the internal desriptor format '[L' and the algo is using '[]')
886
if (m_name.endsWith("[]")) {
887                 m_isArray = true;
888                 int index = m_name.indexOf('[');
889                 m_componentTypeName = m_name.substring(0, index);
890             } else if (m_name.equals("long")
891                        || m_name.equals("int")
892                        || m_name.equals("short")
893                        || m_name.equals("double")
894                        || m_name.equals("float")
895                        || m_name.equals("byte")
896                        || m_name.equals("boolean")
897                        || m_name.equals("char")) {
898                 m_isPrimitive = true;
899             }
900         }
901
902         public void visitAttribute(final Attribute attribute) {
903             // attributes
904
if (!m_lazyAttributes) {
905                 List annotations = new ArrayList();
906                 annotations =
907                 AsmAnnotationHelper.extractAnnotations(annotations, attribute, (ClassLoader JavaDoc) m_loaderRef.get());
908                 m_annotations = annotations;
909             }
910         }
911
912         public void visitField(final int access,
913                                final String JavaDoc name,
914                                final String JavaDoc desc,
915                                final Object JavaDoc value,
916                                final Attribute attrs) {
917             final FieldStruct struct = new FieldStruct();
918             struct.modifiers = access;
919             struct.name = name;
920             struct.desc = desc;
921             struct.value = value;
922             AsmFieldInfo fieldInfo = new AsmFieldInfo(struct, m_name, (ClassLoader JavaDoc) m_loaderRef.get());
923             // attributes
924
if (!m_lazyAttributes) {
925                 List annotations = new ArrayList();
926                 annotations =
927                 AsmAnnotationHelper.extractAnnotations(annotations, attrs, (ClassLoader JavaDoc) m_loaderRef.get());
928                 fieldInfo.m_annotations = annotations;
929             }
930             int hash = AsmHelper.calculateFieldHash(name, desc);
931             m_fields.put(hash, fieldInfo);
932             m_sortedFieldHashes.add(hash);
933         }
934
935         public CodeVisitor visitMethod(final int access,
936                                        final String JavaDoc name,
937                                        final String JavaDoc desc,
938                                        final String JavaDoc[] exceptions,
939                                        final Attribute attrs) {
940             final MethodStruct struct = new MethodStruct();
941             struct.modifiers = access;
942             struct.name = name;
943             struct.desc = desc;
944             struct.exceptions = exceptions;
945             int hash = AsmHelper.calculateMethodHash(name, desc);
946             // the methodInfo that should be updated when we will visit the method parameter names info if needed.
947
AsmMethodInfo methodInfo = null;
948             if (name.equals(TransformationConstants.CLINIT_METHOD_NAME)) {
949                 m_hasStaticInitializer = true;
950             } else {
951                 AsmMemberInfo memberInfo = null;
952                 if (name.equals(TransformationConstants.INIT_METHOD_NAME)) {
953                     memberInfo = new AsmConstructorInfo(struct, m_name, (ClassLoader JavaDoc) m_loaderRef.get());
954                     m_constructors.put(hash, memberInfo);
955                     m_sortedConstructorHashes.add(hash);
956                 } else {
957                     memberInfo = new AsmMethodInfo(struct, m_name, (ClassLoader JavaDoc) m_loaderRef.get());
958                     m_methods.put(hash, memberInfo);
959                     m_sortedMethodHashes.add(hash);
960                     methodInfo = (AsmMethodInfo) memberInfo;
961                 }
962                 // attributes
963
if (!m_lazyAttributes) {
964                     List annotations = new ArrayList();
965                     annotations =
966                     AsmAnnotationHelper.extractAnnotations(annotations, attrs, (ClassLoader JavaDoc) m_loaderRef.get());
967                     memberInfo.m_annotations = annotations;
968                 }
969             }
970             if (methodInfo != null) {
971                 // visit the method to access the parameter names as required to support Aspect with bindings
972
// TODO: should we make this optional - similar to m_lazyAttributes ?
973
Type[] parameterTypes = Type.getArgumentTypes(desc);
974                 if (parameterTypes.length > 0) {
975                     CodeVisitor methodParameterNamesVisitor = new MethodParameterNamesCodeAdapter(
976                             Modifier.isStatic(access),
977                             parameterTypes.length, methodInfo
978                     );
979                     return methodParameterNamesVisitor;
980                 } else {
981                     methodInfo.m_parameterNames = EMPTY_STRING_ARRAY;
982                 }
983             }
984             return AsmAnnotationHelper.NullCodeAdapter.NULL_CODE_ADAPTER;
985         }
986
987         public void visitEnd() {
988             m_signature = AsmHelper.getClassDescriptor(AsmClassInfo.this);
989         }
990     }
991
992     /**
993      * Extracts method parameter names as they appear in the source code from debug infos
994      *
995      * @author <a HREF="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
996      */

997     static class MethodParameterNamesCodeAdapter extends AsmAnnotationHelper.NullCodeAdapter {
998         private final boolean m_isStatic;
999         private final int m_parameterCount;
1000        private AsmMethodInfo m_methodInfo;
1001        private int m_signatureParameterRegisterDepth = 0;
1002
1003        public MethodParameterNamesCodeAdapter(boolean isStatic, int parameterCount, AsmMethodInfo methodInfo) {
1004            m_isStatic = isStatic;
1005            m_parameterCount = parameterCount;
1006            m_methodInfo = methodInfo;
1007            m_methodInfo.m_parameterNames = new String JavaDoc[m_parameterCount];
1008
1009            // compute the max index of the arguments that appear in the method signature
1010
// including "this" on register 0 for non static methods
1011
// a long or double needs 2 registers
1012
if (!m_isStatic) {
1013                m_signatureParameterRegisterDepth++;// index 0 = this
1014
}
1015            m_signatureParameterRegisterDepth += AsmHelper.getRegisterDepth(Type.getArgumentTypes(m_methodInfo.m_member.desc));
1016        }
1017
1018        /**
1019         * Do not assume to visit the local variable with index always increasing since it is a wrong assumption
1020         * [ see f.e. test.args.ArgsAspect.withArray advice ]
1021         * @param name
1022         * @param desc
1023         * @param start
1024         * @param end
1025         * @param index the index of the argument on the stack
1026         */

1027        public void visitLocalVariable(String JavaDoc name, String JavaDoc desc, Label start, Label end, int index) {
1028            if (index < m_signatureParameterRegisterDepth) {
1029                // this is not a local variable
1030
if (index == 0) {
1031                    if (!m_isStatic) {
1032                        ;//skip this
1033
} else {
1034                        m_methodInfo.pushParameterNameFromRegister(index, name);
1035                    }
1036                } else {
1037                    m_methodInfo.pushParameterNameFromRegister(index, name);
1038                }
1039            } else {
1040                ;// skip code block locals
1041
}
1042        }
1043    }
1044
1045    /**
1046     * Converts the class name from VM type class name to Java type class name.
1047     *
1048     * @param className the VM type class name
1049     * @return the Java type class name
1050     */

1051    private static String JavaDoc getJavaClassName(final String JavaDoc className) {
1052        String JavaDoc javaClassName;
1053        if (className.startsWith("[")) {
1054            javaClassName = Type.getType(className).getClassName();
1055        } else {
1056            javaClassName = className.replace('/', '.');
1057        }
1058        return javaClassName;
1059    }
1060}
Popular Tags