001: /**************************************************************************************
002: * Copyright (c) Jonas BonŽr, Alexandre Vasseur. All rights reserved. *
003: * http://aspectwerkz.codehaus.org *
004: * ---------------------------------------------------------------------------------- *
005: * The software in this package is published under the terms of the LGPL license *
006: * a copy of which has been included with this distribution in the license.txt file. *
007: **************************************************************************************/package org.codehaus.aspectwerkz.reflect.impl.java;
008:
009: import gnu.trove.TIntObjectHashMap;
010: import org.codehaus.aspectwerkz.annotation.Annotations;
011: import org.codehaus.aspectwerkz.reflect.ClassInfo;
012: import org.codehaus.aspectwerkz.reflect.ConstructorInfo;
013: import org.codehaus.aspectwerkz.reflect.FieldInfo;
014: import org.codehaus.aspectwerkz.reflect.MethodInfo;
015: import org.codehaus.aspectwerkz.reflect.ReflectHelper;
016: import org.codehaus.aspectwerkz.reflect.ReflectHelper;
017: import org.codehaus.aspectwerkz.reflect.StaticInitializationInfo;
018: import org.codehaus.aspectwerkz.reflect.StaticInitializationInfoImpl;
019: import org.codehaus.aspectwerkz.reflect.impl.asm.AsmClassInfo;
020: import org.codehaus.aspectwerkz.transform.TransformationConstants;
021:
022: import java.lang.reflect.Constructor;
023: import java.lang.reflect.Field;
024: import java.lang.reflect.Method;
025: import java.util.List;
026:
027: /**
028: * Implementation of the ClassInfo interface for java.lang.reflect.*.
029: *
030: * @author <a href="mailto:jboner@codehaus.org">Jonas BonŽr </a>
031: */
032: public class JavaClassInfo implements ClassInfo {
033: /**
034: * The class.
035: */
036: // TODO might be safer to wrap this member in a weak ref
037: private final Class m_class;
038:
039: /**
040: * The name of the class.
041: */
042: private String m_name;
043:
044: /**
045: * The signature of the class.
046: */
047: private String m_signature;
048:
049: /**
050: * Is the class an interface.
051: */
052: private boolean m_isInterface = false;
053:
054: /**
055: * Is the class a primitive type.
056: */
057: private boolean m_isPrimitive = false;
058:
059: /**
060: * Is the class of type array.
061: */
062: private boolean m_isArray = false;
063:
064: /**
065: * A list with the <code>ConstructorInfo</code> instances.
066: */
067: private final TIntObjectHashMap m_constructors = new TIntObjectHashMap();
068:
069: /**
070: * A list with the <code>MethodInfo</code> instances.
071: */
072: private final TIntObjectHashMap m_methods = new TIntObjectHashMap();
073:
074: /**
075: * A list with the <code>FieldInfo</code> instances.
076: */
077: private final TIntObjectHashMap m_fields = new TIntObjectHashMap();
078:
079: /**
080: * A list with the interfaces.
081: */
082: private ClassInfo[] m_interfaces = null;
083:
084: /**
085: * The super class.
086: */
087: private ClassInfo m_super Class = null;
088:
089: /**
090: * The annotations.
091: */
092: private List m_annotations = null;
093:
094: /**
095: * The component type if array type.
096: */
097: private ClassInfo m_componentType = null;
098:
099: /**
100: * The class info repository.
101: */
102: private final JavaClassInfoRepository m_classInfoRepository;
103:
104: /**
105: * Lazy, the static initializer info or null if not present
106: */
107: private StaticInitializationInfo m_staticInitializer = null;
108:
109: /**
110: * Creates a new class meta data instance.
111: *
112: * @param klass
113: */
114: JavaClassInfo(final Class klass) {
115: if (klass == null) {
116: throw new IllegalArgumentException("class can not be null");
117: }
118: m_class = klass;
119:
120: m_signature = ReflectHelper.getClassSignature(klass);
121:
122: m_classInfoRepository = JavaClassInfoRepository
123: .getRepository(klass.getClassLoader());
124: m_isInterface = klass.isInterface();
125: if (klass.isPrimitive()) {
126: m_name = klass.getName();
127: m_isPrimitive = true;
128: } else if (klass.getComponentType() != null) {
129: m_name = convertJavaArrayTypeNameToHumanTypeName(klass
130: .getName());
131: m_isArray = true;
132: m_interfaces = new ClassInfo[0];
133: } else {
134: m_name = klass.getName();
135: Method[] methods = m_class.getDeclaredMethods();
136: for (int i = 0; i < methods.length; i++) {
137: Method method = methods[i];
138: m_methods.put(ReflectHelper.calculateHash(method),
139: new JavaMethodInfo(method, this ));
140: }
141: Constructor[] constructors = m_class
142: .getDeclaredConstructors();
143: for (int i = 0; i < constructors.length; i++) {
144: Constructor constructor = constructors[i];
145: m_constructors.put(ReflectHelper
146: .calculateHash(constructor),
147: new JavaConstructorInfo(constructor, this ));
148: }
149: Field[] fields = m_class.getDeclaredFields();
150: for (int i = 0; i < fields.length; i++) {
151: if (fields[i].getName().startsWith(
152: TransformationConstants.ASPECTWERKZ_PREFIX)) {
153: continue;
154: }
155: Field field = fields[i];
156: m_fields.put(ReflectHelper.calculateHash(field),
157: new JavaFieldInfo(field, this ));
158: }
159: }
160: m_classInfoRepository.addClassInfo(this );
161: }
162:
163: /**
164: * Returns the class info for a specific class.
165: *
166: * @return the class info
167: */
168: public static ClassInfo getClassInfo(final Class clazz) {
169: JavaClassInfoRepository repository = JavaClassInfoRepository
170: .getRepository(clazz.getClassLoader());
171: ClassInfo classInfo = repository.getClassInfo(clazz.getName());
172: if (classInfo == null) {
173: classInfo = new JavaClassInfo(clazz);
174: }
175: return classInfo;
176: }
177:
178: /**
179: * Returns the annotations infos.
180: *
181: * @return the annotations infos
182: */
183: public List getAnnotations() {
184: if (m_annotations == null) {
185: // TODO this means that JavaClassInfo is always using AsmClassInfo to get that annotations
186: // TODO should optimize for Java5
187: m_annotations = Annotations.getAnnotationInfos(m_class);
188: }
189: return m_annotations;
190: }
191:
192: /**
193: * Returns the name of the class.
194: *
195: * @return the name of the class
196: */
197: public String getName() {
198: return m_name.replace('/', '.');
199: }
200:
201: /**
202: * Checks if the class has a static initalizer.
203: *
204: * @return
205: */
206: public boolean hasStaticInitializer() {
207: ClassInfo classInfo = AsmClassInfo.getClassInfo(getName(),
208: getClassLoader());
209: return classInfo.hasStaticInitializer();
210: }
211:
212: /**
213: * Returns the static initializer info of the current underlying class if any.
214: *
215: * @see org.codehaus.aspectwerkz.reflect.ClassInfo#staticInitializer()
216: */
217: public StaticInitializationInfo staticInitializer() {
218: if (hasStaticInitializer() && m_staticInitializer == null) {
219: m_staticInitializer = new StaticInitializationInfoImpl(this );
220: }
221: return m_staticInitializer;
222: }
223:
224: /**
225: * Returns the signature for the element.
226: *
227: * @return the signature for the element
228: */
229: public String getSignature() {
230: return m_signature;
231: }
232:
233: /**
234: * Returns the class modifiers.
235: *
236: * @return the class modifiers
237: */
238: public int getModifiers() {
239: return m_class.getModifiers();
240: }
241:
242: /**
243: * Returns the class loader that loaded this class.
244: *
245: * @return the class loader
246: */
247: public ClassLoader getClassLoader() {
248: return m_class.getClassLoader();
249: }
250:
251: /**
252: * Returns a constructor info by its hash.
253: *
254: * @param hash
255: * @return
256: */
257: public ConstructorInfo getConstructor(final int hash) {
258: ConstructorInfo constructor = (ConstructorInfo) m_constructors
259: .get(hash);
260: if (constructor == null && getSuperclass() != null) {
261: constructor = getSuperclass().getConstructor(hash);
262: }
263: return constructor;
264: }
265:
266: /**
267: * Returns a list with all the constructors info.
268: *
269: * @return the constructors info
270: */
271: public ConstructorInfo[] getConstructors() {
272: Object[] values = m_constructors.getValues();
273: ConstructorInfo[] methodInfos = new ConstructorInfo[values.length];
274: for (int i = 0; i < values.length; i++) {
275: methodInfos[i] = (ConstructorInfo) values[i];
276: }
277: return methodInfos;
278: }
279:
280: /**
281: * Returns a method info by its hash.
282: *
283: * @param hash
284: * @return
285: */
286: public MethodInfo getMethod(final int hash) {
287: MethodInfo method = (MethodInfo) m_methods.get(hash);
288: if (method == null) {
289: for (int i = 0; i < getInterfaces().length; i++) {
290: method = getInterfaces()[i].getMethod(hash);
291: if (method != null) {
292: break;
293: }
294: }
295: }
296: if (method == null && getSuperclass() != null) {
297: method = getSuperclass().getMethod(hash);
298: }
299: return method;
300: }
301:
302: /**
303: * Returns a list with all the methods info.
304: *
305: * @return the methods info
306: */
307: public MethodInfo[] getMethods() {
308: Object[] values = m_methods.getValues();
309: MethodInfo[] methodInfos = new MethodInfo[values.length];
310: for (int i = 0; i < values.length; i++) {
311: methodInfos[i] = (MethodInfo) values[i];
312: }
313: return methodInfos;
314: }
315:
316: /**
317: * Returns a field info by its hash.
318: *
319: * @param hash
320: * @return
321: */
322: public FieldInfo getField(final int hash) {
323: FieldInfo field = (FieldInfo) m_fields.get(hash);
324: if (field == null && getSuperclass() != null) {
325: field = getSuperclass().getField(hash);
326: }
327: return field;
328: }
329:
330: /**
331: * Returns a list with all the field info.
332: *
333: * @return the field info
334: */
335: public FieldInfo[] getFields() {
336: Object[] values = m_fields.getValues();
337: FieldInfo[] fieldInfos = new FieldInfo[values.length];
338: for (int i = 0; i < values.length; i++) {
339: fieldInfos[i] = (FieldInfo) values[i];
340: }
341: return fieldInfos;
342: }
343:
344: /**
345: * Returns the interfaces.
346: *
347: * @return the interfaces
348: */
349: public ClassInfo[] getInterfaces() {
350: if (m_interfaces == null) {
351: Class[] interfaces = m_class.getInterfaces();
352: m_interfaces = new ClassInfo[interfaces.length];
353: for (int i = 0; i < interfaces.length; i++) {
354: Class anInterface = interfaces[i];
355: ClassInfo classInfo = JavaClassInfo
356: .getClassInfo(anInterface);
357: m_interfaces[i] = classInfo;
358: if (!m_classInfoRepository.hasClassInfo(anInterface
359: .getName())) {
360: m_classInfoRepository.addClassInfo(classInfo);
361: }
362: }
363: }
364: return m_interfaces;
365: }
366:
367: /**
368: * Returns the super class.
369: *
370: * @return the super class
371: */
372: public ClassInfo getSuperclass() {
373: if (m_super Class == null) {
374: Class super class = m_class.getSuperclass();
375: if (super class != null) {
376: if (m_classInfoRepository.hasClassInfo(super class
377: .getName())) {
378: m_super Class = m_classInfoRepository
379: .getClassInfo(super class.getName());
380: } else {
381: m_super Class = JavaClassInfo
382: .getClassInfo(super class);
383: m_classInfoRepository.addClassInfo(m_super Class);
384: }
385: }
386: }
387: return m_super Class;
388: }
389:
390: /**
391: * Returns the component type if array type else null.
392: *
393: * @return the component type
394: */
395: public ClassInfo getComponentType() {
396: if (isArray() && (m_componentType == null)) {
397: Class componentType = m_class.getComponentType();
398: if (m_classInfoRepository.hasClassInfo(componentType
399: .getName())) {
400: m_componentType = m_classInfoRepository
401: .getClassInfo(componentType.getName());
402: } else {
403: m_componentType = JavaClassInfo
404: .getClassInfo(componentType);
405: m_classInfoRepository.addClassInfo(m_componentType);
406: }
407: }
408: return m_componentType;
409: }
410:
411: /**
412: * Is the class an interface.
413: *
414: * @return
415: */
416: public boolean isInterface() {
417: return m_isInterface;
418: }
419:
420: /**
421: * Is the class a primitive type.
422: *
423: * @return
424: */
425: public boolean isPrimitive() {
426: return m_isPrimitive;
427: }
428:
429: /**
430: * Is the class an array type.
431: *
432: * @return
433: */
434: public boolean isArray() {
435: return m_isArray;
436: }
437:
438: /**
439: * Converts an internal Java array type name ([Lblabla) to the a the format used by the expression matcher
440: * (blabla[])
441: *
442: * @param typeName is type name
443: * @return
444: */
445: public static String convertJavaArrayTypeNameToHumanTypeName(
446: final String typeName) {
447: int index = typeName.lastIndexOf('[');
448: if (index != -1) {
449: StringBuffer arrayType = new StringBuffer();
450: if (typeName.endsWith("I")) {
451: arrayType.append("int");
452: } else if (typeName.endsWith("J")) {
453: arrayType.append("long");
454: } else if (typeName.endsWith("S")) {
455: arrayType.append("short");
456: } else if (typeName.endsWith("F")) {
457: arrayType.append("float");
458: } else if (typeName.endsWith("D")) {
459: arrayType.append("double");
460: } else if (typeName.endsWith("Z")) {
461: arrayType.append("boolean");
462: } else if (typeName.endsWith("C")) {
463: arrayType.append("char");
464: } else if (typeName.endsWith("B")) {
465: arrayType.append("byte");
466: } else {
467: arrayType.append(typeName.substring(index + 2, typeName
468: .length() - 1));
469: }
470: for (int i = 0; i < (index + 1); i++) {
471: arrayType.append("[]");
472: }
473: return arrayType.toString();
474: } else {
475: return typeName;
476: }
477: }
478:
479: public boolean equals(Object o) {
480: if (this == o) {
481: return true;
482: }
483: if (!(o instanceof ClassInfo)) {
484: return false;
485: }
486: ClassInfo classInfo = (ClassInfo) o;
487: return m_class.getName().toString().equals(
488: classInfo.getName().toString());
489: }
490:
491: public int hashCode() {
492: return m_class.getName().toString().hashCode();
493: }
494:
495: public String toString() {
496: return getName();
497: }
498: }
|