1 // Method.java - Represent method of class or interface. 2 3 /* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2006, 2007 Free Software Foundation 4 5 This file is part of libgcj. 6 7 This software is copyrighted work licensed under the terms of the 8 Libgcj License. Please consult the file "LIBGCJ_LICENSE" for 9 details. */ 10 11 package java.lang.reflect; 12 13 import gnu.gcj.RawData; 14 import gnu.java.lang.reflect.MethodSignatureParser; 15 import java.lang.annotation.Annotation; 16 17 /** 18 * The Method class represents a member method of a class. It also allows 19 * dynamic invocation, via reflection. This works for both static and 20 * instance methods. Invocation on Method objects knows how to do 21 * widening conversions, but throws {@link IllegalArgumentException} if 22 * a narrowing conversion would be necessary. You can query for information 23 * on this Method regardless of location, but invocation access may be limited 24 * by Java language access controls. If you can't do it in the compiler, you 25 * can't normally do it here either.<p> 26 * 27 * <B>Note:</B> This class returns and accepts types as Classes, even 28 * primitive types; there are Class types defined that represent each 29 * different primitive type. They are <code>java.lang.Boolean.TYPE, 30 * java.lang.Byte.TYPE,</code>, also available as <code>boolean.class, 31 * byte.class</code>, etc. These are not to be confused with the 32 * classes <code>java.lang.Boolean, java.lang.Byte</code>, etc., which are 33 * real classes.<p> 34 * 35 * Also note that this is not a serializable class. It is entirely feasible 36 * to make it serializable using the Externalizable interface, but this is 37 * on Sun, not me. 38 * 39 * @author John Keiser 40 * @author Eric Blake <ebb9@email.byu.edu> 41 * @author Tom Tromey <tromey@redhat.com> 42 * @see Member 43 * @see Class 44 * @see java.lang.Class#getMethod(String,Class[]) 45 * @see java.lang.Class#getDeclaredMethod(String,Class[]) 46 * @see java.lang.Class#getMethods() 47 * @see java.lang.Class#getDeclaredMethods() 48 * @since 1.1 49 * @status updated to 1.4 50 */ 51 public final class Method 52 extends AccessibleObject implements Member, GenericDeclaration 53 { 54 static final int METHOD_MODIFIERS 55 = Modifier.ABSTRACT | Modifier.FINAL | Modifier.NATIVE 56 | Modifier.PRIVATE | Modifier.PROTECTED | Modifier.PUBLIC 57 | Modifier.STATIC | Modifier.STRICT | Modifier.SYNCHRONIZED; 58 59 /** 60 * This class is uninstantiable. 61 */ Method()62 private Method () 63 { 64 } 65 66 /** 67 * Gets the class that declared this method, or the class where this method 68 * is a non-inherited member. 69 * @return the class that declared this member 70 */ getDeclaringClass()71 public Class<?> getDeclaringClass() 72 { 73 return declaringClass; 74 } 75 76 /** 77 * Gets the name of this method. 78 * @return the name of this method 79 */ getName()80 public native String getName (); 81 82 /** 83 * Return the raw modifiers for this method. 84 * @return the method's modifiers 85 */ getModifiersInternal()86 private native int getModifiersInternal(); 87 88 /** 89 * Gets the modifiers this method uses. Use the <code>Modifier</code> 90 * class to interpret the values. A method can only have a subset of the 91 * following modifiers: public, private, protected, abstract, static, 92 * final, synchronized, native, and strictfp. 93 * 94 * @return an integer representing the modifiers to this Member 95 * @see Modifier 96 */ getModifiers()97 public int getModifiers() 98 { 99 return getModifiersInternal() & METHOD_MODIFIERS; 100 } 101 102 /** 103 * Return true if this method is a bridge method. A bridge method 104 * is generated by the compiler in some situations involving 105 * generics and inheritance. 106 * @since 1.5 107 */ isBridge()108 public boolean isBridge() 109 { 110 return (getModifiersInternal() & Modifier.BRIDGE) != 0; 111 } 112 113 /** 114 * Return true if this method is synthetic, false otherwise. 115 * @since 1.5 116 */ isSynthetic()117 public boolean isSynthetic() 118 { 119 return (getModifiersInternal() & Modifier.SYNTHETIC) != 0; 120 } 121 122 /** 123 * Return true if this is a varargs method, that is if 124 * the method takes a variable number of arguments. 125 * @since 1.5 126 */ isVarArgs()127 public boolean isVarArgs() 128 { 129 return (getModifiersInternal() & Modifier.VARARGS) != 0; 130 } 131 132 /** 133 * Gets the return type of this method. 134 * @return the type of this method 135 */ getReturnType()136 public Class<?> getReturnType () 137 { 138 if (return_type == null) 139 getType(); 140 return return_type; 141 } 142 143 /** 144 * Get the parameter list for this method, in declaration order. If the 145 * method takes no parameters, returns a 0-length array (not null). 146 * 147 * @return a list of the types of the method's parameters 148 */ getParameterTypes()149 public Class<?>[] getParameterTypes () 150 { 151 if (parameter_types == null) 152 getType(); 153 return (Class<?>[]) parameter_types.clone(); 154 } 155 156 // Just like getParameterTypes, but don't clone the array. 157 // Package private for use by VMProxy. internalGetParameterTypes()158 final Class<?>[] internalGetParameterTypes () 159 { 160 if (parameter_types == null) 161 getType(); 162 return (Class<?>[]) parameter_types; 163 } 164 165 /** 166 * Get the exception types this method says it throws, in no particular 167 * order. If the method has no throws clause, returns a 0-length array 168 * (not null). 169 * 170 * @return a list of the types in the method's throws clause 171 */ getExceptionTypes()172 public Class<?>[] getExceptionTypes () 173 { 174 if (exception_types == null) 175 getType(); 176 return (Class<?>[]) exception_types.clone(); 177 } 178 179 // Just like getExceptionTypes, but don't clone the array. 180 // Package private for use by VMProxy. internalGetExceptionTypes()181 final Class<?>[] internalGetExceptionTypes () 182 { 183 if (exception_types == null) 184 getType(); 185 return (Class<?>[]) exception_types; 186 } 187 188 /** 189 * Compare two objects to see if they are semantically equivalent. 190 * Two Methods are semantically equivalent if they have the same declaring 191 * class, name, and parameter list. This ignores different exception 192 * clauses or return types. 193 * 194 * @param o the object to compare to 195 * @return <code>true</code> if they are equal; <code>false</code> if not 196 */ equals(Object obj)197 public boolean equals (Object obj) 198 { 199 if (! (obj instanceof Method)) 200 return false; 201 Method m = (Method) obj; 202 return declaringClass == m.declaringClass && offset == m.offset; 203 } 204 205 /** 206 * Get the hash code for the Method. The Method hash code is the hash code 207 * of its name XOR'd with the hash code of its class name. 208 * 209 * @return the hash code for the object 210 */ hashCode()211 public int hashCode() 212 { 213 return getDeclaringClass().getName().hashCode() ^ getName().hashCode(); 214 } 215 216 /** 217 * Get a String representation of the Method. A Method's String 218 * representation is "<modifiers> <returntype> 219 * <methodname>(<paramtypes>) throws <exceptions>", where 220 * everything after ')' is omitted if there are no exceptions.<br> Example: 221 * <code>public static int run(java.lang.Runnable,int)</code> 222 * 223 * @return the String representation of the Method 224 */ toString()225 public String toString() 226 { 227 if (parameter_types == null) 228 getType (); 229 230 StringBuffer b = new StringBuffer (); 231 int mods = getModifiers(); 232 if (mods != 0) 233 { 234 Modifier.toString(mods, b); 235 b.append(" "); 236 } 237 appendClassName (b, return_type); 238 b.append(" "); 239 appendClassName (b, declaringClass); 240 b.append("."); 241 b.append(getName()); 242 b.append("("); 243 for (int i = 0; i < parameter_types.length; ++i) 244 { 245 appendClassName (b, parameter_types[i]); 246 if (i < parameter_types.length - 1) 247 b.append(","); 248 } 249 b.append(")"); 250 if (exception_types.length > 0) 251 { 252 b.append(" throws "); 253 for (int i = 0; i < exception_types.length; ++i) 254 { 255 appendClassName (b, exception_types[i]); 256 if (i < exception_types.length - 1) 257 b.append(","); 258 } 259 } 260 return b.toString(); 261 } 262 toGenericString()263 public String toGenericString() 264 { 265 // 128 is a reasonable buffer initial size for constructor 266 StringBuilder sb = new StringBuilder(128); 267 Modifier.toString(getModifiers(), sb).append(' '); 268 Constructor.addTypeParameters(sb, getTypeParameters()); 269 sb.append(getGenericReturnType()).append(' '); 270 sb.append(getDeclaringClass().getName()).append('.'); 271 sb.append(getName()).append('('); 272 Type[] types = getGenericParameterTypes(); 273 if (types.length > 0) 274 { 275 sb.append(types[0]); 276 for (int i = 1; i < types.length; i++) 277 sb.append(',').append(types[i]); 278 } 279 sb.append(')'); 280 types = getGenericExceptionTypes(); 281 if (types.length > 0) 282 { 283 sb.append(" throws ").append(types[0]); 284 for (int i = 1; i < types.length; i++) 285 sb.append(',').append(types[i]); 286 } 287 return sb.toString(); 288 } 289 290 /** 291 * Invoke the method. Arguments are automatically unwrapped and widened, 292 * and the result is automatically wrapped, if needed.<p> 293 * 294 * If the method is static, <code>o</code> will be ignored. Otherwise, 295 * the method uses dynamic lookup as described in JLS 15.12.4.4. You cannot 296 * mimic the behavior of nonvirtual lookup (as in super.foo()). This means 297 * you will get a <code>NullPointerException</code> if <code>o</code> is 298 * null, and an <code>IllegalArgumentException</code> if it is incompatible 299 * with the declaring class of the method. If the method takes 0 arguments, 300 * you may use null or a 0-length array for <code>args</code>.<p> 301 * 302 * Next, if this Method enforces access control, your runtime context is 303 * evaluated, and you may have an <code>IllegalAccessException</code> if 304 * you could not acces this method in similar compiled code. If the method 305 * is static, and its class is uninitialized, you trigger class 306 * initialization, which may end in a 307 * <code>ExceptionInInitializerError</code>.<p> 308 * 309 * Finally, the method is invoked. If it completes normally, the return value 310 * will be null for a void method, a wrapped object for a primitive return 311 * method, or the actual return of an Object method. If it completes 312 * abruptly, the exception is wrapped in an 313 * <code>InvocationTargetException</code>. 314 * 315 * @param o the object to invoke the method on 316 * @param args the arguments to the method 317 * @return the return value of the method, wrapped in the appropriate 318 * wrapper if it is primitive 319 * @throws IllegalAccessException if the method could not normally be called 320 * by the Java code (i.e. it is not public) 321 * @throws IllegalArgumentException if the number of arguments is incorrect; 322 * if the arguments types are wrong even with a widening conversion; 323 * or if <code>o</code> is not an instance of the class or interface 324 * declaring this method 325 * @throws InvocationTargetException if the method throws an exception 326 * @throws NullPointerException if <code>o</code> is null and this field 327 * requires an instance 328 * @throws ExceptionInInitializerError if accessing a static method triggered 329 * class initialization, which then failed 330 */ invoke(Object obj, Object... args)331 public native Object invoke (Object obj, Object... args) 332 throws IllegalAccessException, IllegalArgumentException, 333 InvocationTargetException; 334 335 /** 336 * Returns an array of <code>TypeVariable</code> objects that represents 337 * the type variables declared by this constructor, in declaration order. 338 * An array of size zero is returned if this class has no type 339 * variables. 340 * 341 * @return the type variables associated with this class. 342 * @throws GenericSignatureFormatError if the generic signature does 343 * not conform to the format specified in the Virtual Machine 344 * specification, version 3. 345 * @since 1.5 346 */ getTypeParameters()347 public TypeVariable<Method>[] getTypeParameters() 348 { 349 String sig = getSignature(); 350 if (sig == null) 351 return new TypeVariable[0]; 352 MethodSignatureParser p = new MethodSignatureParser(this, sig); 353 return p.getTypeParameters(); 354 } 355 356 /** 357 * Return the String in the Signature attribute for this method. If there 358 * is no Signature attribute, return null. 359 */ getSignature()360 private native String getSignature(); 361 362 /** 363 * Returns an array of <code>Type</code> objects that represents 364 * the exception types declared by this method, in declaration order. 365 * An array of size zero is returned if this method declares no 366 * exceptions. 367 * 368 * @return the exception types declared by this method. 369 * @throws GenericSignatureFormatError if the generic signature does 370 * not conform to the format specified in the Virtual Machine 371 * specification, version 3. 372 * @since 1.5 373 */ getGenericExceptionTypes()374 public Type[] getGenericExceptionTypes() 375 { 376 String sig = getSignature(); 377 if (sig == null) 378 return getExceptionTypes(); 379 MethodSignatureParser p = new MethodSignatureParser(this, sig); 380 return p.getGenericExceptionTypes(); 381 } 382 383 /** 384 * Returns an array of <code>Type</code> objects that represents 385 * the parameter list for this method, in declaration order. 386 * An array of size zero is returned if this method takes no 387 * parameters. 388 * 389 * @return a list of the types of the method's parameters 390 * @throws GenericSignatureFormatError if the generic signature does 391 * not conform to the format specified in the Virtual Machine 392 * specification, version 3. 393 * @since 1.5 394 */ getGenericParameterTypes()395 public Type[] getGenericParameterTypes() 396 { 397 String sig = getSignature(); 398 if (sig == null) 399 return getParameterTypes(); 400 MethodSignatureParser p = new MethodSignatureParser(this, sig); 401 return p.getGenericParameterTypes(); 402 } 403 404 /** 405 * Returns the return type of this method. 406 * 407 * @return the return type of this method 408 * @throws GenericSignatureFormatError if the generic signature does 409 * not conform to the format specified in the Virtual Machine 410 * specification, version 3. 411 * @since 1.5 412 */ getGenericReturnType()413 public Type getGenericReturnType() 414 { 415 String sig = getSignature(); 416 if (sig == null) 417 return getReturnType(); 418 MethodSignatureParser p = new MethodSignatureParser(this, sig); 419 return p.getGenericReturnType(); 420 } 421 422 /** 423 * If this method is an annotation method, returns the default 424 * value for the method. If there is no default value, or if the 425 * method is not a member of an annotation type, returns null. 426 * Primitive types are wrapped. 427 * 428 * @throws TypeNotPresentException if the method returns a Class, 429 * and the class cannot be found 430 * 431 * @since 1.5 432 */ getDefaultValue()433 public native Object getDefaultValue(); 434 getAnnotation(Class<T> annoClass)435 public <T extends Annotation> T getAnnotation(Class<T> annoClass) 436 { 437 Annotation[] annos = getDeclaredAnnotations(); 438 for (int i = 0; i < annos.length; ++i) 439 if (annos[i].annotationType() == annoClass) 440 return (T) annos[i]; 441 return null; 442 } 443 getDeclaredAnnotations()444 public Annotation[] getDeclaredAnnotations() 445 { 446 Annotation[] result = getDeclaredAnnotationsInternal(); 447 if (result == null) 448 result = new Annotation[0]; 449 return result; 450 } 451 getParameterAnnotations()452 public Annotation[][] getParameterAnnotations() 453 { 454 // FIXME: should check that we have the right number 455 // of parameters ...? 456 Annotation[][] result = getParameterAnnotationsInternal(); 457 if (result == null) 458 result = new Annotation[0][0]; 459 return result; 460 } 461 getDeclaredAnnotationsInternal()462 private native Annotation[] getDeclaredAnnotationsInternal(); getParameterAnnotationsInternal()463 private native Annotation[][] getParameterAnnotationsInternal(); 464 getType()465 private native void getType (); 466 467 // Append a class name to a string buffer. We try to print the 468 // fully-qualified name, the way that a Java programmer would expect 469 // it to be written. Weirdly, Class has no appropriate method for 470 // this. appendClassName(StringBuffer buf, Class k)471 static void appendClassName (StringBuffer buf, Class k) 472 { 473 if (k.isArray ()) 474 { 475 appendClassName (buf, k.getComponentType ()); 476 buf.append ("[]"); 477 } 478 else 479 { 480 // This is correct for primitive and reference types. Really 481 // we'd like `Main$Inner' to be printed as `Main.Inner', I 482 // think, but that is a pain. 483 buf.append (k.getName ()); 484 } 485 } 486 487 // Declaring class. 488 private Class declaringClass; 489 490 // Exception types. 491 Class[] exception_types; 492 // Name cache. (Initially null.) 493 private String name; 494 // Parameter types. 495 Class[] parameter_types; 496 // Return type. 497 Class return_type; 498 499 // Offset in bytes from the start of declaringClass's methods array. 500 private int offset; 501 } 502