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) 2012 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.List;
     38 import libcore.reflect.AnnotationAccess;
     39 import libcore.reflect.GenericSignatureParser;
     40 import libcore.reflect.ListOfTypes;
     41 import libcore.reflect.Types;
     42 
     43 /**
     44  * This class represents an abstract method. Abstract methods are either methods or constructors.
     45  * @hide
     46  */
     47 public abstract class AbstractMethod extends AccessibleObject {
     48 
     49     /**
     50      * Hidden to workaround b/16828157.
     51      * @hide
     52      */
     53     protected final ArtMethod artMethod;
     54 
     55     /**
     56      * Hidden to workaround b/16828157.
     57      * @hide
     58      */
     59     protected AbstractMethod(ArtMethod artMethod) {
     60         if (artMethod == null) {
     61             throw new NullPointerException("artMethod == null");
     62         }
     63         this.artMethod = artMethod;
     64     }
     65 
     66     public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
     67         return super.getAnnotation(annotationClass);
     68     }
     69 
     70     /**
     71      * We insert native method stubs for abstract methods so we don't have to
     72      * check the access flags at the time of the method call.  This results in
     73      * "native abstract" methods, which can't exist.  If we see the "abstract"
     74      * flag set, clear the "native" flag.
     75      *
     76      * We also move the DECLARED_SYNCHRONIZED flag into the SYNCHRONIZED
     77      * position, because the callers of this function are trying to convey
     78      * the "traditional" meaning of the flags to their callers.
     79      */
     80     private static int fixMethodFlags(int flags) {
     81         if ((flags & Modifier.ABSTRACT) != 0) {
     82             flags &= ~Modifier.NATIVE;
     83         }
     84         flags &= ~Modifier.SYNCHRONIZED;
     85         int ACC_DECLARED_SYNCHRONIZED = 0x00020000;
     86         if ((flags & ACC_DECLARED_SYNCHRONIZED) != 0) {
     87             flags |= Modifier.SYNCHRONIZED;
     88         }
     89         return flags & 0xffff;  // mask out bits not used by Java
     90     }
     91 
     92     int getModifiers() {
     93         return fixMethodFlags(artMethod.getAccessFlags());
     94     }
     95 
     96     boolean isVarArgs() {
     97         return (artMethod.getAccessFlags() & Modifier.VARARGS) != 0;
     98     }
     99 
    100     boolean isBridge() {
    101         return (artMethod.getAccessFlags() & Modifier.BRIDGE) != 0;
    102     }
    103 
    104     boolean isSynthetic() {
    105         return (artMethod.getAccessFlags() & Modifier.SYNTHETIC) != 0;
    106     }
    107 
    108     /**
    109      * @hide
    110      */
    111     public final int getAccessFlags() {
    112         return artMethod.getAccessFlags();
    113     }
    114 
    115     /**
    116      * Returns the class that declares this constructor or method.
    117      */
    118     Class<?> getDeclaringClass() {
    119         return artMethod.getDeclaringClass();
    120     }
    121 
    122     /**
    123      * Returns the index of this method's ID in its dex file.
    124      *
    125      * @hide
    126      */
    127     public final int getDexMethodIndex() {
    128         return artMethod.getDexMethodIndex();
    129     }
    130 
    131     /**
    132      * Returns the name of the method or constructor represented by this
    133      * instance.
    134      *
    135      * @return the name of this method
    136      */
    137     abstract public String getName();
    138 
    139     /**
    140      * Returns an array of {@code Class} objects associated with the parameter types of this
    141      * abstract method. If the method was declared with no parameters, an
    142      * empty array will be returned.
    143      *
    144      * @return the parameter types
    145      */
    146     Class<?>[] getParameterTypes() {
    147         return artMethod.getParameterTypes();
    148     }
    149 
    150     /**
    151      * Returns true if {@code other} has the same declaring class, name,
    152      * parameters and return type as this method.
    153      */
    154     @Override public boolean equals(Object other) {
    155         if (!(other instanceof AbstractMethod)) {
    156             return false;
    157         }
    158         // exactly one instance of each member in this runtime
    159         return this.artMethod == ((AbstractMethod) other).artMethod;
    160     }
    161 
    162     String toGenericString() {
    163         return toGenericStringHelper();
    164     }
    165 
    166     Type[] getGenericParameterTypes() {
    167         return Types.getTypeArray(getMethodOrConstructorGenericInfo().genericParameterTypes, false);
    168     }
    169 
    170     Type[] getGenericExceptionTypes() {
    171         return Types.getTypeArray(getMethodOrConstructorGenericInfo().genericExceptionTypes, false);
    172     }
    173 
    174     @Override public Annotation[] getDeclaredAnnotations() {
    175         List<Annotation> result = AnnotationAccess.getDeclaredAnnotations(this);
    176         return result.toArray(new Annotation[result.size()]);
    177     }
    178 
    179     @Override public boolean isAnnotationPresent(Class<? extends Annotation> annotationType) {
    180         if (annotationType == null) {
    181             throw new NullPointerException("annotationType == null");
    182         }
    183         return AnnotationAccess.isDeclaredAnnotationPresent(this, annotationType);
    184     }
    185 
    186     public Annotation[] getAnnotations() {
    187         return super.getAnnotations();
    188     }
    189 
    190     /**
    191      * Returns an array of arrays that represent the annotations of the formal
    192      * parameters of this method. If there are no parameters on this method,
    193      * then an empty array is returned. If there are no annotations set, then
    194      * and array of empty arrays is returned.
    195      *
    196      * @return an array of arrays of {@code Annotation} instances
    197      */
    198     public abstract Annotation[][] getParameterAnnotations();
    199 
    200     /**
    201      * Returns the constructor's signature in non-printable form. This is called
    202      * (only) from IO native code and needed for deriving the serialVersionUID
    203      * of the class
    204      *
    205      * @return The constructor's signature.
    206      */
    207     @SuppressWarnings("unused")
    208     abstract String getSignature();
    209 
    210     static final class GenericInfo {
    211         final ListOfTypes genericExceptionTypes;
    212         final ListOfTypes genericParameterTypes;
    213         final Type genericReturnType;
    214         final TypeVariable<?>[] formalTypeParameters;
    215 
    216         GenericInfo(ListOfTypes exceptions, ListOfTypes parameters, Type ret,
    217                     TypeVariable<?>[] formal) {
    218             genericExceptionTypes = exceptions;
    219             genericParameterTypes = parameters;
    220             genericReturnType = ret;
    221             formalTypeParameters = formal;
    222         }
    223     }
    224 
    225     /**
    226      * Returns generic information associated with this method/constructor member.
    227      */
    228     final GenericInfo getMethodOrConstructorGenericInfo() {
    229         String signatureAttribute = AnnotationAccess.getSignature(this);
    230         Member member;
    231         Class<?>[] exceptionTypes;
    232         boolean method = this instanceof Method;
    233         if (method) {
    234             Method m = (Method) this;
    235             member = m;
    236             exceptionTypes = m.getExceptionTypes();
    237         } else {
    238             Constructor<?> c = (Constructor<?>) this;
    239             member = c;
    240             exceptionTypes = c.getExceptionTypes();
    241         }
    242         GenericSignatureParser parser =
    243             new GenericSignatureParser(member.getDeclaringClass().getClassLoader());
    244         if (method) {
    245             parser.parseForMethod((GenericDeclaration) this, signatureAttribute, exceptionTypes);
    246         } else {
    247             parser.parseForConstructor((GenericDeclaration) this,
    248                                        signatureAttribute,
    249                                        exceptionTypes);
    250         }
    251         return new GenericInfo(parser.exceptionTypes, parser.parameterTypes,
    252                                parser.returnType, parser.formalTypeParameters);
    253     }
    254 
    255     /**
    256      * Helper for Method and Constructor for toGenericString
    257      */
    258     final String toGenericStringHelper() {
    259         StringBuilder sb = new StringBuilder(80);
    260         GenericInfo info =  getMethodOrConstructorGenericInfo();
    261         int modifiers = ((Member)this).getModifiers();
    262         // append modifiers if any
    263         if (modifiers != 0) {
    264             sb.append(Modifier.toString(modifiers & ~Modifier.VARARGS)).append(' ');
    265         }
    266         // append type parameters
    267         if (info.formalTypeParameters != null && info.formalTypeParameters.length > 0) {
    268             sb.append('<');
    269             for (int i = 0; i < info.formalTypeParameters.length; i++) {
    270                 Types.appendGenericType(sb, info.formalTypeParameters[i]);
    271                 if (i < info.formalTypeParameters.length - 1) {
    272                     sb.append(",");
    273                 }
    274             }
    275             sb.append("> ");
    276         }
    277         Class<?> declaringClass = ((Member) this).getDeclaringClass();
    278         if (this instanceof Constructor) {
    279             // append constructor name
    280             Types.appendTypeName(sb, declaringClass);
    281         } else {
    282             // append return type
    283             Types.appendGenericType(sb, Types.getType(info.genericReturnType));
    284             sb.append(' ');
    285             // append method name
    286             Types.appendTypeName(sb, declaringClass);
    287             sb.append(".").append(((Method) this).getName());
    288         }
    289         // append parameters
    290         sb.append('(');
    291         Types.appendArrayGenericType(sb, info.genericParameterTypes.getResolvedTypes());
    292         sb.append(')');
    293         // append exceptions if any
    294         Type[] genericExceptionTypeArray =
    295             Types.getTypeArray(info.genericExceptionTypes, false);
    296         if (genericExceptionTypeArray.length > 0) {
    297             sb.append(" throws ");
    298             Types.appendArrayGenericType(sb, genericExceptionTypeArray);
    299         }
    300         return sb.toString();
    301     }
    302 }
    303