001: /*
002: * @(#)Method.java 1.30 02/08/19
003: *
004: * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: *
026: */
027:
028: package java.lang.reflect;
029:
030: import sun.misc.CVM;
031:
032: /**
033: * A <code>Method</code> provides information about, and access to, a single method
034: * on a class or interface. The reflected method may be a class method
035: * or an instance method (including an abstract method).
036: *
037: * <p>A <code>Method</code> permits widening conversions to occur when matching the
038: * actual parameters to invokewith the underlying method's formal
039: * parameters, but it throws an <code>IllegalArgumentException</code> if a
040: * narrowing conversion would occur.
041: *
042: * @see Member
043: * @see java.lang.Class
044: * @see java.lang.Class#getMethods()
045: * @see java.lang.Class#getMethod(String, Class[])
046: * @see java.lang.Class#getDeclaredMethods()
047: * @see java.lang.Class#getDeclaredMethod(String, Class[])
048: *
049: * @author Nakul Saraiya
050: */
051: public final class Method extends AccessibleObject implements Member {
052:
053: private Class clazz;
054: private int slot;
055: private String name;
056: private Class returnType;
057: private Class[] parameterTypes;
058: private Class[] exceptionTypes;
059: private int modifiers;
060:
061: /**
062: * Constructor. Only the Java Virtual Machine may construct a Method.
063: */
064: private Method() {
065: }
066:
067: /**
068: * Returns the <code>Class</code> object representing the class or interface
069: * that declares the method represented by this <code>Method</code> object.
070: */
071: public Class getDeclaringClass() {
072: return clazz;
073: }
074:
075: /**
076: * Returns the name of the method represented by this <code>Method</code>
077: * object, as a <code>String</code>.
078: */
079: public String getName() {
080: return name;
081: }
082:
083: /**
084: * Returns the Java language modifiers for the method represented
085: * by this <code>Method</code> object, as an integer. The <code>Modifier</code> class should
086: * be used to decode the modifiers.
087: *
088: * @see Modifier
089: */
090: public int getModifiers() {
091: return modifiers;
092: }
093:
094: /**
095: * Returns a <code>Class</code> object that represents the formal return type
096: * of the method represented by this <code>Method</code> object.
097: *
098: * @return the return type for the method this object represents
099: */
100: public Class getReturnType() {
101: return returnType;
102: }
103:
104: /**
105: * Returns an array of <code>Class</code> objects that represent the formal
106: * parameter types, in declaration order, of the method
107: * represented by this <code>Method</code> object. Returns an array of length
108: * 0 if the underlying method takes no parameters.
109: *
110: * @return the parameter types for the method this object
111: * represents
112: */
113: public Class[] getParameterTypes() {
114: return copy(parameterTypes);
115: }
116:
117: /**
118: * Returns an array of <code>Class</code> objects that represent
119: * the types of the exceptions declared to be thrown
120: * by the underlying method
121: * represented by this <code>Method</code> object. Returns an array of length
122: * 0 if the method declares no exceptions in its <code>throws</code> clause.
123: *
124: * @return the exception types declared as being thrown by the
125: * method this object represents
126: */
127: public Class[] getExceptionTypes() {
128: return copy(exceptionTypes);
129: }
130:
131: /**
132: * Compares this <code>Method</code> against the specified object. Returns
133: * true if the objects are the same. Two <code>Methods</code> are the same if
134: * they were declared by the same class and have the same name
135: * and formal parameter types and return type.
136: */
137: public boolean equals(Object obj) {
138: if (obj != null && obj instanceof Method) {
139: Method other = (Method) obj;
140: if ((getDeclaringClass() == other.getDeclaringClass())
141: && (getName().equals(other.getName()))) {
142: /* Avoid unnecessary cloning */
143: Class[] params1 = parameterTypes;
144: Class[] params2 = other.parameterTypes;
145: if (params1.length == params2.length) {
146: for (int i = 0; i < params1.length; i++) {
147: if (params1[i] != params2[i])
148: return false;
149: }
150: return true;
151: }
152: }
153: }
154: return false;
155: }
156:
157: /**
158: * Returns a hashcode for this <code>Method</code>. The hashcode is computed
159: * as the exclusive-or of the hashcodes for the underlying
160: * method's declaring class name and the method's name.
161: */
162: public int hashCode() {
163: return getDeclaringClass().getName().hashCode()
164: ^ getName().hashCode();
165: }
166:
167: /**
168: * Returns a string describing this <code>Method</code>. The string is
169: * formatted as the method access modifiers, if any, followed by
170: * the method return type, followed by a space, followed by the
171: * class declaring the method, followed by a period, followed by
172: * the method name, followed by a parenthesized, comma-separated
173: * list of the method's formal parameter types. If the method
174: * throws checked exceptions, the parameter list is followed by a
175: * space, followed by the word throws followed by a
176: * comma-separated list of the thrown exception types.
177: * For example:
178: * <pre>
179: * public boolean java.lang.Object.equals(java.lang.Object)
180: * </pre>
181: *
182: * <p>The access modifiers are placed in canonical order as
183: * specified by "The Java Language Specification". This is
184: * <tt>public</tt>, <tt>protected</tt> or <tt>private</tt> first,
185: * and then other modifiers in the following order:
186: * <tt>abstract</tt>, <tt>static</tt>, <tt>final</tt>,
187: * <tt>synchronized</tt> <tt>native</tt>.
188: */
189: public String toString() {
190: try {
191: StringBuffer sb = new StringBuffer();
192: int mod = getModifiers();
193: if (mod != 0) {
194: sb.append(Modifier.toString(mod) + " ");
195: }
196: sb.append(Field.getTypeName(getReturnType()) + " ");
197: sb.append(Field.getTypeName(getDeclaringClass()) + ".");
198: sb.append(getName() + "(");
199: Class[] params = parameterTypes; // avoid clone
200: for (int j = 0; j < params.length; j++) {
201: sb.append(Field.getTypeName(params[j]));
202: if (j < (params.length - 1))
203: sb.append(",");
204: }
205: sb.append(")");
206: Class[] exceptions = exceptionTypes; // avoid clone
207: if (exceptions.length > 0) {
208: sb.append(" throws ");
209: for (int k = 0; k < exceptions.length; k++) {
210: sb.append(exceptions[k].getName());
211: if (k < (exceptions.length - 1))
212: sb.append(",");
213: }
214: }
215: return sb.toString();
216: } catch (Exception e) {
217: return "<" + e + ">";
218: }
219: }
220:
221: /** An internal class to be able to distinguish between an
222: IllegalArgumentException because of incorrectly-typed objects in
223: the argument array to Method.invoke() and one thrown by the
224: invoked method. NOTE: do not change the name of this class as it
225: is referenced by name in reflect.c, utils.c and elsewhere. */
226: private static class ArgumentException extends Exception {
227: }
228:
229: /** An internal class to be able to distinguish between an
230: IllegalAccessException because of an invalid attempt to invoke a
231: protected or private method in Method.invoke() and one thrown by
232: the invoked method. NOTE: do not change the name of this class
233: as it is referenced by name in reflect.c, utils.c and
234: elsewhere. */
235: private static class AccessException extends Exception {
236: }
237:
238: /**
239: * Invokes the underlying method represented by this <code>Method</code>
240: * object, on the specified object with the specified parameters.
241: * Individual parameters are automatically unwrapped to match
242: * primitive formal parameters, and both primitive and reference
243: * parameters are subject to method invocation conversions as
244: * necessary.
245: *
246: * <p>If the underlying method is static, then the specified <code>obj</code>
247: * argument is ignored. It may be null.
248: *
249: * <p>If the number of formal parameters required by the underlying method is
250: * 0, the supplied <code>args</code> array may be of length 0 or null.
251: *
252: * <p>If the underlying method is an instance method, it is invoked
253: * using dynamic method lookup as documented in The Java Language
254: * Specification, Second Edition, section 15.12.4.4; in particular,
255: * overriding based on the runtime type of the target object will occur.
256: *
257: * <p>If the underlying method is static, the class that declared
258: * the method is initialized if it has not already been initialized.
259: *
260: * <p>If the method completes normally, the value it returns is
261: * returned to the caller of invoke; if the value has a primitive
262: * type, it is first appropriately wrapped in an object. If the
263: * underlying method return type is void, the invocation returns
264: * null.
265: *
266: * @param obj the object the underlying method is invoked from
267: * @param args the arguments used for the method call
268: * @return the result of dispatching the method represented by
269: * this object on <code>obj</code> with parameters
270: * <code>args</code>
271: *
272: * @exception IllegalAccessException if this <code>Method</code> object
273: * enforces Java language access control and the underlying
274: * method is inaccessible.
275: * @exception IllegalArgumentException if the method is an
276: * instance method and the specified object argument
277: * is not an instance of the class or interface
278: * declaring the underlying method (or of a subclass
279: * or implementor thereof); if the number of actual
280: * and formal parameters differ; if an unwrapping
281: * conversion for primitive arguments fails; or if,
282: * after possible unwrapping, a parameter value
283: * cannot be converted to the corresponding formal
284: * parameter type by a method invocation conversion.
285: * @exception InvocationTargetException if the underlying method
286: * throws an exception.
287: * @exception NullPointerException if the specified object is null
288: * and the method is an instance method.
289: * @exception ExceptionInInitializerError if the initialization
290: * provoked by this method fails.
291: */
292: public Object invoke(Object obj, Object[] args)
293: throws IllegalAccessException, IllegalArgumentException,
294: InvocationTargetException {
295: Object retval = null;
296:
297: if ((obj == null) && ((getModifiers() & Modifier.STATIC) == 0)) {
298: throw new NullPointerException("Method.invoke()");
299: }
300:
301: /* Null pointer is acceptable for args if no arguments to method */
302: if (parameterTypes.length == 0) {
303: if ((args != null) && (args.length != 0))
304: throw new IllegalArgumentException(
305: "wrong number of arguments");
306: } else {
307: if ((args == null)
308: || (args.length != parameterTypes.length))
309: throw new IllegalArgumentException(
310: "wrong number of arguments");
311: }
312:
313: CVM.setContextArtificial();
314:
315: /* NOTE: Consider reordering for more efficient
316: testing for common cases. */
317: try {
318: if (returnType == Void.TYPE) {
319: invokeV(obj, args);
320: } else if (returnType == Boolean.TYPE) {
321: retval = new Boolean(invokeZ(obj, args));
322: } else if (returnType == Character.TYPE) {
323: retval = new Character(invokeC(obj, args));
324: } else if (returnType == Float.TYPE) {
325: retval = new Float(invokeF(obj, args));
326: } else if (returnType == Double.TYPE) {
327: retval = new Double(invokeD(obj, args));
328: } else if (returnType == Byte.TYPE) {
329: retval = new Byte(invokeB(obj, args));
330: } else if (returnType == Short.TYPE) {
331: retval = new Short(invokeS(obj, args));
332: } else if (returnType == Integer.TYPE) {
333: retval = new Integer(invokeI(obj, args));
334: } else if (returnType == Long.TYPE) {
335: retval = new Long(invokeL(obj, args));
336: } else {
337: /* Object return type */
338: retval = invokeA(obj, args);
339: }
340: } catch (ArgumentException e) {
341: throw new IllegalArgumentException(
342: "wrong object type, or unwrapping conversion failed: "
343: + e.getMessage());
344: } catch (AccessException e) {
345: throw new IllegalAccessException(name);
346: } catch (Throwable e) {
347: throw new InvocationTargetException(e);
348: }
349: return retval;
350: }
351:
352: private native void invokeV(Object obj, Object[] args)
353: throws ArgumentException, AccessException, Exception;
354:
355: private native boolean invokeZ(Object obj, Object[] args)
356: throws ArgumentException, AccessException, Exception;
357:
358: private native char invokeC(Object obj, Object[] args)
359: throws ArgumentException, AccessException, Exception;
360:
361: private native float invokeF(Object obj, Object[] args)
362: throws ArgumentException, AccessException, Exception;
363:
364: private native double invokeD(Object obj, Object[] args)
365: throws ArgumentException, AccessException, Exception;
366:
367: private native byte invokeB(Object obj, Object[] args)
368: throws ArgumentException, AccessException, Exception;
369:
370: private native short invokeS(Object obj, Object[] args)
371: throws ArgumentException, AccessException, Exception;
372:
373: private native int invokeI(Object obj, Object[] args)
374: throws ArgumentException, AccessException, Exception;
375:
376: private native long invokeL(Object obj, Object[] args)
377: throws ArgumentException, AccessException, Exception;
378:
379: private native Object invokeA(Object obj, Object[] args)
380: throws ArgumentException, AccessException, Exception;
381:
382: /*
383: * Avoid clone()
384: */
385: static Class[] copy(Class[] in) {
386: int l = in.length;
387: if (l == 0)
388: return in;
389: Class[] out = new Class[l];
390: for (int i = 0; i < l; i++)
391: out[i] = in[i];
392: return out;
393: }
394: }
|