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