1 /* 2 * Copyright (C) 2018 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 package android.signature.cts; 17 18 import java.util.Arrays; 19 import java.util.Collections; 20 import java.util.HashSet; 21 import java.util.Set; 22 23 /** 24 * Represents one class member parsed from the reader of dex signatures. 25 */ 26 public abstract class DexMember { 27 private final String mName; 28 private final String mClassDescriptor; 29 private final String mType; 30 private final Set<String> mFlags; 31 DexMember(String className, String name, String type, String[] flags)32 protected DexMember(String className, String name, String type, String[] flags) { 33 mName = name; 34 mClassDescriptor = className; 35 mType = type; 36 mFlags = flags == null ? Collections.emptySet() : new HashSet<>(Arrays.asList(flags)); 37 } 38 getName()39 public String getName() { 40 return mName; 41 } 42 getDexClassName()43 public String getDexClassName() { 44 return mClassDescriptor; 45 } 46 getJavaClassName()47 public String getJavaClassName() { 48 return dexToJavaType(mClassDescriptor); 49 } 50 getDexType()51 public String getDexType() { 52 return mType; 53 } 54 getJavaType()55 public String getJavaType() { 56 return dexToJavaType(mType); 57 } 58 getHiddenapiFlags()59 public Set<String> getHiddenapiFlags() { 60 return mFlags; 61 } 62 63 /** 64 * Converts `type` to a Java type. 65 */ dexToJavaType(String type)66 protected static String dexToJavaType(String type) { 67 String javaDimension = ""; 68 while (type.startsWith("[")) { 69 javaDimension += "[]"; 70 type = type.substring(1); 71 } 72 73 String javaType = null; 74 if ("V".equals(type)) { 75 javaType = "void"; 76 } else if ("Z".equals(type)) { 77 javaType = "boolean"; 78 } else if ("B".equals(type)) { 79 javaType = "byte"; 80 } else if ("C".equals(type)) { 81 javaType = "char"; 82 } else if ("S".equals(type)) { 83 javaType = "short"; 84 } else if ("I".equals(type)) { 85 javaType = "int"; 86 } else if ("J".equals(type)) { 87 javaType = "long"; 88 } else if ("F".equals(type)) { 89 javaType = "float"; 90 } else if ("D".equals(type)) { 91 javaType = "double"; 92 } else if (type.startsWith("L") && type.endsWith(";")) { 93 javaType = type.substring(1, type.length() - 1).replace('/', '.'); 94 } else { 95 throw new IllegalStateException("Unexpected type " + type); 96 } 97 98 return javaType + javaDimension; 99 } 100 typeToClass(String type)101 public static Class<?> typeToClass(String type) throws ClassNotFoundException { 102 if ("V".equals(type)) { 103 return void.class; 104 } else if ("Z".equals(type)) { 105 return boolean.class; 106 } else if ("B".equals(type)) { 107 return byte.class; 108 } else if ("C".equals(type)) { 109 return char.class; 110 } else if ("S".equals(type)) { 111 return short.class; 112 } else if ("I".equals(type)) { 113 return int.class; 114 } else if ("J".equals(type)) { 115 return long.class; 116 } else if ("F".equals(type)) { 117 return float.class; 118 } else if ("D".equals(type)) { 119 return double.class; 120 } else { 121 // Class names expected for Class.forName are: 122 // * for reference types: Ljava/lang/String; -> java.lang.String 123 // * for array types: [Ljava/lang/String; -> [Ljava.lang.String; 124 type = type.startsWith("L") 125 ? type.substring(1, type.length() - 1).replace('/', '.') 126 : type.replace('/', '.'); 127 } 128 129 return Class.forName(type, /* initialize */ false, DexMember.class.getClassLoader()); 130 } 131 } 132