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.annotation.instrumentation;
9
10 import org.codehaus.aspectwerkz.annotation.instrumentation.javassist.JavassistAttributeExtractor;
11 import org.codehaus.aspectwerkz.exception.WrappedRuntimeException;
12
13 import java.util.Map;
14 import java.util.WeakHashMap;
15
16 import javassist.CtClass;
17
18 /***
19 * Retrieves attributes from the class bytecode on class, method and field level.
20 *
21 * FIXME - remove in 2.0
22 *
23 * @author <a href="mailto:jboner@codehaus.org">Jonas Bonér </a>
24 */
25 public class Attributes {
26 // private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
27
28 /***
29 * Hold a cache of AttributeExtractors so we don't have to load the class loaded repeatedly when accessing custom
30 * attributes.
31 */
32 private static final Map s_extractorCache = new WeakHashMap();
33
34 // /***
35 // * Return the list (possibly empty) of custom attributes associated with the class "klass".
36 // *
37 // * @param klass The java.lang.Class object to find the attributes on.
38 // * @return The possibly 0-length array of attributes
39 // */
40 // public static Object[] getAttributes(final Class klass) {
41 // AttributeExtractor extractor = getAttributeExtractor(klass);
42 // if (extractor == null) {
43 // return EMPTY_OBJECT_ARRAY;
44 // } else {
45 // return extractor.getClassAttributes();
46 // }
47 // }
48 //
49 // /***
50 // * Return all the attributes associated with the given method.
51 // *
52 // * @param method The java.lang.reflect.Method describing the method.
53 // * @return Attribute[] all attributes associated with the method. Returns a 0 length array in case no attributes
54 // * were found.
55 // */
56 // public static Object[] getAttributes(final Method method) {
57 // Class klass = method.getDeclaringClass();
58 // ArrayList attribList = new ArrayList();
59 //
60 // // search for superclass
61 // while (true) {
62 // Object[] returnAttribs = searchForMethodAttributes(klass, method);
63 // if (returnAttribs.length > 0) {
64 // // already in the list and the attribute is allowed to be specified mulitple times.
65 // attribList.addAll(Arrays.asList(returnAttribs));
66 // }
67 // Class superClass = klass.getSuperclass();
68 // if (superClass == null) {
69 // break;
70 // } else if (superClass.getName().startsWith("java.")) {
71 // break;
72 // } else {
73 // klass = superClass;
74 // }
75 // }
76 //
77 // // search for interfaces.
78 // while (true) {
79 // Class[] interfaceClasses = klass.getInterfaces();
80 // for (int i = 0; i < interfaceClasses.length; i++) {
81 // Object[] intAttribs = searchForMethodAttributes(interfaceClasses[i], method);
82 // if (intAttribs.length > 0) {
83 // attribList.addAll(Arrays.asList(intAttribs));
84 // }
85 // }
86 // Class superClass = klass.getSuperclass();
87 // if (superClass == null) {
88 // break;
89 // } else if (superClass.getName().startsWith("java.")) {
90 // break;
91 // } else {
92 // klass = superClass;
93 // }
94 // }
95 // return attribList.toArray(new Object[attribList.size()]);
96 // }
97 //
98 // /***
99 // * Return all the attributes associated with the given method.
100 // *
101 // * @param method The java.lang.reflect.Method describing the method.
102 // * @return Attribute[] all attributes associated with the method. Returns a 0 length array in case no attributes
103 // * were found.
104 // */
105 // public static Object[] getAttributes(final Constructor constructor) {
106 // Class klass = constructor.getDeclaringClass();
107 // ArrayList attribList = new ArrayList();
108 //
109 // // search for superclass
110 // while (true) {
111 // Object[] returnAttribs = searchForConstructorAttributes(klass, constructor);
112 // if (returnAttribs.length > 0) {
113 // // already in the list and the attribute is allowed to be specified mulitple times.
114 // attribList.addAll(Arrays.asList(returnAttribs));
115 // }
116 // Class superClass = klass.getSuperclass();
117 // if (superClass == null) {
118 // break;
119 // } else if (superClass.getName().startsWith("java.")) {
120 // break;
121 // } else {
122 // klass = superClass;
123 // }
124 // }
125 //
126 // // search for interfaces.
127 // while (true) {
128 // Class[] interfaceClasses = klass.getInterfaces();
129 // for (int i = 0; i < interfaceClasses.length; i++) {
130 // Object[] intAttribs = searchForConstructorAttributes(interfaceClasses[i], constructor);
131 // if (intAttribs.length > 0) {
132 // attribList.addAll(Arrays.asList(intAttribs));
133 // }
134 // }
135 // Class superClass = klass.getSuperclass();
136 // if (superClass == null) {
137 // break;
138 // } else if (superClass.getName().startsWith("java.")) {
139 // break;
140 // } else {
141 // klass = superClass;
142 // }
143 // }
144 // return attribList.toArray(new Object[attribList.size()]);
145 // }
146 //
147 // /***
148 // * Return the list (possibly empty) of custom attributes associated with the field.
149 // *
150 // * @param field The java.lang.reflect.Field object to find the attributes on.
151 // * @return The possibly 0-length array of attributes
152 // */
153 // public static Object[] getAttributes(final Field field) {
154 // AttributeExtractor extractor = getAttributeExtractor(field.getDeclaringClass());
155 // if (extractor == null) {
156 // return EMPTY_OBJECT_ARRAY;
157 // } else {
158 // return extractor.getFieldAttributes(field.getName());
159 // }
160 // }
161 //
162 // /***
163 // * Searches for method attributes
164 // *
165 // * @param klass
166 // * @param method
167 // * @return Attribute[]
168 // */
169 // private static Object[] searchForMethodAttributes(final Class klass, final Method method) {
170 // AttributeExtractor extractor = getAttributeExtractor(klass);
171 // if (extractor == null) {
172 // return EMPTY_OBJECT_ARRAY;
173 // } else {
174 // String[] paramTypes = new String[method.getParameterTypes().length];
175 // for (int i = 0; i < paramTypes.length; i++) {
176 // String paramType = method.getParameterTypes()[i].getName();
177 //
178 // // TODO: is this fix generic? are there other cases not handled?
179 // // handle array types
180 // if (paramType.startsWith("[L")) {
181 // paramType = paramType.substring(2, paramType.length() - 1) + "[]";
182 // }
183 // paramTypes[i] = paramType;
184 // }
185 // return extractor.getMethodAttributes(method.getName(), paramTypes);
186 // }
187 // }
188 //
189 // /***
190 // * Searches for constructor attributes
191 // *
192 // * @param klass
193 // * @param constructor
194 // * @return Attribute[]
195 // */
196 // private static Object[] searchForConstructorAttributes(final Class klass, final Constructor constructor) {
197 // AttributeExtractor extractor = getAttributeExtractor(klass);
198 // if (extractor != null) {
199 // String[] paramTypes = new String[constructor.getParameterTypes().length];
200 // for (int i = 0; i < paramTypes.length; i++) {
201 // String paramType = constructor.getParameterTypes()[i].getName();
202 //
203 // // TODO: is this fix generic? are there other cases not handled?
204 // // handle array types
205 // if (paramType.startsWith("[L")) {
206 // paramType = paramType.substring(2, paramType.length() - 1) + "[]";
207 // }
208 // paramTypes[i] = paramType;
209 // }
210 // return extractor.getConstructorAttributes(paramTypes);
211 // } else {
212 // return EMPTY_OBJECT_ARRAY;
213 // }
214 // }
215
216 // /***
217 // * Return the attribute extractor associated with the class.
218 // *
219 // * @param klass the Class object to find the attributes on.
220 // * @return the attribute extractor or null if the class bytecode could not be found
221 // */
222 // public static synchronized AttributeExtractor getAttributeExtractor(final Class klass) {
223 // if (klass.isPrimitive() || klass.isArray() || klass.getName().startsWith("java.")) {
224 // return null;
225 // }
226 // AsmAttributeExtractor extractor;
227 // if ((extractor = (AsmAttributeExtractor) s_extractorCache.get(klass)) == null) {
228 // String className = klass.getName();
229 // try {
230 // ClassLoader loader = klass.getClassLoader();
231 // if (loader != null) {
232 // extractor = new AsmAttributeExtractor();
233 // if (extractor.initialize(className, klass.getClassLoader())) {
234 // s_extractorCache.put(klass, extractor);
235 // } else {
236 // return null;
237 // }
238 // } else {
239 // // bootstrap classloader
240 // extractor = new AsmAttributeExtractor();
241 // if (extractor.initialize(className, ClassLoader.getSystemClassLoader())) {
242 // s_extractorCache.put(klass, extractor);
243 // } else {
244 // return null;
245 // }
246 // }
247 // } catch (Exception e) {
248 // throw new WrappedRuntimeException(e);
249 // }
250 // }
251 // return extractor;
252 // }
253
254 /***
255 * Return the list (possibly empty) of custom attributes associated with the class.
256 *
257 * @param ctClass the class name
258 * @param loader the class loader
259 * @return the possibly 0-length array of attributes
260 */
261 public static synchronized AttributeExtractor getAttributeExtractor(final CtClass ctClass, final ClassLoader loader) {
262 if (ctClass.isPrimitive() || ctClass.isArray() || ctClass.getName().startsWith("java.")) {
263 return null;
264 }
265 JavassistAttributeExtractor extractor;
266 Integer hash = new Integer((29 * ctClass.hashCode()) + loader.hashCode());
267 if ((extractor = (JavassistAttributeExtractor) s_extractorCache.get(hash)) == null) {
268 try {
269 extractor = new JavassistAttributeExtractor();
270 extractor.initialize(ctClass);
271 s_extractorCache.put(hash, extractor);
272 } catch (Exception e) {
273 throw new WrappedRuntimeException(e);
274 }
275 }
276 return extractor;
277 }
278 }