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