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 }