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.javassist;
9
10 import org.codehaus.aspectwerkz.annotation.AnnotationInfo;
11 import org.codehaus.aspectwerkz.annotation.instrumentation.AttributeExtractor;
12 import org.codehaus.aspectwerkz.exception.WrappedRuntimeException;
13 import org.codehaus.aspectwerkz.reflect.ClassInfo;
14 import org.codehaus.aspectwerkz.reflect.MethodInfo;
15 import org.codehaus.aspectwerkz.transform.delegation.JavassistHelper;
16
17 import java.util.List;
18
19 import javassist.CtBehavior;
20 import javassist.CtClass;
21 import javassist.CtMethod;
22 import javassist.NotFoundException;
23
24 /***
25 * Implementation of the MethodInfo interface for Javassist.
26 *
27 * @author <a href="mailto:jboner@codehaus.org">Jonas Bonér </a>
28 */
29 public class JavassistMethodInfo extends JavassistCodeInfo implements MethodInfo {
30 /***
31 * The return type.
32 */
33 private ClassInfo m_returnType = null;
34
35 /***
36 * Creates a new method meta data instance.
37 *
38 * @param method
39 * @param declaringType
40 * @param loader
41 * @param attributeExtractor
42 */
43 JavassistMethodInfo(final CtMethod method,
44 final JavassistClassInfo declaringType,
45 final ClassLoader loader,
46 final AttributeExtractor attributeExtractor) {
47 super(method, declaringType, loader, attributeExtractor);
48 addAnnotations();
49 }
50
51 /***
52 * Returns the method info for the method specified.
53 *
54 * @param method the method
55 * @param loader the class loader
56 * @return the method info
57 */
58 public static MethodInfo getMethodInfo(final CtMethod method, final ClassLoader loader) {
59 CtClass declaringClass = method.getDeclaringClass();
60 JavassistClassInfoRepository repository = JavassistClassInfoRepository.getRepository(loader);
61 ClassInfo classInfo = repository.getClassInfo(declaringClass.getName());
62 if (classInfo == null) {
63 classInfo = JavassistClassInfo.getClassInfo(declaringClass, loader);
64 }
65 return classInfo.getMethod(calculateHash(method));
66 }
67
68 /***
69 * Calculates the method hash.
70 *
71 * @param method
72 * @return the hash
73 */
74 public static int calculateHash(final CtMethod method) {
75 int hash = method.getName().hashCode();
76 try {
77 for (int i = 0; i < method.getParameterTypes().length; i++) {
78 String name = method.getParameterTypes()[i].getName();
79 name = JavassistHelper.convertJavassistTypeSignatureToReflectTypeSignature(name);
80 hash = (17 * hash) + name.hashCode();
81 }
82 } catch (NotFoundException e) {
83
84 }
85 return hash;
86 }
87
88 /***
89 * Returns the annotations.
90 *
91 * @return the annotations
92 */
93 public List getAnnotations() {
94 return m_annotations;
95 }
96
97 /***
98 * Returns the return type.
99 *
100 * @return the return type
101 */
102 public ClassInfo getReturnType() {
103 if (m_returnType == null) {
104 try {
105 CtClass returnTypeClass = ((CtMethod) m_member).getReturnType();
106 if (m_classInfoRepository.hasClassInfo(returnTypeClass.getName())) {
107 m_returnType = m_classInfoRepository.getClassInfo(returnTypeClass.getName());
108 } else {
109 m_returnType = JavassistClassInfo.getClassInfo(returnTypeClass, (ClassLoader) m_loaderRef.get());
110 m_classInfoRepository.addClassInfo(m_returnType);
111 }
112 } catch (NotFoundException e) {
113
114 }
115 }
116 return m_returnType;
117 }
118
119 public boolean equals(Object o) {
120 if (this == o) {
121 return true;
122 }
123 if (!(o instanceof MethodInfo)) {
124 return false;
125 }
126 MethodInfo methodInfo = (MethodInfo) o;
127 if (!m_declaringType.getName().toString().equals(methodInfo.getDeclaringType().getName().toString())) {
128 return false;
129 }
130 if (!m_member.getName().toString().equals(methodInfo.getName().toString())) {
131 return false;
132 }
133 ClassInfo[] parameterTypes = methodInfo.getParameterTypes();
134 if (m_parameterTypes.length != parameterTypes.length) {
135 return false;
136 }
137 for (int i = 0; i < m_parameterTypes.length; i++) {
138 if (!m_parameterTypes[i].getName().toString().equals(parameterTypes[i].getName().toString())) {
139 return false;
140 }
141 }
142 return true;
143 }
144
145 public int hashCode() {
146 int result = 29;
147 result = (29 * result) + m_declaringType.getName().toString().hashCode();
148 result = (29 * result) + m_member.getName().toString().hashCode();
149 if (m_parameterTypes == null) {
150 getParameterTypes();
151 }
152 for (int i = 0; i < m_parameterTypes.length; i++) {
153 result = (29 * result) + m_parameterTypes[i].getName().toString().hashCode();
154 }
155 return result;
156 }
157
158 /***
159 * Adds annotations to the method info.
160 */
161 private void addAnnotations() {
162 if (m_attributeExtractor == null) {
163 return;
164 }
165 try {
166 CtClass[] parameterTypes = ((CtBehavior) m_member).getParameterTypes();
167 String[] parameterNames = new String[parameterTypes.length];
168 for (int i = 0; i < parameterTypes.length; i++) {
169 parameterNames[i] = parameterTypes[i].getName();
170 }
171 Object[] attributes = m_attributeExtractor.getMethodAttributes(getName(), parameterNames);
172 for (int i = 0; i < attributes.length; i++) {
173 Object attribute = attributes[i];
174 if (attribute instanceof AnnotationInfo) {
175 m_annotations.add(attribute);
176 }
177 }
178 } catch (NotFoundException e) {
179
180 }
181 }
182
183 public String toString() {
184 return m_member.toString();
185 }
186 }