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.java;
9
10 import gnu.trove.TIntObjectHashMap;
11 import org.codehaus.aspectwerkz.annotation.Annotations;
12 import org.codehaus.aspectwerkz.reflect.ClassInfo;
13 import org.codehaus.aspectwerkz.reflect.ConstructorInfo;
14 import org.codehaus.aspectwerkz.reflect.FieldInfo;
15 import org.codehaus.aspectwerkz.reflect.MethodInfo;
16 import org.codehaus.aspectwerkz.transform.TransformationUtil;
17 import org.codehaus.aspectwerkz.transform.ReflectHelper;
18 import org.codehaus.aspectwerkz.transform.TransformationConstants;
19
20 import java.lang.reflect.Constructor;
21 import java.lang.reflect.Field;
22 import java.lang.reflect.Method;
23 import java.util.List;
24
25 /***
26 * Implementation of the ClassInfo interface for java.lang.reflect.*.
27 *
28 * @author <a href="mailto:jboner@codehaus.org">Jonas Bonér </a>
29 */
30 public class JavaClassInfo implements ClassInfo {
31 /***
32 * The class.
33 */
34 private final Class m_class;
35
36 /***
37 * The name of the class.
38 */
39 private String m_name;
40
41 /***
42 * Is the class an interface.
43 */
44 private boolean m_isInterface = false;
45
46 /***
47 * Is the class a primitive type.
48 */
49 private boolean m_isPrimitive = false;
50
51 /***
52 * Is the class of type array.
53 */
54 private boolean m_isArray = false;
55
56 /***
57 * A list with the <code>ConstructorInfo</code> instances.
58 */
59 private final TIntObjectHashMap m_constructors = new TIntObjectHashMap();
60
61 /***
62 * A list with the <code>MethodInfo</code> instances.
63 */
64 private final TIntObjectHashMap m_methods = new TIntObjectHashMap();
65
66 /***
67 * A list with the <code>FieldInfo</code> instances.
68 */
69 private final TIntObjectHashMap m_fields = new TIntObjectHashMap();
70
71 /***
72 * A list with the interfaces.
73 */
74 private ClassInfo[] m_interfaces = null;
75
76 /***
77 * The super class.
78 */
79 private ClassInfo m_superClass = null;
80
81 /***
82 * The annotations.
83 */
84 private List m_annotations = null;
85
86 /***
87 * The component type if array type.
88 */
89 private ClassInfo m_componentType = null;
90
91 /***
92 * The class info repository.
93 */
94 private final JavaClassInfoRepository m_classInfoRepository;
95
96 /***
97 * Creates a new class meta data instance.
98 *
99 * @param klass
100 */
101 JavaClassInfo(final Class klass) {
102 if (klass == null) {
103 throw new IllegalArgumentException("class can not be null");
104 }
105 m_class = klass;
106 m_classInfoRepository = JavaClassInfoRepository.getRepository(klass.getClassLoader());
107 m_isInterface = klass.isInterface();
108 if (klass.isPrimitive()) {
109 m_name = klass.getName();
110 m_isPrimitive = true;
111 } else if (klass.getComponentType() != null) {
112 m_name = convertJavaArrayTypeNameToHumanTypeName(klass.getName());
113 m_isArray = true;
114 m_interfaces = new ClassInfo[0];
115 } else {
116 m_name = klass.getName();
117 Method[] methods = m_class.getDeclaredMethods();
118 for (int i = 0; i < methods.length; i++) {
119 Method method = methods[i];
120 m_methods.put(ReflectHelper.calculateHash(method), new JavaMethodInfo(method, this));
121 }
122 Constructor[] constructors = m_class.getDeclaredConstructors();
123 for (int i = 0; i < constructors.length; i++) {
124 Constructor constructor = constructors[i];
125 m_constructors.put(ReflectHelper.calculateHash(constructor), new JavaConstructorInfo(
126 constructor,
127 this));
128 }
129 Field[] fields = m_class.getDeclaredFields();
130 for (int i = 0; i < fields.length; i++) {
131 if (fields[i].getName().startsWith(TransformationConstants.ASPECTWERKZ_PREFIX)) {
132 continue;
133 }
134 Field field = fields[i];
135 m_fields.put(ReflectHelper.calculateHash(field), new JavaFieldInfo(field, this));
136 }
137 }
138 m_classInfoRepository.addClassInfo(this);
139 }
140
141 /***
142 * Returns the class info for a specific class.
143 *
144 * @return the class info
145 */
146 public static ClassInfo getClassInfo(final Class clazz) {
147 JavaClassInfoRepository repository = JavaClassInfoRepository.getRepository(clazz.getClassLoader());
148 ClassInfo classInfo = repository.getClassInfo(clazz.getName());
149 if (classInfo == null) {
150 classInfo = new JavaClassInfo(clazz);
151 }
152 return classInfo;
153 }
154
155 /***
156 * Returns the annotations infos.
157 *
158 * @return the annotations infos
159 */
160 public List getAnnotations() {
161 if (m_annotations == null) {
162 m_annotations = Annotations.getAnnotationInfos(m_class);
163 }
164 return m_annotations;
165 }
166
167 /***
168 * Returns the name of the class.
169 *
170 * @return the name of the class
171 */
172 public String getName() {
173 return m_name.replace('/', '.');
174 }
175
176 /***
177 * Returns the class modifiers.
178 *
179 * @return the class modifiers
180 */
181 public int getModifiers() {
182 return m_class.getModifiers();
183 }
184
185 /***
186 * Returns a constructor info by its hash.
187 *
188 * @param hash
189 * @return
190 */
191 public ConstructorInfo getConstructor(final int hash) {
192 return (ConstructorInfo) m_constructors.get(hash);
193 }
194
195 /***
196 * Returns a list with all the constructors info.
197 *
198 * @return the constructors info
199 */
200 public ConstructorInfo[] getConstructors() {
201 Object[] values = m_constructors.getValues();
202 ConstructorInfo[] methodInfos = new ConstructorInfo[values.length];
203 for (int i = 0; i < values.length; i++) {
204 methodInfos[i] = (ConstructorInfo) values[i];
205 }
206 return methodInfos;
207 }
208
209 /***
210 * Returns a method info by its hash.
211 *
212 * @param hash
213 * @return
214 */
215 public MethodInfo getMethod(final int hash) {
216 return (MethodInfo) m_methods.get(hash);
217 }
218
219 /***
220 * Returns a list with all the methods info.
221 *
222 * @return the methods info
223 */
224 public MethodInfo[] getMethods() {
225 Object[] values = m_methods.getValues();
226 MethodInfo[] methodInfos = new MethodInfo[values.length];
227 for (int i = 0; i < values.length; i++) {
228 methodInfos[i] = (MethodInfo) values[i];
229 }
230 return methodInfos;
231 }
232
233 /***
234 * Returns a field info by its hash.
235 *
236 * @param hash
237 * @return
238 */
239 public FieldInfo getField(final int hash) {
240 return (FieldInfo) m_fields.get(hash);
241 }
242
243 /***
244 * Returns a list with all the field info.
245 *
246 * @return the field info
247 */
248 public FieldInfo[] getFields() {
249 Object[] values = m_fields.getValues();
250 FieldInfo[] fieldInfos = new FieldInfo[values.length];
251 for (int i = 0; i < values.length; i++) {
252 fieldInfos[i] = (FieldInfo) values[i];
253 }
254 return fieldInfos;
255 }
256
257 /***
258 * Returns the interfaces.
259 *
260 * @return the interfaces
261 */
262 public ClassInfo[] getInterfaces() {
263 if (m_interfaces == null) {
264 Class[] interfaces = m_class.getInterfaces();
265 m_interfaces = new ClassInfo[interfaces.length];
266 for (int i = 0; i < interfaces.length; i++) {
267 Class anInterface = interfaces[i];
268 ClassInfo classInfo = JavaClassInfo.getClassInfo(anInterface);
269 m_interfaces[i] = classInfo;
270 if (!m_classInfoRepository.hasClassInfo(anInterface.getName())) {
271 m_classInfoRepository.addClassInfo(classInfo);
272 }
273 }
274 }
275 return m_interfaces;
276 }
277
278 /***
279 * Returns the super class.
280 *
281 * @return the super class
282 */
283 public ClassInfo getSuperClass() {
284 if (m_superClass == null) {
285 Class superclass = m_class.getSuperclass();
286 if (superclass != null) {
287 if (m_classInfoRepository.hasClassInfo(superclass.getName())) {
288 m_superClass = m_classInfoRepository.getClassInfo(superclass.getName());
289 } else {
290 m_superClass = JavaClassInfo.getClassInfo(superclass);
291 m_classInfoRepository.addClassInfo(m_superClass);
292 }
293 }
294 }
295 return m_superClass;
296 }
297
298 /***
299 * Returns the component type if array type else null.
300 *
301 * @return the component type
302 */
303 public ClassInfo getComponentType() {
304 if (isArray() && (m_componentType == null)) {
305 Class componentType = m_class.getComponentType();
306 if (m_classInfoRepository.hasClassInfo(componentType.getName())) {
307 m_componentType = m_classInfoRepository.getClassInfo(componentType.getName());
308 } else {
309 m_componentType = JavaClassInfo.getClassInfo(componentType);
310 m_classInfoRepository.addClassInfo(m_componentType);
311 }
312 }
313 return m_componentType;
314 }
315
316 /***
317 * Is the class an interface.
318 *
319 * @return
320 */
321 public boolean isInterface() {
322 return m_isInterface;
323 }
324
325 /***
326 * Is the class a primitive type.
327 *
328 * @return
329 */
330 public boolean isPrimitive() {
331 return m_isPrimitive;
332 }
333
334 /***
335 * Is the class an array type.
336 *
337 * @return
338 */
339 public boolean isArray() {
340 return m_isArray;
341 }
342
343 /***
344 * Converts an internal Java array type name ([Lblabla) to the a the format used by the expression matcher
345 * (blabla[])
346 *
347 * @param typeName is type name
348 * @return
349 */
350 public static String convertJavaArrayTypeNameToHumanTypeName(final String typeName) {
351 int index = typeName.lastIndexOf('[');
352 if (index != -1) {
353 StringBuffer arrayType = new StringBuffer();
354 if (typeName.endsWith("I")) {
355 arrayType.append("int");
356 } else if (typeName.endsWith("J")) {
357 arrayType.append("long");
358 } else if (typeName.endsWith("S")) {
359 arrayType.append("short");
360 } else if (typeName.endsWith("F")) {
361 arrayType.append("float");
362 } else if (typeName.endsWith("D")) {
363 arrayType.append("double");
364 } else if (typeName.endsWith("Z")) {
365 arrayType.append("boolean");
366 } else if (typeName.endsWith("C")) {
367 arrayType.append("char");
368 } else if (typeName.endsWith("B")) {
369 arrayType.append("byte");
370 } else {
371 arrayType.append(typeName.substring(index + 2, typeName.length() - 1));
372 }
373 for (int i = 0; i < (index + 1); i++) {
374 arrayType.append("[]");
375 }
376 return arrayType.toString();
377 } else {
378 return typeName;
379 }
380 }
381
382 public boolean equals(Object o) {
383 if (this == o) {
384 return true;
385 }
386 if (!(o instanceof ClassInfo)) {
387 return false;
388 }
389 ClassInfo classInfo = (ClassInfo) o;
390 return m_class.getName().toString().equals(classInfo.getName().toString());
391 }
392
393 public int hashCode() {
394 return m_class.getName().toString().hashCode();
395 }
396
397 public String toString() {
398 return getName();
399 }
400 }