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 libcore.reflect;
18 
19 import java.lang.reflect.GenericArrayType;
20 import java.lang.reflect.ParameterizedType;
21 import java.lang.reflect.Type;
22 import java.lang.reflect.TypeVariable;
23 import java.util.HashMap;
24 import java.util.Map;
25 import libcore.util.EmptyArray;
26 
27 public final class Types {
Types()28     private Types() {
29     }
30 
31     // Holds a mapping from Java type names to native type codes.
32     private static final Map<Class<?>, String> PRIMITIVE_TO_SIGNATURE;
33     static {
34         PRIMITIVE_TO_SIGNATURE = new HashMap<Class<?>, String>(9);
PRIMITIVE_TO_SIGNATURE.put(byte.class, "B")35         PRIMITIVE_TO_SIGNATURE.put(byte.class, "B");
PRIMITIVE_TO_SIGNATURE.put(char.class, "C")36         PRIMITIVE_TO_SIGNATURE.put(char.class, "C");
PRIMITIVE_TO_SIGNATURE.put(short.class, "S")37         PRIMITIVE_TO_SIGNATURE.put(short.class, "S");
PRIMITIVE_TO_SIGNATURE.put(int.class, "I")38         PRIMITIVE_TO_SIGNATURE.put(int.class, "I");
PRIMITIVE_TO_SIGNATURE.put(long.class, "J")39         PRIMITIVE_TO_SIGNATURE.put(long.class, "J");
PRIMITIVE_TO_SIGNATURE.put(float.class, "F")40         PRIMITIVE_TO_SIGNATURE.put(float.class, "F");
PRIMITIVE_TO_SIGNATURE.put(double.class, "D")41         PRIMITIVE_TO_SIGNATURE.put(double.class, "D");
PRIMITIVE_TO_SIGNATURE.put(void.class, "V")42         PRIMITIVE_TO_SIGNATURE.put(void.class, "V");
PRIMITIVE_TO_SIGNATURE.put(boolean.class, "Z")43         PRIMITIVE_TO_SIGNATURE.put(boolean.class, "Z");
44     }
45 
getTypeArray(ListOfTypes types, boolean clone)46     public static Type[] getTypeArray(ListOfTypes types, boolean clone) {
47         if (types.length() == 0) {
48             return EmptyArray.TYPE;
49         }
50         Type[] result = types.getResolvedTypes();
51         return clone ? result.clone() : result;
52     }
53 
getType(Type type)54     public static Type getType(Type type) {
55         if (type instanceof ParameterizedTypeImpl) {
56             return ((ParameterizedTypeImpl)type).getResolvedType();
57         }
58         return type;
59     }
60 
61     /**
62      * Returns the internal name of {@code clazz} (also known as the descriptor).
63      */
getSignature(Class<?> clazz)64     public static String getSignature(Class<?> clazz) {
65         String primitiveSignature = PRIMITIVE_TO_SIGNATURE.get(clazz);
66         if (primitiveSignature != null) {
67             return primitiveSignature;
68         } else if (clazz.isArray()) {
69             return "[" + getSignature(clazz.getComponentType());
70         } else {
71             // TODO: this separates packages with '.' rather than '/'
72             return "L" + clazz.getName() + ";";
73         }
74     }
75 
76     /**
77      * Returns the names of {@code types} separated by commas.
78      */
toString(Class<?>[] types)79     public static String toString(Class<?>[] types) {
80         if (types.length == 0) {
81             return "";
82         }
83         StringBuilder result = new StringBuilder();
84         appendTypeName(result, types[0]);
85         for (int i = 1; i < types.length; i++) {
86             result.append(',');
87             appendTypeName(result, types[i]);
88         }
89         return result.toString();
90     }
91 
92     /**
93      * Appends the best {@link #toString} name for {@code c} to {@code out}.
94      * This works around the fact that {@link Class#getName} is lousy for
95      * primitive arrays (it writes "[C" instead of "char[]") and {@link
96      * Class#getCanonicalName()} is lousy for nested classes (it uses a "."
97      * separator rather than a "$" separator).
98      */
appendTypeName(StringBuilder out, Class<?> c)99     public static void appendTypeName(StringBuilder out, Class<?> c) {
100         int dimensions = 0;
101         while (c.isArray()) {
102             c = c.getComponentType();
103             dimensions++;
104         }
105         out.append(c.getName());
106         for (int d = 0; d < dimensions; d++) {
107             out.append("[]");
108         }
109     }
110 
111     /**
112      * Appends names of the {@code types} to {@code out} separated by commas.
113      */
appendArrayGenericType(StringBuilder out, Type[] types)114     public static void appendArrayGenericType(StringBuilder out, Type[] types) {
115         if (types.length == 0) {
116             return;
117         }
118         appendGenericType(out, types[0]);
119         for (int i = 1; i < types.length; i++) {
120             out.append(',');
121             appendGenericType(out, types[i]);
122         }
123     }
124 
appendGenericType(StringBuilder out, Type type)125     public static void appendGenericType(StringBuilder out, Type type) {
126         if (type instanceof TypeVariable) {
127             out.append(((TypeVariable) type).getName());
128         } else if (type instanceof ParameterizedType) {
129             out.append(type.toString());
130         } else if (type instanceof GenericArrayType) {
131             Type simplified = ((GenericArrayType) type).getGenericComponentType();
132             appendGenericType(out, simplified);
133             out.append("[]");
134         } else if (type instanceof Class) {
135             Class c = (Class<?>) type;
136             if (c.isArray()){
137                 String as[] = c.getName().split("\\[");
138                 int len = as.length-1;
139                 if (as[len].length() > 1){
140                     out.append(as[len].substring(1, as[len].length() - 1));
141                 } else {
142                     char ch = as[len].charAt(0);
143                     if (ch == 'I') {
144                         out.append("int");
145                     } else if (ch == 'B') {
146                         out.append("byte");
147                     } else if (ch == 'J') {
148                         out.append("long");
149                     } else if (ch == 'F') {
150                         out.append("float");
151                     } else if (ch == 'D') {
152                         out.append("double");
153                     } else if (ch == 'S') {
154                         out.append("short");
155                     } else if (ch == 'C') {
156                         out.append("char");
157                     } else if (ch == 'Z') {
158                         out.append("boolean");
159                     } else if (ch == 'V') {
160                         out.append("void");
161                     }
162                 }
163                 for (int i = 0; i < len; i++){
164                     out.append("[]");
165                 }
166             } else {
167                 out.append(c.getName());
168             }
169         }
170     }
171 }
172