Home | History | Annotate | Download | only in cts
      1 /*
      2  * Copyright (C) 2008 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.signature.cts;
     18 
     19 import java.lang.reflect.Modifier;
     20 import java.util.ArrayList;
     21 import java.util.Collection;
     22 import java.util.List;
     23 
     24 /**
     25  * Represents class descriptions loaded from a jdiff xml file.  Used
     26  * for CTS SignatureTests.
     27  */
     28 public class JDiffClassDescription {
     29 
     30     public enum JDiffType {
     31         INTERFACE, CLASS
     32     }
     33 
     34     private final String mPackageName;
     35     private final String mShortClassName;
     36 
     37     /**
     38      * Package name + short class name
     39      */
     40     private final String mAbsoluteClassName;
     41 
     42     private int mModifier;
     43 
     44     private String mExtendedClass;
     45     private final List<String> implInterfaces = new ArrayList<>();
     46     private final List<JDiffField> jDiffFields = new ArrayList<>();
     47     private final List<JDiffMethod> jDiffMethods = new ArrayList<>();
     48     private final List<JDiffConstructor> jDiffConstructors = new ArrayList<>();
     49 
     50     private JDiffType mClassType;
     51 
     52     /**
     53      * Creates a new JDiffClassDescription.
     54      *
     55      * @param pkg the java package this class will end up in.
     56      * @param className the name of the class.
     57      */
     58     public JDiffClassDescription(String pkg, String className) {
     59         mPackageName = pkg;
     60         mShortClassName = className;
     61         mAbsoluteClassName = mPackageName + "." + mShortClassName;
     62     }
     63 
     64 
     65     String getPackageName() {
     66         return mPackageName;
     67     }
     68 
     69     public String getShortClassName() {
     70         return mShortClassName;
     71     }
     72 
     73     int getModifier() {
     74         return mModifier;
     75     }
     76 
     77     String getExtendedClass() {
     78         return mExtendedClass;
     79     }
     80 
     81     List<String> getImplInterfaces() {
     82         return implInterfaces;
     83     }
     84 
     85     List<JDiffField> getFields() {
     86         return jDiffFields;
     87     }
     88 
     89     List<JDiffMethod> getMethods() {
     90         return jDiffMethods;
     91     }
     92 
     93     List<JDiffConstructor> getConstructors() {
     94         return jDiffConstructors;
     95     }
     96 
     97     JDiffType getClassType() {
     98         return mClassType;
     99     }
    100 
    101     /**
    102      * adds implemented interface name.
    103      *
    104      * @param iname name of interface
    105      */
    106     public void addImplInterface(String iname) {
    107         implInterfaces.add(iname);
    108     }
    109 
    110     /**
    111      * Adds a field.
    112      *
    113      * @param field the field to be added.
    114      */
    115     public void addField(JDiffField field) {
    116         jDiffFields.add(field);
    117     }
    118 
    119     /**
    120      * Adds a method.
    121      *
    122      * @param method the method to be added.
    123      */
    124     public void addMethod(JDiffMethod method) {
    125         jDiffMethods.add(method);
    126     }
    127 
    128     /**
    129      * Adds a constructor.
    130      *
    131      * @param tc the constructor to be added.
    132      */
    133     public void addConstructor(JDiffConstructor tc) {
    134         jDiffConstructors.add(tc);
    135     }
    136 
    137     private static String convertModifiersToAccessLevel(int modifiers) {
    138         if ((modifiers & Modifier.PUBLIC) != 0) {
    139             return "public";
    140         } else if ((modifiers & Modifier.PRIVATE) != 0) {
    141             return "private";
    142         } else if ((modifiers & Modifier.PROTECTED) != 0) {
    143             return "protected";
    144         } else {
    145             // package protected
    146             return "";
    147         }
    148     }
    149 
    150     private static String convertModifersToModifierString(int modifiers) {
    151         StringBuilder sb = new StringBuilder();
    152         String separator = "";
    153 
    154         // order taken from Java Language Spec, sections 8.1.1, 8.3.1, and 8.4.3
    155         if ((modifiers & Modifier.ABSTRACT) != 0) {
    156             sb.append(separator).append("abstract");
    157             separator = " ";
    158         }
    159         if ((modifiers & Modifier.STATIC) != 0) {
    160             sb.append(separator).append("static");
    161             separator = " ";
    162         }
    163         if ((modifiers & Modifier.FINAL) != 0) {
    164             sb.append(separator).append("final");
    165             separator = " ";
    166         }
    167         if ((modifiers & Modifier.TRANSIENT) != 0) {
    168             sb.append(separator).append("transient");
    169             separator = " ";
    170         }
    171         if ((modifiers & Modifier.VOLATILE) != 0) {
    172             sb.append(separator).append("volatile");
    173             separator = " ";
    174         }
    175         if ((modifiers & Modifier.SYNCHRONIZED) != 0) {
    176             sb.append(separator).append("synchronized");
    177             separator = " ";
    178         }
    179         if ((modifiers & Modifier.NATIVE) != 0) {
    180             sb.append(separator).append("native");
    181             separator = " ";
    182         }
    183         if ((modifiers & Modifier.STRICT) != 0) {
    184             sb.append(separator).append("strictfp");
    185         }
    186 
    187         return sb.toString();
    188     }
    189 
    190     abstract static class JDiffElement {
    191         final String mName;
    192         int mModifier;
    193 
    194         JDiffElement(String name, int modifier) {
    195             mName = name;
    196             mModifier = modifier;
    197         }
    198     }
    199 
    200     /**
    201      * Represents a  field.
    202      */
    203     public static final class JDiffField extends JDiffElement {
    204         final String mFieldType;
    205         private final String mFieldValue;
    206 
    207         public JDiffField(String name, String fieldType, int modifier, String value) {
    208             super(name, modifier);
    209 
    210             mFieldType = fieldType;
    211             mFieldValue = value;
    212         }
    213 
    214         /**
    215          * A string representation of the value within the field.
    216          */
    217         public String getValueString() {
    218             return mFieldValue;
    219         }
    220 
    221         /**
    222          * Make a readable string according to the class name specified.
    223          *
    224          * @param className The specified class name.
    225          * @return A readable string to represent this field along with the class name.
    226          */
    227         String toReadableString(String className) {
    228             return className + "#" + mName + "(" + mFieldType + ")";
    229         }
    230 
    231         public String toSignatureString() {
    232             StringBuilder sb = new StringBuilder();
    233 
    234             // access level
    235             String accesLevel = convertModifiersToAccessLevel(mModifier);
    236             if (!"".equals(accesLevel)) {
    237                 sb.append(accesLevel).append(" ");
    238             }
    239 
    240             String modifierString = convertModifersToModifierString(mModifier);
    241             if (!"".equals(modifierString)) {
    242                 sb.append(modifierString).append(" ");
    243             }
    244 
    245             sb.append(mFieldType).append(" ");
    246 
    247             sb.append(mName);
    248 
    249             return sb.toString();
    250         }
    251     }
    252 
    253     /**
    254      * Represents a method.
    255      */
    256     public static class JDiffMethod extends JDiffElement {
    257         final String mReturnType;
    258         final ArrayList<String> mParamList;
    259         final ArrayList<String> mExceptionList;
    260 
    261         public JDiffMethod(String name, int modifier, String returnType) {
    262             super(name, modifier);
    263 
    264             if (returnType == null) {
    265                 mReturnType = "void";
    266             } else {
    267                 mReturnType = scrubJdiffParamType(returnType);
    268             }
    269 
    270             mParamList = new ArrayList<>();
    271             mExceptionList = new ArrayList<>();
    272         }
    273 
    274         /**
    275          * Adds a parameter.
    276          *
    277          * @param param parameter type
    278          */
    279         public void addParam(String param) {
    280             mParamList.add(scrubJdiffParamType(param));
    281         }
    282 
    283         /**
    284          * Adds an exception.
    285          *
    286          * @param exceptionName name of exception
    287          */
    288         public void addException(String exceptionName) {
    289             mExceptionList.add(exceptionName);
    290         }
    291 
    292         /**
    293          * Makes a readable string according to the class name specified.
    294          *
    295          * @param className The specified class name.
    296          * @return A readable string to represent this method along with the class name.
    297          */
    298         String toReadableString(String className) {
    299             return className + "#" + mName + "(" + convertParamList(mParamList) + ")";
    300         }
    301 
    302         /**
    303          * Converts a parameter array to a string
    304          *
    305          * @param params the array to convert
    306          * @return converted parameter string
    307          */
    308         private static String convertParamList(final ArrayList<String> params) {
    309 
    310             StringBuilder paramList = new StringBuilder();
    311 
    312             if (params != null) {
    313                 for (String str : params) {
    314                     paramList.append(str).append(", ");
    315                 }
    316                 if (params.size() > 0) {
    317                     paramList.delete(paramList.length() - 2, paramList.length());
    318                 }
    319             }
    320 
    321             return paramList.toString();
    322         }
    323 
    324         public String toSignatureString() {
    325             StringBuilder sb = new StringBuilder();
    326 
    327             // access level
    328             String accesLevel = convertModifiersToAccessLevel(mModifier);
    329             if (!"".equals(accesLevel)) {
    330                 sb.append(accesLevel).append(" ");
    331             }
    332 
    333             String modifierString = convertModifersToModifierString(mModifier);
    334             if (!"".equals(modifierString)) {
    335                 sb.append(modifierString).append(" ");
    336             }
    337 
    338             String returnType = getReturnType();
    339             if (!"".equals(returnType)) {
    340                 sb.append(returnType).append(" ");
    341             }
    342 
    343             sb.append(mName);
    344             sb.append("(");
    345             for (int x = 0; x < mParamList.size(); x++) {
    346                 sb.append(mParamList.get(x));
    347                 if (x + 1 != mParamList.size()) {
    348                     sb.append(", ");
    349                 }
    350             }
    351             sb.append(")");
    352 
    353             // does it throw?
    354             if (mExceptionList.size() > 0) {
    355                 sb.append(" throws ");
    356                 for (int x = 0; x < mExceptionList.size(); x++) {
    357                     sb.append(mExceptionList.get(x));
    358                     if (x + 1 != mExceptionList.size()) {
    359                         sb.append(", ");
    360                     }
    361                 }
    362             }
    363 
    364             return sb.toString();
    365         }
    366 
    367         /**
    368          * Gets the return type.
    369          *
    370          * @return the return type of this method.
    371          */
    372         String getReturnType() {
    373             return mReturnType;
    374         }
    375     }
    376 
    377     /**
    378      * Represents a constructor.
    379      */
    380     public static final class JDiffConstructor extends JDiffMethod {
    381         public JDiffConstructor(String name, int modifier) {
    382             super(name, modifier, null);
    383         }
    384 
    385         /**
    386          * Gets the return type.
    387          *
    388          * @return the return type of this method.
    389          */
    390         @Override
    391         protected String getReturnType() {
    392             // Constructors have no return type.
    393             return "";
    394         }
    395     }
    396 
    397     /**
    398      * Gets the list of fields found within this class.
    399      *
    400      * @return the list of fields.
    401      */
    402     public Collection<JDiffField> getFieldList() {
    403         return jDiffFields;
    404     }
    405 
    406     /**
    407      * Convert the class into a printable signature string.
    408      *
    409      * @return the signature string
    410      */
    411     public String toSignatureString() {
    412         StringBuilder sb = new StringBuilder();
    413 
    414         String accessLevel = convertModifiersToAccessLevel(mModifier);
    415         if (!"".equals(accessLevel)) {
    416             sb.append(accessLevel).append(" ");
    417         }
    418         if (!JDiffType.INTERFACE.equals(mClassType)) {
    419             String modifierString = convertModifersToModifierString(mModifier);
    420             if (!"".equals(modifierString)) {
    421                 sb.append(modifierString).append(" ");
    422             }
    423             sb.append("class ");
    424         } else {
    425             sb.append("interface ");
    426         }
    427         // class name
    428         sb.append(mShortClassName);
    429 
    430         // does it extends something?
    431         if (mExtendedClass != null) {
    432             sb.append(" extends ").append(mExtendedClass).append(" ");
    433         }
    434 
    435         // implements something?
    436         if (implInterfaces.size() > 0) {
    437             sb.append(" implements ");
    438             for (int x = 0; x < implInterfaces.size(); x++) {
    439                 String interf = implInterfaces.get(x);
    440                 sb.append(interf);
    441                 // if not last elements
    442                 if (x + 1 != implInterfaces.size()) {
    443                     sb.append(", ");
    444                 }
    445             }
    446         }
    447         return sb.toString();
    448     }
    449 
    450     /**
    451      * Sees if the class under test is actually an enum.
    452      *
    453      * @return true if this class is enum
    454      */
    455     boolean isEnumType() {
    456         return "java.lang.Enum".equals(mExtendedClass);
    457     }
    458 
    459     /**
    460      * Sees if the class under test is actually an annotation.
    461      *
    462      * @return true if this class is Annotation.
    463      */
    464     boolean isAnnotation() {
    465         return implInterfaces.contains("java.lang.annotation.Annotation");
    466     }
    467 
    468     /**
    469      * Gets the class name for the class under test.
    470      *
    471      * @return the class name.
    472      */
    473     String getClassName() {
    474         return mShortClassName;
    475     }
    476 
    477     /**
    478      * Gets the package name + short class name
    479      *
    480      * @return The package + short class name
    481      */
    482     public String getAbsoluteClassName() {
    483         return mAbsoluteClassName;
    484     }
    485 
    486     /**
    487      * Sets the modifier for the class under test.
    488      *
    489      * @param modifier the modifier
    490      */
    491     public void setModifier(int modifier) {
    492         mModifier = modifier;
    493     }
    494 
    495     /**
    496      * Sets the return type for the class under test.
    497      *
    498      * @param type the return type
    499      */
    500     public void setType(JDiffType type) {
    501         mClassType = type;
    502     }
    503 
    504     /**
    505      * Sets the class that is beign extended for the class under test.
    506      *
    507      * @param extendsClass the class being extended.
    508      */
    509     void setExtendsClass(String extendsClass) {
    510         mExtendedClass = extendsClass;
    511     }
    512 
    513     /**
    514      * Cleans up jdiff parameters to canonicalize them.
    515      *
    516      * @param paramType the parameter from jdiff.
    517      * @return the scrubbed version of the parameter.
    518      */
    519     private static String scrubJdiffParamType(String paramType) {
    520         // <? extends java.lang.Object and <?> are the same, so
    521         // canonicalize them to one form.
    522         return paramType
    523             .replace("? extends java.lang.Object", "?")
    524             .replace("? super java.lang.Object", "? super ?");
    525     }
    526 
    527     @Override
    528     public String toString() {
    529         return mAbsoluteClassName;
    530     }
    531 }
    532