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
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
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) {
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 }