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