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