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