View Javadoc

1   /***************************************************************************************
2    * Copyright (c) Jonas Bonér, Alexandre Vasseur. All rights reserved.                 *
3    * http://aspectwerkz.codehaus.org                                                    *
4    * ---------------------------------------------------------------------------------- *
5    * The software in this package is published under the terms of the LGPL license      *
6    * a copy of which has been included with this distribution in the license.txt file.  *
7    **************************************************************************************/
8   package org.codehaus.aspectwerkz.reflect.impl.asm;
9   
10  import org.codehaus.aspectwerkz.reflect.ClassInfo;
11  import org.codehaus.aspectwerkz.reflect.MethodInfo;
12  import org.codehaus.aspectwerkz.transform.AsmHelper;
13  import org.codehaus.aspectwerkz.transform.AsmHelper;
14  import org.codehaus.aspectwerkz.annotation.instrumentation.asm.AsmAnnotationHelper;
15  import org.objectweb.asm.Type;
16  import org.objectweb.asm.ClassReader;
17  
18  import java.util.List;
19  import java.util.ArrayList;
20  import java.io.IOException;
21  
22  /***
23   * ASM implementation of the MethodInfo interface.
24   * 
25   * @author <a href="mailto:jboner@codehaus.org">Jonas Bonér </a>
26   */
27  public class AsmMethodInfo extends AsmMemberInfo implements MethodInfo {
28      /***
29       * The return type name.
30       */
31      private String m_returnTypeName = null;
32  
33      /***
34       * A list with the parameter type names.
35       */
36      private String[] m_parameterTypeNames = null;
37  
38      /***
39       * A list with the exception type names.
40       */
41      private String[] m_exceptionTypeNames = null;
42  
43      /***
44       * The return type.
45       */
46      private ClassInfo m_returnType = null;
47  
48      /***
49       * A list with the parameter types.
50       */
51      private ClassInfo[] m_parameterTypes = null;
52  
53      /***
54       * A list with the exception types.
55       */
56      private ClassInfo[] m_exceptionTypes = null;
57  
58      /***
59       * Creates a new method info instance.
60       * 
61       * @param method
62       * @param declaringType
63       * @param loader
64       */
65      AsmMethodInfo(final MethodStruct method, final String declaringType, final ClassLoader loader) {
66          super(method, declaringType, loader);
67  
68          m_returnTypeName = Type.getReturnType(method.desc).getClassName();
69          Type[] argTypes = Type.getArgumentTypes(method.desc);
70          m_parameterTypeNames = new String[argTypes.length];
71          for (int i = 0; i < argTypes.length; i++) {
72              m_parameterTypeNames[i] = argTypes[i].getClassName();
73          }
74          // FIXME: how to do exceptions? needed?
75          m_exceptionTypeNames = new String[] {};
76      }
77  
78      /***
79       * Returns the method info for the method specified.
80       * 
81       * @param methodName
82       * @param methodDesc
83       * @param bytecode
84       * @param loader
85       * @return the method info
86       */
87      public static MethodInfo getMethodInfo(
88          final String methodName,
89          final String methodDesc,
90          final byte[] bytecode,
91          final ClassLoader loader) {
92          String className = AsmClassInfo.retrieveClassNameFromBytecode(bytecode);
93          AsmClassInfoRepository repository = AsmClassInfoRepository.getRepository(loader);
94          ClassInfo classInfo = repository.getClassInfo(className);
95          if (classInfo == null) {
96              classInfo = AsmClassInfo.getClassInfo(bytecode, loader);
97          }
98          return classInfo.getMethod(AsmHelper.calculateMethodHash(methodName, methodDesc));
99      }
100 
101     /***
102      * Returns the return type.
103      * 
104      * @return the return type
105      */
106     public ClassInfo getReturnType() {
107         if (m_returnType == null) {
108             m_returnType = AsmClassInfo.getClassInfo(m_returnTypeName, (ClassLoader) m_loaderRef.get());
109         }
110         return m_returnType;
111     }
112 
113     /***
114      * Returns the parameter types.
115      * 
116      * @return the parameter types
117      */
118     public ClassInfo[] getParameterTypes() {
119         if (m_parameterTypes == null) {
120             m_parameterTypes = new ClassInfo[m_parameterTypeNames.length];
121             for (int i = 0; i < m_parameterTypeNames.length; i++) {
122                 m_parameterTypes[i] = AsmClassInfo.getClassInfo(
123                         m_parameterTypeNames[i],
124                         (ClassLoader) m_loaderRef.get()
125                 );
126             }
127         }
128         return m_parameterTypes;
129     }
130 
131     /***
132      * Returns the exception types.
133      * 
134      * @return the exception types
135      */
136     public ClassInfo[] getExceptionTypes() {
137         if (m_exceptionTypes == null) {
138             m_exceptionTypes = new ClassInfo[m_exceptionTypeNames.length];
139             for (int i = 0; i < m_exceptionTypeNames.length; i++) {
140                 m_exceptionTypes[i] = AsmClassInfo.getClassInfo(
141                         m_exceptionTypeNames[i],
142                         (ClassLoader) m_loaderRef.get()
143                 );
144             }
145         }
146         return m_exceptionTypes;
147     }
148 
149     /***
150      * Returns the annotations.
151      *
152      * @return the annotations
153      */
154     public List getAnnotations() {
155         if (m_annotations == null) {
156             try {
157                 ClassReader cr = new ClassReader(((ClassLoader)m_loaderRef.get()).getResourceAsStream(m_declaringTypeName.replace('.','/')+".class"));
158                 List annotations = new ArrayList();
159                 cr.accept(
160                         new AsmAnnotationHelper.MethodAnnotationExtractor(annotations, m_member.name, m_member.desc, (ClassLoader)m_loaderRef.get()),
161                         AsmAnnotationHelper.ANNOTATIONS_ATTRIBUTES,
162                         true
163                 );
164                 m_annotations = annotations;
165             } catch (IOException e) {
166                 // unlikely to occur since ClassInfo relies on getResourceAsStream
167                 System.err.println("WARN - could not load " + m_declaringTypeName + " as a resource to retrieve annotations");
168                 m_annotations = AsmClassInfo.EMPTY_LIST;
169             }
170         }
171         return m_annotations;
172     }
173 
174     public boolean equals(Object o) {
175         if (this == o) {
176             return true;
177         }
178         if (!(o instanceof MethodInfo)) {
179             return false;
180         }
181         MethodInfo methodInfo = (MethodInfo) o;
182         if (!m_declaringTypeName.equals(methodInfo.getDeclaringType().getName())) {
183             return false;
184         }
185         if (!m_member.name.equals(methodInfo.getName())) {
186             return false;
187         }
188         ClassInfo[] parameterTypes = methodInfo.getParameterTypes();
189         if (m_parameterTypeNames.length != parameterTypes.length) {//check on names length for lazyness optim
190             return false;
191         }
192         for (int i = 0; i < m_parameterTypeNames.length; i++) {
193             if (!m_parameterTypeNames[i].equals(parameterTypes[i].getName())) {
194                 return false;
195             }
196         }
197         return true;
198     }
199 
200     public int hashCode() {
201         int result = 29;
202         result = (29 * result) + m_declaringTypeName.hashCode();
203         result = (29 * result) + m_member.name.hashCode();
204         for (int i = 0; i < m_parameterTypeNames.length; i++) {
205             result = (29 * result) + m_parameterTypeNames[i].hashCode();
206         }
207         return result;
208     }
209 
210     public String toString() {
211         StringBuffer sb = new StringBuffer(m_declaringTypeName);
212         sb.append('.').append(m_member.name);
213         sb.append(m_member.desc);
214         return sb.toString();
215     }
216 }