1/*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements.  See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17/*
18 * Copyright (C) 2008 The Android Open Source Project
19 *
20 * Licensed under the Apache License, Version 2.0 (the "License");
21 * you may not use this file except in compliance with the License.
22 * You may obtain a copy of the License at
23 *
24 *      http://www.apache.org/licenses/LICENSE-2.0
25 *
26 * Unless required by applicable law or agreed to in writing, software
27 * distributed under the License is distributed on an "AS IS" BASIS,
28 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
29 * See the License for the specific language governing permissions and
30 * limitations under the License.
31 */
32
33package java.lang.reflect;
34
35import java.lang.annotation.Annotation;
36import java.util.Arrays;
37import java.util.Comparator;
38import libcore.util.EmptyArray;
39import org.apache.harmony.kernel.vm.StringUtils;
40import libcore.reflect.GenericSignatureParser;
41import libcore.reflect.ListOfTypes;
42import libcore.reflect.Types;
43
44/**
45 * This class represents a method. Information about the method can be accessed,
46 * and the method can be invoked dynamically.
47 */
48public final class Method extends AccessibleObject implements GenericDeclaration, Member {
49
50    /**
51     * Orders methods by their name, parameters and return type.
52     *
53     * @hide
54     */
55    public static final Comparator<Method> ORDER_BY_SIGNATURE = new Comparator<Method>() {
56        public int compare(Method a, Method b) {
57            int comparison = a.name.compareTo(b.name);
58            if (comparison != 0) {
59                return comparison;
60            }
61
62            Class<?>[] aParameters = a.parameterTypes;
63            Class<?>[] bParameters = b.parameterTypes;
64            int length = Math.min(aParameters.length, bParameters.length);
65            for (int i = 0; i < length; i++) {
66                comparison = aParameters[i].getName().compareTo(bParameters[i].getName());
67                if (comparison != 0) {
68                    return comparison;
69                }
70            }
71
72            if (aParameters.length != bParameters.length) {
73                return aParameters.length - bParameters.length;
74            }
75
76            // this is necessary for methods that have covariant return types.
77            return a.getReturnType().getName().compareTo(b.getReturnType().getName());
78        }
79    };
80
81    private int slot;
82
83    private final int methodDexIndex;
84
85    private Class<?> declaringClass;
86
87    private String name;
88
89    private Class<?>[] parameterTypes;
90
91    private Class<?>[] exceptionTypes;
92
93    private Class<?> returnType;
94
95    private ListOfTypes genericExceptionTypes;
96    private ListOfTypes genericParameterTypes;
97    private Type genericReturnType;
98    private TypeVariable<Method>[] formalTypeParameters;
99    private volatile boolean genericTypesAreInitialized = false;
100
101    private synchronized void initGenericTypes() {
102        if (!genericTypesAreInitialized) {
103            String signatureAttribute = getSignatureAttribute();
104            GenericSignatureParser parser = new GenericSignatureParser(
105                    declaringClass.getClassLoader());
106            parser.parseForMethod(this, signatureAttribute, exceptionTypes);
107            formalTypeParameters = parser.formalTypeParameters;
108            genericParameterTypes = parser.parameterTypes;
109            genericExceptionTypes = parser.exceptionTypes;
110            genericReturnType = parser.returnType;
111            genericTypesAreInitialized = true;
112        }
113    }
114
115    private Method(Class<?> declaring, Class<?>[] paramTypes, Class<?>[] exceptTypes, Class<?> returnType, String name, int slot, int methodDexIndex) {
116        this.declaringClass = declaring;
117        this.name = name;
118        this.slot = slot;
119        this.parameterTypes = paramTypes;
120        this.exceptionTypes = exceptTypes;      // may be null
121        this.returnType = returnType;
122        this.methodDexIndex = methodDexIndex;
123    }
124
125    /** @hide */
126    public int getDexMethodIndex() {
127        return methodDexIndex;
128    }
129
130    public TypeVariable<Method>[] getTypeParameters() {
131        initGenericTypes();
132        return formalTypeParameters.clone();
133    }
134
135    /** {@inheritDoc} */
136    @Override /*package*/ String getSignatureAttribute() {
137        Object[] annotation = getSignatureAnnotation(declaringClass, slot);
138
139        if (annotation == null) {
140            return null;
141        }
142
143        return StringUtils.combineStrings(annotation);
144    }
145
146    /**
147     * Returns the Signature annotation for this method. Returns {@code null} if
148     * not found.
149     */
150    static native Object[] getSignatureAnnotation(Class declaringClass, int slot);
151
152    /**
153     * Returns the string representation of the method's declaration, including
154     * the type parameters.
155     *
156     * @return the string representation of this method
157     */
158    public String toGenericString() {
159        StringBuilder sb = new StringBuilder(80);
160
161        initGenericTypes();
162
163        // append modifiers if any
164        int modifier = getModifiers();
165        if (modifier != 0) {
166            sb.append(Modifier.toString(modifier & ~(Modifier.BRIDGE +
167                    Modifier.VARARGS))).append(' ');
168        }
169        // append type parameters
170        if (formalTypeParameters != null && formalTypeParameters.length > 0) {
171            sb.append('<');
172            for (int i = 0; i < formalTypeParameters.length; i++) {
173                appendGenericType(sb, formalTypeParameters[i]);
174                if (i < formalTypeParameters.length - 1) {
175                    sb.append(",");
176                }
177            }
178            sb.append("> ");
179        }
180        // append return type
181        appendGenericType(sb, Types.getType(genericReturnType));
182        sb.append(' ');
183        // append method name
184        appendTypeName(sb, getDeclaringClass());
185        sb.append(".").append(getName());
186        // append parameters
187        sb.append('(');
188        appendArrayGenericType(sb, Types.getTypeArray(genericParameterTypes, false));
189        sb.append(')');
190        // append exceptions if any
191        Type[] genericExceptionTypeArray = Types.getTypeArray(genericExceptionTypes, false);
192        if (genericExceptionTypeArray.length > 0) {
193            sb.append(" throws ");
194            appendArrayGenericType(sb, genericExceptionTypeArray);
195        }
196        return sb.toString();
197    }
198
199    /**
200     * Returns the parameter types as an array of {@code Type} instances, in
201     * declaration order. If this method has no parameters, an empty array is
202     * returned.
203     *
204     * @return the parameter types
205     *
206     * @throws GenericSignatureFormatError
207     *             if the generic method signature is invalid
208     * @throws TypeNotPresentException
209     *             if any parameter type points to a missing type
210     * @throws MalformedParameterizedTypeException
211     *             if any parameter type points to a type that cannot be
212     *             instantiated for some reason
213     */
214    public Type[] getGenericParameterTypes() {
215        initGenericTypes();
216        return Types.getTypeArray(genericParameterTypes, true);
217    }
218
219    /**
220     * Returns the exception types as an array of {@code Type} instances. If
221     * this method has no declared exceptions, an empty array will be returned.
222     *
223     * @return an array of generic exception types
224     *
225     * @throws GenericSignatureFormatError
226     *             if the generic method signature is invalid
227     * @throws TypeNotPresentException
228     *             if any exception type points to a missing type
229     * @throws MalformedParameterizedTypeException
230     *             if any exception type points to a type that cannot be
231     *             instantiated for some reason
232     */
233    public Type[] getGenericExceptionTypes() {
234        initGenericTypes();
235        return Types.getTypeArray(genericExceptionTypes, true);
236    }
237
238    /**
239     * Returns the return type of this method as a {@code Type} instance.
240     *
241     * @return the return type of this method
242     *
243     * @throws GenericSignatureFormatError
244     *             if the generic method signature is invalid
245     * @throws TypeNotPresentException
246     *             if the return type points to a missing type
247     * @throws MalformedParameterizedTypeException
248     *             if the return type points to a type that cannot be
249     *             instantiated for some reason
250     */
251    public Type getGenericReturnType() {
252        initGenericTypes();
253        return Types.getType(genericReturnType);
254    }
255
256    @Override
257    public Annotation[] getDeclaredAnnotations() {
258        return getDeclaredAnnotations(declaringClass, slot);
259    }
260    static native Annotation[] getDeclaredAnnotations(Class<?> declaringClass, int slot);
261
262    @Override public <A extends Annotation> A getAnnotation(Class<A> annotationType) {
263        if (annotationType == null) {
264            throw new NullPointerException("annotationType == null");
265        }
266        return getAnnotation(declaringClass, slot, annotationType);
267    }
268    static native <A extends Annotation> A getAnnotation(
269            Class<?> declaringClass, int slot, Class<A> annotationType);
270
271    @Override public boolean isAnnotationPresent(Class<? extends Annotation> annotationType) {
272        if (annotationType == null) {
273            throw new NullPointerException("annotationType == null");
274        }
275        return isAnnotationPresent(declaringClass, slot, annotationType);
276    }
277    static native boolean isAnnotationPresent(
278            Class<?> declaringClass, int slot, Class<? extends Annotation> annotationType);
279
280    private static final Annotation[] NO_ANNOTATIONS = new Annotation[0];
281
282    /**
283     * Creates an array of empty Annotation arrays.
284     */
285    /*package*/ static Annotation[][] noAnnotations(int size) {
286        Annotation[][] annotations = new Annotation[size][];
287        for (int i = 0; i < size; i++) {
288            annotations[i] = NO_ANNOTATIONS;
289        }
290        return annotations;
291    }
292
293    /**
294     * Returns an array of arrays that represent the annotations of the formal
295     * parameters of this method. If there are no parameters on this method,
296     * then an empty array is returned. If there are no annotations set, then
297     * and array of empty arrays is returned.
298     *
299     * @return an array of arrays of {@code Annotation} instances
300     */
301    public Annotation[][] getParameterAnnotations() {
302        Annotation[][] parameterAnnotations
303                = getParameterAnnotations(declaringClass, slot);
304        if (parameterAnnotations.length == 0) {
305            return noAnnotations(parameterTypes.length);
306        }
307        return parameterAnnotations;
308    }
309
310    static native Annotation[][] getParameterAnnotations(Class declaringClass, int slot);
311
312    /**
313     * Indicates whether or not this method takes a variable number argument.
314     *
315     * @return {@code true} if a vararg is declared, {@code false} otherwise
316     */
317    public boolean isVarArgs() {
318        int modifiers = getMethodModifiers(declaringClass, slot);
319        return (modifiers & Modifier.VARARGS) != 0;
320    }
321
322    /**
323     * Indicates whether or not this method is a bridge.
324     *
325     * @return {@code true} if this method is a bridge, {@code false} otherwise
326     */
327    public boolean isBridge() {
328        int modifiers = getMethodModifiers(declaringClass, slot);
329        return (modifiers & Modifier.BRIDGE) != 0;
330    }
331
332    /**
333     * Indicates whether or not this method is synthetic.
334     *
335     * @return {@code true} if this method is synthetic, {@code false} otherwise
336     */
337    public boolean isSynthetic() {
338        int modifiers = getMethodModifiers(declaringClass, slot);
339        return (modifiers & Modifier.SYNTHETIC) != 0;
340    }
341
342    /**
343     * Returns the default value for the annotation member represented by this
344     * method.
345     *
346     * @return the default value, or {@code null} if none
347     *
348     * @throws TypeNotPresentException
349     *             if this annotation member is of type {@code Class} and no
350     *             definition can be found
351     */
352    public Object getDefaultValue() {
353        return getDefaultValue(declaringClass, slot);
354    }
355    native private Object getDefaultValue(Class declaringClass, int slot);
356
357    /**
358     * Indicates whether or not the specified {@code object} is equal to this
359     * method. To be equal, the specified object must be an instance
360     * of {@code Method} with the same declaring class and parameter types
361     * as this method.
362     *
363     * @param object
364     *            the object to compare
365     *
366     * @return {@code true} if the specified object is equal to this
367     *         method, {@code false} otherwise
368     *
369     * @see #hashCode
370     */
371    @Override
372    public boolean equals(Object object) {
373        if (this == object) {
374            return true;
375        }
376        if (!(object instanceof Method)) {
377            return false;
378        }
379        Method rhs = (Method) object;
380        // We don't compare exceptionTypes because two methods
381        // can't differ only by their declared exceptions.
382        return declaringClass.equals(rhs.declaringClass) &&
383            name.equals(rhs.name) &&
384            getModifiers() == rhs.getModifiers() &&
385            returnType.equals(rhs.returnType) &&
386            Arrays.equals(parameterTypes, rhs.parameterTypes);
387    }
388
389    /**
390     * Returns the class that declares this method.
391     *
392     * @return the declaring class
393     */
394    public Class<?> getDeclaringClass() {
395        return declaringClass;
396    }
397
398    /**
399     * Returns the exception types as an array of {@code Class} instances. If
400     * this method has no declared exceptions, an empty array is returned.
401     *
402     * @return the declared exception classes
403     */
404    public Class<?>[] getExceptionTypes() {
405        if (exceptionTypes == null) {
406            return EmptyArray.CLASS;
407        }
408        return exceptionTypes.clone();
409    }
410
411    /**
412     * Returns the modifiers for this method. The {@link Modifier} class should
413     * be used to decode the result.
414     *
415     * @return the modifiers for this method
416     *
417     * @see Modifier
418     */
419    public int getModifiers() {
420        return getMethodModifiers(declaringClass, slot);
421    }
422
423    static native int getMethodModifiers(Class<?> declaringClass, int slot);
424
425    /**
426     * Returns the name of the method represented by this {@code Method}
427     * instance.
428     *
429     * @return the name of this method
430     */
431    public String getName() {
432        return name;
433    }
434
435    /**
436     * Returns an array of {@code Class} objects associated with the parameter
437     * types of this method. If the method was declared with no parameters, an
438     * empty array will be returned.
439     *
440     * @return the parameter types
441     */
442    public Class<?>[] getParameterTypes() {
443        return parameterTypes.clone();
444    }
445
446    /**
447     * Returns the {@code Class} associated with the return type of this
448     * method.
449     *
450     * @return the return type
451     */
452    public Class<?> getReturnType() {
453        return returnType;
454    }
455
456    /**
457     * Returns an integer hash code for this method. Objects which are equal
458     * return the same value for this method. The hash code for this Method is
459     * the hash code of the name of this method.
460     *
461     * @return hash code for this method
462     *
463     * @see #equals
464     */
465    @Override
466    public int hashCode() {
467        return name.hashCode();
468    }
469
470    /**
471     * Returns the result of dynamically invoking this method. Equivalent to
472     * {@code receiver.methodName(arg1, arg2, ... , argN)}.
473     *
474     * <p>If the method is static, the receiver argument is ignored (and may be null).
475     *
476     * <p>If the method takes no arguments, you can pass {@code (Object[]) null} instead of
477     * allocating an empty array.
478     *
479     * <p>If you're calling a varargs method, you need to pass an {@code Object[]} for the
480     * varargs parameter: that conversion is usually done in {@code javac}, not the VM, and
481     * the reflection machinery does not do this for you. (It couldn't, because it would be
482     * ambiguous.)
483     *
484     * <p>Reflective method invocation follows the usual process for method lookup.
485     *
486     * <p>If an exception is thrown during the invocation it is caught and
487     * wrapped in an InvocationTargetException. This exception is then thrown.
488     *
489     * <p>If the invocation completes normally, the return value itself is
490     * returned. If the method is declared to return a primitive type, the
491     * return value is boxed. If the return type is void, null is returned.
492     *
493     * @param receiver
494     *            the object on which to call this method (or null for static methods)
495     * @param args
496     *            the arguments to the method
497     * @return the result
498     *
499     * @throws NullPointerException
500     *             if {@code receiver == null} for a non-static method
501     * @throws IllegalAccessException
502     *             if this method is not accessible (see {@link AccessibleObject})
503     * @throws IllegalArgumentException
504     *             if the number of arguments doesn't match the number of parameters, the receiver
505     *             is incompatible with the declaring class, or an argument could not be unboxed
506     *             or converted by a widening conversion to the corresponding parameter type
507     * @throws InvocationTargetException
508     *             if an exception was thrown by the invoked method
509     */
510    public Object invoke(Object receiver, Object... args)
511            throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
512        if (args == null) {
513            args = EmptyArray.OBJECT;
514        }
515        return invokeNative(receiver, args, declaringClass, parameterTypes, returnType, slot, flag);
516    }
517
518    private native Object invokeNative(Object obj, Object[] args, Class<?> declaringClass,
519            Class<?>[] parameterTypes, Class<?> returnType, int slot, boolean noAccessCheck)
520                    throws IllegalAccessException, IllegalArgumentException,
521                            InvocationTargetException;
522
523    /**
524     * Returns a string containing a concise, human-readable description of this
525     * method. The format of the string is:
526     *
527     * <ol>
528     *   <li>modifiers (if any)
529     *   <li>return type or 'void'
530     *   <li>declaring class name
531     *   <li>'('
532     *   <li>parameter types, separated by ',' (if any)
533     *   <li>')'
534     *   <li>'throws' plus exception types, separated by ',' (if any)
535     * </ol>
536     *
537     * For example: {@code public native Object
538     * java.lang.Method.invoke(Object,Object) throws
539     * IllegalAccessException,IllegalArgumentException
540     * ,InvocationTargetException}
541     *
542     * @return a printable representation for this method
543     */
544    @Override
545    public String toString() {
546        StringBuilder result = new StringBuilder(Modifier.toString(getModifiers()));
547
548        if (result.length() != 0)
549            result.append(' ');
550        result.append(returnType.getName());
551        result.append(' ');
552        result.append(declaringClass.getName());
553        result.append('.');
554        result.append(name);
555        result.append("(");
556        result.append(toString(parameterTypes));
557        result.append(")");
558        if (exceptionTypes != null && exceptionTypes.length != 0) {
559            result.append(" throws ");
560            result.append(toString(exceptionTypes));
561        }
562
563        return result.toString();
564    }
565
566    /**
567     * Returns the constructor's signature in non-printable form. This is called
568     * (only) from IO native code and needed for deriving the serialVersionUID
569     * of the class
570     *
571     * @return The constructor's signature.
572     */
573    @SuppressWarnings("unused")
574    private String getSignature() {
575        StringBuilder result = new StringBuilder();
576
577        result.append('(');
578        for (int i = 0; i < parameterTypes.length; i++) {
579            result.append(getSignature(parameterTypes[i]));
580        }
581        result.append(')');
582        result.append(getSignature(returnType));
583
584        return result.toString();
585    }
586
587}
588