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;
34 import java.io.InputStream;
35 import java.lang.ref.WeakReference;
36 import java.lang.reflect.Array;
37 import java.lang.reflect.Modifier;
38 import java.util.ArrayList;
39 import java.util.List;
40 import java.util.Iterator;
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[] EMPTY_STRING_ARRAY = new String[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 m_loaderRef;
65
66 /***
67 * The name of the class (with dots and not slashes)
68 */
69 private String m_name;
70
71 /***
72 * The signature of the class.
73 */
74 private String 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[] 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 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 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 loader, boolean lazyAttributes) {
182 if (bytecode == null) {
183 throw new IllegalArgumentException("bytecode can not be null");
184 }
185 m_loaderRef = new WeakReference(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 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 resourceStream, final ClassLoader loader) {
204 if (resourceStream == null) {
205 throw new IllegalArgumentException("resource stream can not be null");
206 }
207 m_loaderRef = new WeakReference(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 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 className,
229 final ClassLoader loader,
230 final ClassInfo componentInfo) {
231 m_loaderRef = new WeakReference(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;
239 m_superClass = JavaClassInfo.getClassInfo(Object.class);
240 m_superClassName = m_superClass.getName();
241 m_interfaceClassNames = new String[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 loader) {
255 final String 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 className, final ClassLoader loader) {
269 final String 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 loader) {
286 final String 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 stream, final ClassLoader loader) {
303 try {
304 ClassReader cr = new ClassReader(stream);
305
306 byte[] bytes = cr.b;
307 ClassNameRetrievalClassAdapter visitor = new ClassNameRetrievalClassAdapter();
308 cr.accept(visitor, NO_ATTRIBUTES, true);
309 final String 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 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 stream, final ClassLoader loader, boolean lazyAttributes) {
330 if (lazyAttributes) {
331 return getClassInfo(stream, loader);
332 }
333 try {
334 ClassReader cr = new ClassReader(stream);
335
336 byte[] bytes = cr.b;
337 ClassNameRetrievalClassAdapter visitor = new ClassNameRetrievalClassAdapter();
338 cr.accept(visitor, NO_ATTRIBUTES, true);
339 String 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 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 className, final ClassLoader 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 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 getPrimitiveClass(final String 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 in = null;
415 ClassReader cr = null;
416 try {
417 if ((ClassLoader) m_loaderRef.get() != null) {
418 in =
419 ((ClassLoader) 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) m_loaderRef.get(), m_name);
425 }
426 cr = new ClassReader(in);
427 } finally {
428 try {
429 in.close();
430 } catch (Exception e) {
431 ;
432 }
433 }
434 List annotations = new ArrayList();
435 cr.accept(
436 new AsmAnnotationHelper.ClassAnnotationExtractor(
437 annotations, (ClassLoader) m_loaderRef.get()
438 ),
439 Attributes.getDefaultAttributes(),
440 true
441 );
442 m_annotations = annotations;
443 } catch (IOException e) {
444
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 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 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 getClassLoader() {
488 return (ClassLoader) 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) 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) 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) 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 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 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 className,
710 final ClassLoader 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 name,
724 final ClassLoader loader,
725 boolean lazyAttributes) {
726 final String className = name.replace('.', '/');
727
728
729 if (name.indexOf('/') < 0) {
730
731
732 int dimension = 0;
733 for (int i = className.indexOf('['); i > 0; i = className.indexOf('[', i+1)) {
734 dimension++;
735 }
736 String unidimComponentName = className;
737 if (dimension > 0) {
738 int unidimComponentTypeIndex = className.indexOf('[');
739 unidimComponentName = className.substring(0, unidimComponentTypeIndex);
740 }
741 Class primitiveClass = AsmClassInfo.getPrimitiveClass(unidimComponentName);
742 if (primitiveClass != null && primitiveClass.isPrimitive()) {
743 if (dimension == 0) {
744 return JavaClassInfo.getClassInfo(primitiveClass);
745 } else {
746 Class arrayClass = Array.newInstance(primitiveClass, new int[dimension]).getClass();
747 return JavaClassInfo.getClassInfo(arrayClass);
748 }
749 }
750 }
751
752
753
754 int componentTypeIndex = className.lastIndexOf('[');
755 String 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
765 if (componentName.indexOf('[') > 0) {
766 componentInfo = getClassInfo(componentName, loader);
767 } else {
768 InputStream componentClassAsStream = null;
769 if (loader != null) {
770 componentClassAsStream = loader.getResourceAsStream(componentName + ".class");
771 } else {
772
773 componentClassAsStream = ClassLoader.getSystemClassLoader().getResourceAsStream(componentName + ".class");
774 }
775 if (componentClassAsStream == null) {
776
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 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
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
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 m_className;
839
840 public void visit(final int version,
841 final int access,
842 final String name,
843 final String superName,
844 final String[] interfaces,
845 final String sourceFile) {
846 m_className = name.replace('/', '.');
847 }
848
849 public String 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 name,
870 final String superName,
871 final String[] interfaces,
872 final String sourceFile) {
873
874 m_name = name.replace('/', '.');
875 m_modifiers = access;
876 m_isInterface = Modifier.isInterface(m_modifiers);
877
878 m_superClassName = superName == null ? null : superName.replace('/', '.');
879 m_interfaceClassNames = new String[interfaces.length];
880 for (int i = 0; i < interfaces.length; i++) {
881 m_interfaceClassNames[i] = interfaces[i].replace('/', '.');
882 }
883
884
885
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
904 if (!m_lazyAttributes) {
905 List annotations = new ArrayList();
906 annotations =
907 AsmAnnotationHelper.extractAnnotations(annotations, attribute, (ClassLoader) m_loaderRef.get());
908 m_annotations = annotations;
909 }
910 }
911
912 public void visitField(final int access,
913 final String name,
914 final String desc,
915 final Object 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) m_loaderRef.get());
923
924 if (!m_lazyAttributes) {
925 List annotations = new ArrayList();
926 annotations =
927 AsmAnnotationHelper.extractAnnotations(annotations, attrs, (ClassLoader) 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 name,
937 final String desc,
938 final String[] 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
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) m_loaderRef.get());
954 m_constructors.put(hash, memberInfo);
955 m_sortedConstructorHashes.add(hash);
956 } else {
957 memberInfo = new AsmMethodInfo(struct, m_name, (ClassLoader) m_loaderRef.get());
958 m_methods.put(hash, memberInfo);
959 m_sortedMethodHashes.add(hash);
960 methodInfo = (AsmMethodInfo) memberInfo;
961 }
962
963 if (!m_lazyAttributes) {
964 List annotations = new ArrayList();
965 annotations =
966 AsmAnnotationHelper.extractAnnotations(annotations, attrs, (ClassLoader) m_loaderRef.get());
967 memberInfo.m_annotations = annotations;
968 }
969 }
970 if (methodInfo != null) {
971
972
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[m_parameterCount];
1008
1009
1010
1011
1012 if (!m_isStatic) {
1013 m_signatureParameterRegisterDepth++;
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 name, String desc, Label start, Label end, int index) {
1028 if (index < m_signatureParameterRegisterDepth) {
1029
1030 if (index == 0) {
1031 if (!m_isStatic) {
1032 ;
1033 } else {
1034 m_methodInfo.pushParameterNameFromRegister(index, name);
1035 }
1036 } else {
1037 m_methodInfo.pushParameterNameFromRegister(index, name);
1038 }
1039 } else {
1040 ;
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 getJavaClassName(final String className) {
1052 String javaClassName;
1053 if (className.startsWith("[")) {
1054 javaClassName = Type.getType(className).getClassName();
1055 } else {
1056 javaClassName = className.replace('/', '.');
1057 }
1058 return javaClassName;
1059 }
1060 }