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