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 com.android.dex.Dex;
     36 import java.lang.annotation.Annotation;
     37 import java.util.Comparator;
     38 import java.util.List;
     39 import libcore.reflect.AnnotationAccess;
     40 import libcore.reflect.Types;
     41 
     42 /**
     43  * This class represents a method. Information about the method can be accessed,
     44  * and the method can be invoked dynamically.
     45  */
     46 public final class Method extends AbstractMethod implements GenericDeclaration, Member {
     47 
     48     /**
     49      * Orders methods by their name, parameters and return type.
     50      *
     51      * @hide
     52      */
     53     public static final Comparator<Method> ORDER_BY_SIGNATURE = new Comparator<Method>() {
     54         @Override public int compare(Method a, Method b) {
     55             if (a == b) {
     56                 return 0;
     57             }
     58             int comparison = a.getName().compareTo(b.getName());
     59             if (comparison == 0) {
     60                 comparison = a.artMethod.findOverriddenMethodIfProxy().compareParameters(
     61                         b.getParameterTypes());
     62                 if (comparison == 0) {
     63                     // This is necessary for methods that have covariant return types.
     64                     Class<?> aReturnType = a.getReturnType();
     65                     Class<?> bReturnType = b.getReturnType();
     66                     if (aReturnType == bReturnType) {
     67                         comparison = 0;
     68                     } else {
     69                         comparison = aReturnType.getName().compareTo(bReturnType.getName());
     70                     }
     71                 }
     72             }
     73             return comparison;
     74         }
     75     };
     76 
     77     /**
     78      * @hide
     79      */
     80     public Method(ArtMethod artMethod) {
     81         super(artMethod);
     82     }
     83 
     84     ArtMethod getArtMethod() {
     85         return artMethod;
     86     }
     87 
     88     public Annotation[] getAnnotations() {
     89         return super.getAnnotations();
     90     }
     91 
     92     /**
     93      * Returns the modifiers for this method. The {@link Modifier} class should
     94      * be used to decode the result.
     95      *
     96      * @return the modifiers for this method
     97      *
     98      * @see Modifier
     99      */
    100     @Override public int getModifiers() {
    101         return super.getModifiers();
    102     }
    103 
    104     /**
    105      * Indicates whether or not this method takes a variable number argument.
    106      *
    107      * @return {@code true} if a vararg is declared, {@code false} otherwise
    108      */
    109     public boolean isVarArgs() {
    110         return super.isVarArgs();
    111     }
    112 
    113     /**
    114      * Indicates whether or not this method is a bridge.
    115      *
    116      * @return {@code true} if this method is a bridge, {@code false} otherwise
    117      */
    118     public boolean isBridge() {
    119         return super.isBridge();
    120 
    121     }
    122 
    123     /**
    124      * Indicates whether or not this method is synthetic.
    125      *
    126      * @return {@code true} if this method is synthetic, {@code false} otherwise
    127      */
    128     @Override public boolean isSynthetic() {
    129         return super.isSynthetic();
    130     }
    131 
    132     /**
    133      * Returns the name of the method represented by this {@code Method}
    134      * instance.
    135      *
    136      * @return the name of this method
    137      */
    138     @Override public String getName() {
    139         return ArtMethod.getMethodName(artMethod);
    140     }
    141 
    142     /**
    143      * Returns the class that declares this method.
    144      */
    145     @Override public Class<?> getDeclaringClass() {
    146         return super.getDeclaringClass();
    147     }
    148 
    149     /**
    150      * Returns the exception types as an array of {@code Class} instances. If
    151      * this method has no declared exceptions, an empty array is returned.
    152      *
    153      * @return the declared exception classes
    154      */
    155     public Class<?>[] getExceptionTypes() {
    156         if (getDeclaringClass().isProxy()) {
    157             return getExceptionTypesNative();
    158         } else {
    159             // TODO: use dex cache to speed looking up class
    160             return AnnotationAccess.getExceptions(this);
    161         }
    162     }
    163 
    164     private native Class<?>[] getExceptionTypesNative();
    165 
    166     /**
    167      * Returns an array of {@code Class} objects associated with the parameter
    168      * types of this method. If the method was declared with no parameters, an
    169      * empty array will be returned.
    170      *
    171      * @return the parameter types
    172      */
    173     @Override public Class<?>[] getParameterTypes() {
    174         return artMethod.findOverriddenMethodIfProxy().getParameterTypes();
    175     }
    176 
    177     /**
    178      * Returns the {@code Class} associated with the return type of this
    179      * method.
    180      *
    181      * @return the return type
    182      */
    183     public Class<?> getReturnType() {
    184         return artMethod.findOverriddenMethodIfProxy().getReturnType();
    185     }
    186 
    187     /**
    188      * {@inheritDoc}
    189      *
    190      * <p>Equivalent to {@code getDeclaringClass().getName().hashCode() ^ getName().hashCode()}.
    191      */
    192     @Override public int hashCode() {
    193         return getDeclaringClass().getName().hashCode() ^ getName().hashCode();
    194     }
    195 
    196     /**
    197      * Returns true if {@code other} has the same declaring class, name,
    198      * parameters and return type as this method.
    199      */
    200     @Override public boolean equals(Object other) {
    201         return super.equals(other);
    202     }
    203 
    204     /**
    205      * Returns true if this and {@code method} have the same name and the same
    206      * parameters in the same order. Such methods can share implementation if
    207      * one method's return types is assignable to the other.
    208      *
    209      * @hide needed by Proxy
    210      */
    211     boolean equalNameAndParameters(Method m) {
    212         return getName().equals(m.getName()) &&
    213                 ArtMethod.equalMethodParameters(artMethod,m.getParameterTypes());
    214     }
    215 
    216     /**
    217      * Returns the string representation of the method's declaration, including
    218      * the type parameters.
    219      *
    220      * @return the string representation of this method
    221      */
    222     public String toGenericString() {
    223         return super.toGenericString();
    224     }
    225 
    226     @Override public TypeVariable<Method>[] getTypeParameters() {
    227         GenericInfo info = getMethodOrConstructorGenericInfo();
    228         return (TypeVariable<Method>[]) info.formalTypeParameters.clone();
    229     }
    230 
    231     /**
    232      * Returns the parameter types as an array of {@code Type} instances, in
    233      * declaration order. If this method has no parameters, an empty array is
    234      * returned.
    235      *
    236      * @return the parameter types
    237      *
    238      * @throws GenericSignatureFormatError
    239      *             if the generic method signature is invalid
    240      * @throws TypeNotPresentException
    241      *             if any parameter type points to a missing type
    242      * @throws MalformedParameterizedTypeException
    243      *             if any parameter type points to a type that cannot be
    244      *             instantiated for some reason
    245      */
    246     public Type[] getGenericParameterTypes() {
    247         return Types.getTypeArray(getMethodOrConstructorGenericInfo().genericParameterTypes, false);
    248     }
    249 
    250     @Override public boolean isAnnotationPresent(Class<? extends Annotation> annotationType) {
    251         if (annotationType == null) {
    252             throw new NullPointerException("annotationType == null");
    253         }
    254         return AnnotationAccess.isDeclaredAnnotationPresent(this, annotationType);
    255     }
    256 
    257     /**
    258      * Returns the exception types as an array of {@code Type} instances. If
    259      * this method has no declared exceptions, an empty array will be returned.
    260      *
    261      * @return an array of generic exception types
    262      *
    263      * @throws GenericSignatureFormatError
    264      *             if the generic method signature is invalid
    265      * @throws TypeNotPresentException
    266      *             if any exception type points to a missing type
    267      * @throws MalformedParameterizedTypeException
    268      *             if any exception type points to a type that cannot be
    269      *             instantiated for some reason
    270      */
    271     public Type[] getGenericExceptionTypes() {
    272         return Types.getTypeArray(getMethodOrConstructorGenericInfo().genericExceptionTypes, false);
    273     }
    274 
    275     /**
    276      * Returns the return type of this method as a {@code Type} instance.
    277      *
    278      * @return the return type of this method
    279      *
    280      * @throws GenericSignatureFormatError
    281      *             if the generic method signature is invalid
    282      * @throws TypeNotPresentException
    283      *             if the return type points to a missing type
    284      * @throws MalformedParameterizedTypeException
    285      *             if the return type points to a type that cannot be
    286      *             instantiated for some reason
    287      */
    288     public Type getGenericReturnType() {
    289         return Types.getType(getMethodOrConstructorGenericInfo().genericReturnType);
    290     }
    291 
    292     @Override public Annotation[] getDeclaredAnnotations() {
    293         List<Annotation> result = AnnotationAccess.getDeclaredAnnotations(this);
    294         return result.toArray(new Annotation[result.size()]);
    295     }
    296 
    297     @Override public <A extends Annotation> A getAnnotation(Class<A> annotationType) {
    298         if (annotationType == null) {
    299             throw new NullPointerException("annotationType == null");
    300         }
    301         return AnnotationAccess.getDeclaredAnnotation(this, annotationType);
    302     }
    303 
    304     /**
    305      * Returns an array of arrays that represent the annotations of the formal
    306      * parameters of this method. If there are no parameters on this method,
    307      * then an empty array is returned. If there are no annotations set, then
    308      * and array of empty arrays is returned.
    309      *
    310      * @return an array of arrays of {@code Annotation} instances
    311      */
    312     public Annotation[][] getParameterAnnotations() {
    313         return artMethod.findOverriddenMethodIfProxy().getParameterAnnotations();
    314     }
    315 
    316     /**
    317      * Returns the default value for the annotation member represented by this
    318      * method.
    319      *
    320      * @return the default value, or {@code null} if none
    321      *
    322      * @throws TypeNotPresentException
    323      *             if this annotation member is of type {@code Class} and no
    324      *             definition can be found
    325      */
    326     public Object getDefaultValue() {
    327         return AnnotationAccess.getDefaultValue(this);
    328     }
    329 
    330     /**
    331      * Returns the result of dynamically invoking this method. Equivalent to
    332      * {@code receiver.methodName(arg1, arg2, ... , argN)}.
    333      *
    334      * <p>If the method is static, the receiver argument is ignored (and may be null).
    335      *
    336      * <p>If the method takes no arguments, you can pass {@code (Object[]) null} instead of
    337      * allocating an empty array.
    338      *
    339      * <p>If you're calling a varargs method, you need to pass an {@code Object[]} for the
    340      * varargs parameter: that conversion is usually done in {@code javac}, not the VM, and
    341      * the reflection machinery does not do this for you. (It couldn't, because it would be
    342      * ambiguous.)
    343      *
    344      * <p>Reflective method invocation follows the usual process for method lookup.
    345      *
    346      * <p>If an exception is thrown during the invocation it is caught and
    347      * wrapped in an InvocationTargetException. This exception is then thrown.
    348      *
    349      * <p>If the invocation completes normally, the return value itself is
    350      * returned. If the method is declared to return a primitive type, the
    351      * return value is boxed. If the return type is void, null is returned.
    352      *
    353      * @param receiver
    354      *            the object on which to call this method (or null for static methods)
    355      * @param args
    356      *            the arguments to the method
    357      * @return the result
    358      *
    359      * @throws NullPointerException
    360      *             if {@code receiver == null} for a non-static method
    361      * @throws IllegalAccessException
    362      *             if this method is not accessible (see {@link AccessibleObject})
    363      * @throws IllegalArgumentException
    364      *             if the number of arguments doesn't match the number of parameters, the receiver
    365      *             is incompatible with the declaring class, or an argument could not be unboxed
    366      *             or converted by a widening conversion to the corresponding parameter type
    367      * @throws InvocationTargetException
    368      *             if an exception was thrown by the invoked method
    369      */
    370     public Object invoke(Object receiver, Object... args)
    371             throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
    372         return invoke(receiver, args, isAccessible());
    373     }
    374 
    375     private native Object invoke(Object receiver, Object[] args, boolean accessible)
    376             throws IllegalAccessException, IllegalArgumentException, InvocationTargetException;
    377 
    378     /**
    379      * Returns a string containing a concise, human-readable description of this
    380      * method. The format of the string is:
    381      *
    382      * <ol>
    383      *   <li>modifiers (if any)
    384      *   <li>return type or 'void'
    385      *   <li>declaring class name
    386      *   <li>'('
    387      *   <li>parameter types, separated by ',' (if any)
    388      *   <li>')'
    389      *   <li>'throws' plus exception types, separated by ',' (if any)
    390      * </ol>
    391      *
    392      * For example: {@code public native Object
    393      * java.lang.Method.invoke(Object,Object) throws
    394      * IllegalAccessException,IllegalArgumentException
    395      * ,InvocationTargetException}
    396      *
    397      * @return a printable representation for this method
    398      */
    399     @Override
    400     public String toString() {
    401         StringBuilder result = new StringBuilder(Modifier.toString(getModifiers()));
    402 
    403         if (result.length() != 0) {
    404             result.append(' ');
    405         }
    406         result.append(getReturnType().getName());
    407         result.append(' ');
    408         result.append(getDeclaringClass().getName());
    409         result.append('.');
    410         result.append(getName());
    411         result.append("(");
    412         Class<?>[] parameterTypes = getParameterTypes();
    413         result.append(Types.toString(parameterTypes));
    414         result.append(")");
    415         Class<?>[] exceptionTypes = getExceptionTypes();
    416         if (exceptionTypes.length != 0) {
    417             result.append(" throws ");
    418             result.append(Types.toString(exceptionTypes));
    419         }
    420         return result.toString();
    421     }
    422 
    423     /**
    424      * Returns the constructor's signature in non-printable form. This is called
    425      * (only) from IO native code and needed for deriving the serialVersionUID
    426      * of the class
    427      *
    428      * @return The constructor's signature.
    429      */
    430     @SuppressWarnings("unused")
    431     String getSignature() {
    432         StringBuilder result = new StringBuilder();
    433 
    434         result.append('(');
    435         Class<?>[] parameterTypes = getParameterTypes();
    436         for (Class<?> parameterType : parameterTypes) {
    437             result.append(Types.getSignature(parameterType));
    438         }
    439         result.append(')');
    440         result.append(Types.getSignature(getReturnType()));
    441 
    442         return result.toString();
    443     }
    444 }
    445