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 gnu.trove.TIntObjectHashMap;
11 import org.codehaus.aspectwerkz.annotation.AnnotationInfo;
12 import org.codehaus.aspectwerkz.annotation.instrumentation.AttributeExtractor;
13 import org.codehaus.aspectwerkz.annotation.instrumentation.Attributes;
14 import org.codehaus.aspectwerkz.reflect.ClassInfo;
15 import org.codehaus.aspectwerkz.reflect.ConstructorInfo;
16 import org.codehaus.aspectwerkz.reflect.FieldInfo;
17 import org.codehaus.aspectwerkz.reflect.MethodInfo;
18
19 import java.lang.ref.WeakReference;
20 import java.util.ArrayList;
21 import java.util.List;
22
23 import javassist.CtClass;
24 import javassist.CtConstructor;
25 import javassist.CtField;
26 import javassist.CtMethod;
27 import javassist.NotFoundException;
28
29 /***
30 * Implementation of the ClassInfo interface for Javassist.
31 *
32 * @author <a href="mailto:jboner@codehaus.org">Jonas Bonér </a>
33 * @author <a href="mailto:alex@gnilux.com">Alexandre Vasseur </a>
34 */
35 public class JavassistClassInfo implements ClassInfo {
36 /***
37 * The class.
38 */
39 private final CtClass m_class;
40
41 /***
42 * The name of the class.
43 */
44 private String m_name;
45
46 /***
47 * Is the class a primitive type.
48 */
49 private boolean m_isPrimitive = false;
50
51 /***
52 * Is the class an interface.
53 */
54 private boolean m_isInterface = false;
55
56 /***
57 * Is the class of type array.
58 */
59 private boolean m_isArray = false;
60
61 /***
62 * A list with the <code>ConstructorMetaData</code> instances.
63 */
64 private final TIntObjectHashMap m_constructors = new TIntObjectHashMap();
65
66 /***
67 * A list with the <code>MethodInfo</code> instances.
68 */
69 private final TIntObjectHashMap m_methods = new TIntObjectHashMap();
70
71 /***
72 * A list with the <code>FieldMetaData</code> instances.
73 */
74 private final TIntObjectHashMap m_fields = new TIntObjectHashMap();
75
76 /***
77 * A list with the interfaces.
78 */
79 private ClassInfo[] m_interfaces = null;
80
81 /***
82 * The super class.
83 */
84 private ClassInfo m_superClass = null;
85
86 /***
87 * The attributes.
88 */
89 private List m_annotations = null;
90
91 /***
92 * The component type if array type.
93 */
94 private ClassInfo m_componentType = null;
95
96 /***
97 * The class info repository.
98 */
99 private JavassistClassInfoRepository m_classInfoRepository;
100
101 /***
102 * The class loader that loaded the class.
103 */
104 private transient final WeakReference m_loaderRef;
105
106 /***
107 * The attribute extractor.
108 */
109 private AttributeExtractor m_attributeExtractor;
110
111 /***
112 * Creates a new class meta data instance.
113 *
114 * @param klass
115 * @param loader
116 */
117 JavassistClassInfo(final CtClass klass, final ClassLoader loader) {
118 if (klass == null) {
119 throw new IllegalArgumentException("class can not be null");
120 }
121 if (loader == null) {
122 throw new IllegalArgumentException("class loader can not be null");
123 }
124 m_class = klass;
125 m_loaderRef = new WeakReference(loader);
126 m_isInterface = klass.isInterface();
127 m_attributeExtractor = Attributes.getAttributeExtractor(m_class, loader);
128 m_classInfoRepository = JavassistClassInfoRepository.getRepository(loader);
129 if (klass.isPrimitive()) {
130 m_name = klass.getName();
131 m_isPrimitive = true;
132 } else if (klass.isArray()) {
133 m_name = klass.getName();
134 m_isArray = true;
135 m_interfaces = new ClassInfo[0];
136 } else {
137 m_name = klass.getName();
138 CtMethod[] methods = m_class.getDeclaredMethods();
139 for (int i = 0; i < methods.length; i++) {
140 m_methods.put(JavassistMethodInfo.calculateHash(methods[i]), new JavassistMethodInfo(
141 methods[i],
142 this,
143 loader,
144 m_attributeExtractor));
145 }
146 CtConstructor[] constructors = m_class.getDeclaredConstructors();
147 for (int i = 0; i < constructors.length; i++) {
148 CtConstructor constructor = constructors[i];
149 m_constructors.put(JavassistConstructorInfo.calculateHash(constructor), new JavassistConstructorInfo(
150 constructor,
151 this,
152 loader,
153 m_attributeExtractor));
154 }
155 if (m_class.getClassInitializer() != null) {
156 CtConstructor constructor = m_class.getClassInitializer();
157 m_constructors.put(JavassistConstructorInfo.calculateHash(constructor), new JavassistConstructorInfo(
158 constructor,
159 this,
160 loader,
161 m_attributeExtractor));
162 }
163 CtField[] fields = m_class.getDeclaredFields();
164 for (int i = 0; i < fields.length; i++) {
165 CtField field = fields[i];
166 m_fields.put(JavassistFieldInfo.calculateHash(field), new JavassistFieldInfo(
167 field,
168 this,
169 loader,
170 m_attributeExtractor));
171 }
172 }
173 addAnnotations();
174 m_classInfoRepository.addClassInfo(this);
175 }
176
177 /***
178 * Returns the class info for a specific ctClass.
179 *
180 * @param clazz
181 * @param loader
182 * @return the class info
183 */
184 public static ClassInfo getClassInfo(final CtClass clazz, final ClassLoader loader) {
185 JavassistClassInfoRepository repository = JavassistClassInfoRepository.getRepository(loader);
186 ClassInfo classInfo = repository.getClassInfo(clazz.getName());
187 if (classInfo == null) {
188 classInfo = new JavassistClassInfo(clazz, loader);
189 }
190 return classInfo;
191 }
192
193 /***
194 * Marks the class as dirty (since it has been modified and needs to be rebuild).
195 *
196 * @param clazz
197 * @param loader
198 */
199 public static void markDirty(final CtClass clazz, final ClassLoader loader) {
200 JavassistClassInfoRepository.getRepository(loader).removeClassInfo(clazz);
201 }
202
203 /***
204 * Returns the annotations.
205 *
206 * @return the annotations
207 */
208 public List getAnnotations() {
209 return m_annotations;
210 }
211
212 /***
213 * Returns the name of the class.
214 *
215 * @return the name of the class
216 */
217 public String getName() {
218 return m_name;
219 }
220
221 /***
222 * Returns the class modifiers.
223 *
224 * @return the class modifiers
225 */
226 public int getModifiers() {
227 return m_class.getModifiers();
228 }
229
230 /***
231 * Returns a constructor info by its hash.
232 *
233 * @param hash
234 * @return
235 */
236 public ConstructorInfo getConstructor(final int hash) {
237 return (ConstructorInfo) m_constructors.get(hash);
238 }
239
240 /***
241 * Returns a list with all the constructors info.
242 *
243 * @return the constructors info
244 */
245 public ConstructorInfo[] getConstructors() {
246 Object[] values = m_constructors.getValues();
247 ConstructorInfo[] constructorInfos = new ConstructorInfo[values.length];
248 for (int i = 0; i < values.length; i++) {
249 constructorInfos[i] = (ConstructorInfo) values[i];
250 }
251 return constructorInfos;
252 }
253
254 /***
255 * Returns a method info by its hash.
256 *
257 * @param hash
258 * @return
259 */
260 public MethodInfo getMethod(final int hash) {
261 return (MethodInfo) m_methods.get(hash);
262 }
263
264 /***
265 * Returns a list with all the methods info.
266 *
267 * @return the methods info
268 */
269 public MethodInfo[] getMethods() {
270 Object[] values = m_methods.getValues();
271 MethodInfo[] methodInfos = new MethodInfo[values.length];
272 for (int i = 0; i < values.length; i++) {
273 methodInfos[i] = (MethodInfo) values[i];
274 }
275 return methodInfos;
276 }
277
278 /***
279 * Returns a field info by its hash.
280 *
281 * @param hash
282 * @return
283 */
284 public FieldInfo getField(final int hash) {
285 return (FieldInfo) m_fields.get(hash);
286 }
287
288 /***
289 * Returns a list with all the field info.
290 *
291 * @return the field info
292 */
293 public FieldInfo[] getFields() {
294 Object[] values = m_fields.getValues();
295 FieldInfo[] fieldInfos = new FieldInfo[values.length];
296 for (int i = 0; i < values.length; i++) {
297 fieldInfos[i] = (FieldInfo) values[i];
298 }
299 return fieldInfos;
300 }
301
302 /***
303 * Returns the interfaces.
304 *
305 * @return the interfaces
306 */
307 public ClassInfo[] getInterfaces() {
308 if (m_interfaces == null) {
309 try {
310 CtClass[] interfaces = m_class.getInterfaces();
311 m_interfaces = new ClassInfo[interfaces.length];
312 for (int i = 0; i < interfaces.length; i++) {
313 CtClass anInterface = interfaces[i];
314 ClassInfo classInfo = JavassistClassInfo.getClassInfo(anInterface, (ClassLoader) m_loaderRef.get());
315 m_interfaces[i] = classInfo;
316 if (!m_classInfoRepository.hasClassInfo(anInterface.getName())) {
317 m_classInfoRepository.addClassInfo(classInfo);
318 }
319 }
320 } catch (NotFoundException e) {
321
322 }
323 }
324 return m_interfaces;
325 }
326
327 /***
328 * Returns the super class.
329 *
330 * @return the super class
331 */
332 public ClassInfo getSuperClass() {
333 if (m_superClass == null) {
334 try {
335 CtClass superclass = m_class.getSuperclass();
336 if (superclass != null) {
337 if (m_classInfoRepository.hasClassInfo(superclass.getName())) {
338 m_superClass = m_classInfoRepository.getClassInfo(superclass.getName());
339 } else {
340 m_superClass = JavassistClassInfo.getClassInfo(superclass, (ClassLoader) m_loaderRef.get());
341 m_classInfoRepository.addClassInfo(m_superClass);
342 }
343 }
344 } catch (NotFoundException e) {
345
346 }
347 }
348 return m_superClass;
349 }
350
351 /***
352 * Returns the component type if array type else null.
353 *
354 * @return the component type
355 */
356 public ClassInfo getComponentType() {
357 if (isArray() && (m_componentType == null)) {
358
359
360
361
362
363
364
365
366
367 }
368 return m_componentType;
369 }
370
371 /***
372 * Is the class an interface.
373 *
374 * @return
375 */
376 public boolean isInterface() {
377 return m_isInterface;
378 }
379
380 /***
381 * Is the class a primitive type.
382 *
383 * @return
384 */
385 public boolean isPrimitive() {
386 return m_isPrimitive;
387 }
388
389 /***
390 * Is the class an array type.
391 *
392 * @return
393 */
394 public boolean isArray() {
395 return m_isArray;
396 }
397
398 public boolean equals(Object o) {
399 if (this == o) {
400 return true;
401 }
402 if (!(o instanceof ClassInfo)) {
403 return false;
404 }
405 ClassInfo classInfo = (ClassInfo) o;
406 return m_class.getName().toString().equals(classInfo.getName().toString());
407 }
408
409 public int hashCode() {
410 return m_class.getName().toString().hashCode();
411 }
412
413 /***
414 * Adds annotations to the class info.
415 */
416 private void addAnnotations() {
417 if (m_attributeExtractor == null) {
418 return;
419 }
420 m_annotations = new ArrayList();
421 Object[] attributes = m_attributeExtractor.getClassAttributes();
422 for (int i = 0; i < attributes.length; i++) {
423 Object attribute = attributes[i];
424 if (attribute instanceof AnnotationInfo) {
425 m_annotations.add(attribute);
426 }
427 }
428 }
429
430 public String toString() {
431 return getName();
432 }
433 }