001 package edu.rice.cs.cunit.subAnnot; 002 003 import edu.rice.cs.cunit.classFile.attributes.AMultipleNamedAnnotationsAttributeInfo; 004 import edu.rice.cs.cunit.classFile.attributes.RuntimeVisibleLocalVariableAnnotationsAttributeInfo; 005 import edu.rice.cs.cunit.classFile.attributes.RuntimeVisibleParameterAnnotationsAttributeInfo; 006 007 import java.lang.annotation.Annotation; 008 import java.lang.reflect.*; 009 import java.util.ArrayList; 010 import java.util.HashMap; 011 import java.util.List; 012 import java.util.Map; 013 014 /** 015 * Extended Method class to support annotations with subclassing. 016 * 017 * @author Mathias Ricken 018 */ 019 public class MethodEx extends AAnnotatedElementEx { 020 /** 021 * The java.lang.reflect.Method object that represents the method. 022 */ 023 public final Method java; 024 025 /** 026 * Parameter annotation attribute. 027 */ 028 private RuntimeVisibleParameterAnnotationsAttributeInfo _pai; 029 030 /** 031 * Local variable annotation attribute. 032 */ 033 private RuntimeVisibleLocalVariableAnnotationsAttributeInfo _lvai; 034 035 /** 036 * Create an extended Method instance for the specified method. 037 * @param m method 038 */ 039 public MethodEx(Method m) { 040 this(m, null); 041 } 042 043 /** 044 * Create an extended Method instance for the specified method. 045 * @param m method 046 * @param cl class loader 047 */ 048 public MethodEx(Method m, ClassLoader cl) { 049 super(cl); 050 java = m; 051 findMethodAnnotationsAttributeInfo(m, m.getName(), m.getParameterTypes()); 052 _pai = getParameterAnnotationsAttributeInfo(m, m.getName(), m.getParameterTypes()); 053 _lvai = getLocalVarAnnotationsAttributeInfo(m, m.getName(), m.getParameterTypes()); 054 } 055 056 /** 057 * Return the annotated element. 058 * @return annotated element 059 */ 060 protected AnnotatedElement getAnnotatedElement() { 061 return java; 062 } 063 064 /** 065 * Returns the name of the method represented by this <code>Method</code> object, as a <code>String</code>. 066 * @return name 067 */ 068 public String getName() { 069 return java.getName(); 070 } 071 072 /** 073 * Returns the Java language modifiers for the method represented by this <code>Method</code> object, as an integer. 074 * The <code>Modifier</code> class should be used to decode the modifiers. 075 * @return modifiers 076 * @see java.lang.reflect.Modifier 077 */ 078 public int getModifiers() { 079 return java.getModifiers(); 080 } 081 082 /** 083 * Returns an array of <tt>TypeVariable</tt> objects that represent the type variables declared by the generic 084 * declaration represented by this <tt>GenericDeclaration</tt> object, in declaration order. Returns an array of 085 * length 0 if the underlying generic declaration declares no type variables. 086 * 087 * @return an array of <tt>TypeVariable</tt> objects that represent the type variables declared by this generic 088 * declaration 089 * 090 * @throws java.lang.reflect.GenericSignatureFormatError 091 * if the generic signature of this generic declaration does not conform to the format specified in the 092 * Java Virtual Machine Specification, 3rd edition 093 * @since 1.5 094 */ 095 public TypeVariable<Method>[] getTypeParameters() { 096 return java.getTypeParameters(); 097 } 098 099 /** 100 * Returns a <code>Class</code> object that represents the formal return type of the method represented by this 101 * <code>Method</code> object. 102 * 103 * @return the return type for the method this object represents 104 */ 105 @SuppressWarnings("unchecked") 106 public ClassEx<?> getReturnType() { 107 Class<?> c = java.getReturnType(); 108 return new ClassEx(c, c.getClassLoader()); 109 } 110 111 /** 112 * Returns a <tt>Type</tt> object that represents the formal return type of the method represented by this 113 * <tt>Method</tt> object. 114 * <p/> 115 * <p>If the return type is a parameterized type, the <tt>Type</tt> object returned must accurately reflect the 116 * actual type parameters used in the source code. 117 * <p/> 118 * <p>If the return type is a type variable or a parameterized type, it is created. Otherwise, it is resolved. 119 * 120 * @return a <tt>Type</tt> object that represents the formal return type of the underlying method 121 * 122 * @throws java.lang.reflect.GenericSignatureFormatError 123 * if the generic method signature does not conform to the format specified in the 124 * Java Virtual Machine Specification, 3rd edition 125 * @throws TypeNotPresentException if the underlying method's return type refers to a non-existent type declaration 126 * @throws java.lang.reflect.MalformedParameterizedTypeException 127 * if the underlying method's return typed refers to a parameterized type that 128 * cannot be instantiated for any reason 129 * @since 1.5 130 */ 131 public Type getGenericReturnType() { 132 return java.getGenericReturnType(); 133 } 134 135 /** 136 * Returns an array of <code>Class</code> objects that represent the formal parameter types, in declaration order, 137 * of the method represented by this <code>Method</code> object. Returns an array of length 0 if the underlying 138 * method takes no parameters. 139 * 140 * @return the parameter types for the method this object represents 141 */ 142 @SuppressWarnings("unchecked") 143 public ClassEx[] getParameterTypes() { 144 List<ClassEx> list = new ArrayList<ClassEx>(); 145 for(Class c: java.getParameterTypes()) { 146 list.add(new ClassEx(c, c.getClassLoader())); 147 } 148 return list.toArray(new ClassEx[list.size()]); 149 150 } 151 152 /** 153 * Returns an array of <tt>Type</tt> objects that represent the formal parameter types, in declaration order, of the 154 * method represented by this <tt>Method</tt> object. Returns an array of length 0 if the underlying method takes no 155 * parameters. 156 * <p/> 157 * <p>If a formal parameter type is a parameterized type, the <tt>Type</tt> object returned for it must accurately 158 * reflect the actual type parameters used in the source code. 159 * <p/> 160 * <p>If a formal parameter type is a type variable or a parameterized type, it is created. Otherwise, it is 161 * resolved. 162 * 163 * @return an array of Types that represent the formal parameter types of the underlying method, in declaration 164 * order 165 * 166 * @throws java.lang.reflect.GenericSignatureFormatError 167 * if the generic method signature does not conform to the format specified in the 168 * Java Virtual Machine Specification, 3rd edition 169 * @throws TypeNotPresentException if any of the parameter types of the underlying method refers to a non-existent 170 * type declaration 171 * @throws java.lang.reflect.MalformedParameterizedTypeException 172 * if any of the underlying method's parameter types refer to a parameterized type 173 * that cannot be instantiated for any reason 174 * @since 1.5 175 */ 176 public Type[] getGenericParameterTypes() { 177 return java.getGenericParameterTypes(); 178 } 179 180 /** 181 * Returns an array of <code>Class</code> objects that represent the types of the exceptions declared to be thrown 182 * by the underlying method represented by this <code>Method</code> object. Returns an array of length 0 if the 183 * method declares no exceptions in its <code>throws</code> clause. 184 * 185 * @return the exception types declared as being thrown by the method this object represents 186 */ 187 @SuppressWarnings("unchecked") 188 public ClassEx[] getExceptionTypes() { 189 List<ClassEx> list = new ArrayList<ClassEx>(); 190 for(Class c: java.getExceptionTypes()) { 191 list.add(new ClassEx(c, c.getClassLoader())); 192 } 193 return list.toArray(new ClassEx[list.size()]); 194 } 195 196 /** 197 * Returns an array of <tt>Type</tt> objects that represent the exceptions declared to be thrown by this 198 * <tt>Method</tt> object. Returns an array of length 0 if the underlying method declares no exceptions in its 199 * <tt>throws</tt> clause. 200 * <p/> 201 * <p>If an exception type is a parameterized type, the <tt>Type</tt> object returned for it must accurately 202 * reflect the actual type parameters used in the source code. 203 * <p/> 204 * <p>If an exception type is a type variable or a parameterized type, it is created. Otherwise, it is resolved. 205 * 206 * @return an array of Types that represent the exception types thrown by the underlying method 207 * 208 * @throws java.lang.reflect.GenericSignatureFormatError 209 * if the generic method signature does not conform to the format specified in the 210 * Java Virtual Machine Specification, 3rd edition 211 * @throws TypeNotPresentException if the underlying method's <tt>throws</tt> clause refers to a non-existent type 212 * declaration 213 * @throws java.lang.reflect.MalformedParameterizedTypeException 214 * if the underlying method's <tt>throws</tt> clause refers to a parameterized 215 * type that cannot be instantiated for any reason 216 * @since 1.5 217 */ 218 public Type[] getGenericExceptionTypes() { 219 return java.getGenericExceptionTypes(); 220 } 221 222 /** 223 * Compares this <code>Method</code> against the specified object. Returns true if the objects are the same. Two 224 * <code>Methods</code> are the same if they were declared by the same class and have the same name and formal 225 * parameter types and return type. 226 */ 227 public boolean equals(Object obj) { 228 return (obj!=null)&&(obj.getClass().equals(this.getClass()) && (java.equals(obj))); 229 } 230 231 /** 232 * Returns a hashcode for this <code>Method</code>. The hashcode is computed as the exclusive-or of the hashcodes 233 * for the underlying method's declaring class name and the method's name. 234 */ 235 public int hashCode() { 236 return java.hashCode(); 237 } 238 239 /** 240 * Returns a string describing this <code>Method</code>. The string is formatted as the method access modifiers, if 241 * any, followed by the method return type, followed by a space, followed by the class declaring the method, 242 * followed by a period, followed by the method name, followed by a parenthesized, comma-separated list of the 243 * method's formal parameter types. If the method throws checked exceptions, the parameter list is followed by a 244 * space, followed by the word throws followed by a comma-separated list of the thrown exception types. For 245 * example: 246 * <pre> 247 * public boolean java.lang.Object.equals(java.lang.Object) 248 * </pre> 249 * <p/> 250 * <p>The access modifiers are placed in canonical order as specified by "The Java Language Specification". This is 251 * <tt>public</tt>, <tt>protected</tt> or <tt>private</tt> first, and then other modifiers in the following order: 252 * <tt>abstract</tt>, <tt>static</tt>, <tt>final</tt>, <tt>synchronized</tt> <tt>native</tt>. 253 */ 254 public String toString() { 255 return java.toString(); 256 } 257 258 /** 259 * Returns a string describing this <code>Method</code>, including type parameters. The string is formatted as the 260 * method access modifiers, if any, followed by an angle-bracketed comma-separated list of the method's type 261 * parameters, if any, followed by the method's generic return type, followed by a space, followed by the class 262 * declaring the method, followed by a period, followed by the method name, followed by a parenthesized, 263 * comma-separated list of the method's generic formal parameter types. A space is used to separate access modifiers 264 * from one another and from the type parameters or return type. If there are no type parameters, the type 265 * parameter list is elided; if the type parameter list is present, a space separates the list from the class name. 266 * If the method is declared to throw exceptions, the parameter list is followed by a space, followed by the word 267 * throws followed by a comma-separated list of the generic thrown exception types. If there are no type parameters, 268 * the type parameter list is elided. 269 * <p/> 270 * <p>The access modifiers are placed in canonical order as specified by "The Java Language Specification". This is 271 * <tt>public</tt>, <tt>protected</tt> or <tt>private</tt> first, and then other modifiers in the following order: 272 * <tt>abstract</tt>, <tt>static</tt>, <tt>final</tt>, <tt>synchronized</tt> <tt>native</tt>. 273 * 274 * @return a string describing this <code>Method</code>, include type parameters 275 * 276 * @since 1.5 277 */ 278 public String toGenericString() { 279 return java.toGenericString(); 280 } 281 282 /** 283 * Invokes the underlying method represented by this <code>Method</code> object, on the specified object with the 284 * specified parameters. Individual parameters are automatically unwrapped to match primitive formal parameters, and 285 * both primitive and reference parameters are subject to method invocation conversions as necessary. 286 * <p/> 287 * <p>If the underlying method is static, then the specified <code>obj</code> argument is ignored. It may be null. 288 * <p/> 289 * <p>If the number of formal parameters required by the underlying method is 0, the supplied <code>args</code> 290 * array may be of length 0 or null. 291 * <p/> 292 * <p>If the underlying method is an instance method, it is invoked using dynamic method lookup as documented in The 293 * Java Language Specification, Second Edition, section 15.12.4.4; in particular, overriding based on the runtime 294 * type of the target object will occur. 295 * <p/> 296 * <p>If the underlying method is static, the class that declared the method is initialized if it has not already 297 * been initialized. 298 * <p/> 299 * <p>If the method completes normally, the value it returns is returned to the caller of invoke; if the value has a 300 * primitive type, it is first appropriately wrapped in an object. However, if the value has the type of an array of 301 * a primitive type, the elements of the array are <i>not</i> wrapped in objects; in other words, an array of 302 * primitive type is returned. If the underlying method return type is void, the invocation returns null. 303 * 304 * @param obj the object the underlying method is invoked from 305 * @param args the arguments used for the method call 306 * 307 * @return the result of dispatching the method represented by this object on <code>obj</code> with parameters 308 * <code>args</code> 309 * 310 * @throws IllegalAccessException if this <code>Method</code> object enforces Java language access control and 311 * the underlying method is inaccessible. 312 * @throws IllegalArgumentException if the method is an instance method and the specified object argument is not 313 * an instance of the class or interface declaring the underlying method (or of 314 * a subclass or implementor thereof); if the number of actual and formal 315 * parameters differ; if an unwrapping conversion for primitive arguments fails; 316 * or if, after possible unwrapping, a parameter value cannot be converted to 317 * the corresponding formal parameter type by a method invocation conversion. 318 * @throws java.lang.reflect.InvocationTargetException 319 * if the underlying method throws an exception. 320 * @throws NullPointerException if the specified object is null and the method is an instance method. 321 * @throws ExceptionInInitializerError if the initialization provoked by this method fails. 322 */ 323 public Object invoke(Object obj, Object... args) throws IllegalAccessException, IllegalArgumentException, 324 InvocationTargetException { 325 return java.invoke(obj, args); 326 } 327 328 /** 329 * Returns <tt>true</tt> if this method is a bridge method; returns <tt>false</tt> otherwise. 330 * 331 * @return true if and only if this method is a bridge method as defined by the Java Language Specification. 332 * 333 * @since 1.5 334 */ 335 public boolean isBridge() { 336 return java.isBridge(); 337 } 338 339 /** 340 * Returns <tt>true</tt> if this method was declared to take a variable number of arguments; returns <tt>false</tt> 341 * otherwise. 342 * 343 * @return <tt>true</tt> if an only if this method was declared to take a variable number of arguments. 344 * 345 * @since 1.5 346 */ 347 public boolean isVarArgs() { 348 return java.isVarArgs(); 349 } 350 351 /** 352 * Returns <tt>true</tt> if this method is a synthetic method; returns <tt>false</tt> otherwise. 353 * 354 * @return true if and only if this method is a synthetic method as defined by the Java Language Specification. 355 * 356 * @since 1.5 357 */ 358 public boolean isSynthetic() { 359 return java.isSynthetic(); 360 } 361 362 /** 363 * Returns the default value for the annotation member represented by this <tt>Method</tt> instance. If the member 364 * is of a primitive type, an instance of the corresponding wrapper type is returned. Returns null if no default is 365 * associated with the member, or if the method instance does not represent a declared member of an annotation 366 * type. 367 * 368 * @return the default value for the annotation member represented by this <tt>Method</tt> instance. 369 * 370 * @throws TypeNotPresentException if the annotation is of type {@link Class} and no definition can be found for the 371 * default class value. 372 * @since 1.5 373 */ 374 public Object getDefaultValue() { 375 return java.getDefaultValue(); 376 } 377 378 /** 379 * Returns an array of arrays that represent the annotations on the formal parameters, in declaration order, of the 380 * method represented by this <tt>Method</tt> object. (Returns an array of length zero if the underlying method is 381 * parameterless. If the method has one or more parameters, a nested array of length zero is returned for each 382 * parameter with no annotations.) The annotation objects contained in the returned arrays are serializable. The 383 * caller of this method is free to modify the returned arrays; it will have no effect on the arrays returned to 384 * other callers. 385 * 386 * @return an array of arrays that represent the annotations on the formal parameters, in declaration order, of the 387 * method represented by this Method object 388 * 389 * @since 1.5 390 */ 391 public Annotation[][] getParameterAnnotations() { 392 Annotation[][] ann = java.getParameterAnnotations(); 393 Annotation[][] out = new Annotation[ann.length][]; 394 for(int i=0; i<ann.length; ++i) { 395 out[i] = new Annotation[ann[i].length]; 396 if (_pai!=null) { 397 for(int j=0; j<ann[i].length; ++j) { 398 out[i][j] = (Annotation)Proxy.newProxyInstance(ann[i][j].annotationType().getClassLoader(), 399 new Class[]{ann[i][j].annotationType()}, 400 new AnnotationDynamicProxyHandler(ann[i][j].annotationType(), 401 _pai.getEntityAnnotations().get(i)[j])); 402 } 403 } 404 } 405 return out; 406 } 407 408 /** 409 * Returns a map from local variable names to arrays of annotations associated with them. 410 * @return map from local variable name to arrays of annotations 411 */ 412 @SuppressWarnings("unchecked") 413 public Map<String,Annotation[]> getLocalVariableAnnotations() { 414 Map<String,Annotation[]> out = new HashMap<String,Annotation[]>(); 415 if (_lvai!=null) { 416 for(AMultipleNamedAnnotationsAttributeInfo.NamedAnnotationsRecord nar: _lvai.getEntityAnnotations()) { 417 String name = nar.getName().toString(); 418 Annotation[] arr = new Annotation[nar.getAnnotations().length]; 419 for(int i=0; i<nar.getAnnotations().length; ++i) { 420 String t = nar.getAnnotations()[i].getType().replace('/','.').replace('$', '.'); 421 // TODO: check for arrays of annotations 422 if ((t.length()==0) || (t.charAt(0)!='L')) { 423 throw new ClassFormatError("Unexpected type name for annotation: "+t); 424 } 425 t = t.substring(1,t.length()-1); 426 try { 427 Class c = Class.forName(t); 428 arr[i] = (Annotation)Proxy.newProxyInstance(c.getClassLoader(), 429 new Class[]{c}, 430 new AnnotationDynamicProxyHandler(c, 431 nar.getAnnotations()[i])); 432 } 433 catch(ClassNotFoundException e) { 434 throw new ClassFormatError("Could not find class "+t); 435 } 436 } 437 out.put(name,arr); 438 } 439 } 440 return out; 441 } 442 }