TypeUtils.java revision 674060f01e9090cd21b3c5656cc3204912ad17a6
1/*
2 * Copyright 2003,2004 The Apache Software Foundation
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 */
16package org.mockito.cglib.core;
17
18import java.util.*;
19
20import org.mockito.asm.Type;
21
22public class TypeUtils {
23    private static final Map transforms = new HashMap();
24    private static final Map rtransforms = new HashMap();
25
26    private TypeUtils() {
27    }
28
29    static {
30        transforms.put("void", "V");
31        transforms.put("byte", "B");
32        transforms.put("char", "C");
33        transforms.put("double", "D");
34        transforms.put("float", "F");
35        transforms.put("int", "I");
36        transforms.put("long", "J");
37        transforms.put("short", "S");
38        transforms.put("boolean", "Z");
39
40        CollectionUtils.reverse(transforms, rtransforms);
41    }
42
43    public static Type getType(String className) {
44        return Type.getType("L" + className.replace('.', '/') + ";");
45    }
46
47    public static boolean isFinal(int access) {
48        return (Constants.ACC_FINAL & access) != 0;
49    }
50
51    public static boolean isStatic(int access) {
52        return (Constants.ACC_STATIC & access) != 0;
53    }
54
55    public static boolean isProtected(int access) {
56        return (Constants.ACC_PROTECTED & access) != 0;
57    }
58
59    public static boolean isPublic(int access) {
60        return (Constants.ACC_PUBLIC & access) != 0;
61    }
62
63    public static boolean isAbstract(int access) {
64        return (Constants.ACC_ABSTRACT & access) != 0;
65    }
66
67    public static boolean isInterface(int access) {
68        return (Constants.ACC_INTERFACE & access) != 0;
69    }
70
71    public static boolean isPrivate(int access) {
72        return (Constants.ACC_PRIVATE & access) != 0;
73    }
74
75    public static boolean isSynthetic(int access) {
76        return (Constants.ACC_SYNTHETIC & access) != 0;
77    }
78
79    // getPackage returns null on JDK 1.2
80    public static String getPackageName(Type type) {
81        return getPackageName(getClassName(type));
82    }
83
84    public static String getPackageName(String className) {
85        int idx = className.lastIndexOf('.');
86        return (idx < 0) ? "" : className.substring(0, idx);
87    }
88
89    public static String upperFirst(String s) {
90        if (s == null || s.length() == 0) {
91            return s;
92        }
93        return Character.toUpperCase(s.charAt(0)) + s.substring(1);
94    }
95
96    public static String getClassName(Type type) {
97        if (isPrimitive(type)) {
98            return (String)rtransforms.get(type.getDescriptor());
99        } else if (isArray(type)) {
100            return getClassName(getComponentType(type)) + "[]";
101        } else {
102            return type.getClassName();
103        }
104    }
105
106    public static Type[] add(Type[] types, Type extra) {
107        if (types == null) {
108            return new Type[]{ extra };
109        } else {
110            List list = Arrays.asList(types);
111            if (list.contains(extra)) {
112                return types;
113            }
114            Type[] copy = new Type[types.length + 1];
115            System.arraycopy(types, 0, copy, 0, types.length);
116            copy[types.length] = extra;
117            return copy;
118        }
119    }
120
121    public static Type[] add(Type[] t1, Type[] t2) {
122        // TODO: set semantics?
123        Type[] all = new Type[t1.length + t2.length];
124        System.arraycopy(t1, 0, all, 0, t1.length);
125        System.arraycopy(t2, 0, all, t1.length, t2.length);
126        return all;
127    }
128
129    public static Type fromInternalName(String name) {
130        // TODO; primitives?
131        return Type.getType("L" + name + ";");
132    }
133
134    public static Type[] fromInternalNames(String[] names) {
135        if (names == null) {
136            return null;
137        }
138        Type[] types = new Type[names.length];
139        for (int i = 0; i < names.length; i++) {
140            types[i] = fromInternalName(names[i]);
141        }
142        return types;
143    }
144
145    public static int getStackSize(Type[] types) {
146        int size = 0;
147        for (int i = 0; i < types.length; i++) {
148            size += types[i].getSize();
149        }
150        return size;
151    }
152
153    public static String[] toInternalNames(Type[] types) {
154        if (types == null) {
155            return null;
156        }
157        String[] names = new String[types.length];
158        for (int i = 0; i < types.length; i++) {
159            names[i] = types[i].getInternalName();
160        }
161        return names;
162    }
163
164    public static Signature parseSignature(String s) {
165        int space = s.indexOf(' ');
166        int lparen = s.indexOf('(', space);
167        int rparen = s.indexOf(')', lparen);
168        String returnType = s.substring(0, space);
169        String methodName = s.substring(space + 1, lparen);
170        StringBuffer sb = new StringBuffer();
171        sb.append('(');
172        for (Iterator it = parseTypes(s, lparen + 1, rparen).iterator(); it.hasNext();) {
173            sb.append(it.next());
174        }
175        sb.append(')');
176        sb.append(map(returnType));
177        return new Signature(methodName, sb.toString());
178    }
179
180    public static Type parseType(String s) {
181        return Type.getType(map(s));
182    }
183
184    public static Type[] parseTypes(String s) {
185        List names = parseTypes(s, 0, s.length());
186        Type[] types = new Type[names.size()];
187        for (int i = 0; i < types.length; i++) {
188            types[i] = Type.getType((String)names.get(i));
189        }
190        return types;
191    }
192
193    public static Signature parseConstructor(Type[] types) {
194        StringBuffer sb = new StringBuffer();
195        sb.append("(");
196        for (int i = 0; i < types.length; i++) {
197            sb.append(types[i].getDescriptor());
198        }
199        sb.append(")");
200        sb.append("V");
201        return new Signature(Constants.CONSTRUCTOR_NAME, sb.toString());
202    }
203
204    public static Signature parseConstructor(String sig) {
205        return parseSignature("void <init>(" + sig + ")"); // TODO
206    }
207
208    private static List parseTypes(String s, int mark, int end) {
209        List types = new ArrayList(5);
210        for (;;) {
211            int next = s.indexOf(',', mark);
212            if (next < 0) {
213                break;
214            }
215            types.add(map(s.substring(mark, next).trim()));
216            mark = next + 1;
217        }
218        types.add(map(s.substring(mark, end).trim()));
219        return types;
220    }
221
222    private static String map(String type) {
223        if (type.equals("")) {
224            return type;
225        }
226        String t = (String)transforms.get(type);
227        if (t != null) {
228            return t;
229        } else if (type.indexOf('.') < 0) {
230            return map("java.lang." + type);
231        } else {
232            StringBuffer sb = new StringBuffer();
233            int index = 0;
234            while ((index = type.indexOf("[]", index) + 1) > 0) {
235                sb.append('[');
236            }
237            type = type.substring(0, type.length() - sb.length() * 2);
238            sb.append('L').append(type.replace('.', '/')).append(';');
239            return sb.toString();
240        }
241    }
242
243    public static Type getBoxedType(Type type) {
244        switch (type.getSort()) {
245        case Type.CHAR:
246            return Constants.TYPE_CHARACTER;
247        case Type.BOOLEAN:
248            return Constants.TYPE_BOOLEAN;
249        case Type.DOUBLE:
250            return Constants.TYPE_DOUBLE;
251        case Type.FLOAT:
252            return Constants.TYPE_FLOAT;
253        case Type.LONG:
254            return Constants.TYPE_LONG;
255        case Type.INT:
256            return Constants.TYPE_INTEGER;
257        case Type.SHORT:
258            return Constants.TYPE_SHORT;
259        case Type.BYTE:
260            return Constants.TYPE_BYTE;
261        default:
262            return type;
263        }
264    }
265
266    public static Type getUnboxedType(Type type) {
267        if (Constants.TYPE_INTEGER.equals(type)) {
268            return Type.INT_TYPE;
269        } else if (Constants.TYPE_BOOLEAN.equals(type)) {
270            return Type.BOOLEAN_TYPE;
271        } else if (Constants.TYPE_DOUBLE.equals(type)) {
272            return Type.DOUBLE_TYPE;
273        } else if (Constants.TYPE_LONG.equals(type)) {
274            return Type.LONG_TYPE;
275        } else if (Constants.TYPE_CHARACTER.equals(type)) {
276            return Type.CHAR_TYPE;
277        } else if (Constants.TYPE_BYTE.equals(type)) {
278            return Type.BYTE_TYPE;
279        } else if (Constants.TYPE_FLOAT.equals(type)) {
280            return Type.FLOAT_TYPE;
281        } else if (Constants.TYPE_SHORT.equals(type)) {
282            return Type.SHORT_TYPE;
283        } else {
284            return type;
285        }
286    }
287
288    public static boolean isArray(Type type) {
289        return type.getSort() == Type.ARRAY;
290    }
291
292    public static Type getComponentType(Type type) {
293        if (!isArray(type)) {
294            throw new IllegalArgumentException("Type " + type + " is not an array");
295        }
296        return Type.getType(type.getDescriptor().substring(1));
297    }
298
299    public static boolean isPrimitive(Type type) {
300        switch (type.getSort()) {
301        case Type.ARRAY:
302        case Type.OBJECT:
303            return false;
304        default:
305            return true;
306        }
307    }
308
309    public static String emulateClassGetName(Type type) {
310        if (isArray(type)) {
311            return type.getDescriptor().replace('/', '.');
312        } else {
313            return getClassName(type);
314        }
315    }
316
317    public static boolean isConstructor(MethodInfo method) {
318        return method.getSignature().getName().equals(Constants.CONSTRUCTOR_NAME);
319    }
320
321    public static Type[] getTypes(Class[] classes) {
322        if (classes == null) {
323            return null;
324        }
325        Type[] types = new Type[classes.length];
326        for (int i = 0; i < classes.length; i++) {
327            types[i] = Type.getType(classes[i]);
328        }
329        return types;
330    }
331
332    public static int ICONST(int value) {
333        switch (value) {
334        case -1: return Constants.ICONST_M1;
335        case 0: return Constants.ICONST_0;
336        case 1: return Constants.ICONST_1;
337        case 2: return Constants.ICONST_2;
338        case 3: return Constants.ICONST_3;
339        case 4: return Constants.ICONST_4;
340        case 5: return Constants.ICONST_5;
341        }
342        return -1; // error
343    }
344
345    public static int LCONST(long value) {
346        if (value == 0L) {
347            return Constants.LCONST_0;
348        } else if (value == 1L) {
349            return Constants.LCONST_1;
350        } else {
351            return -1; // error
352        }
353    }
354
355    public static int FCONST(float value) {
356        if (value == 0f) {
357            return Constants.FCONST_0;
358        } else if (value == 1f) {
359            return Constants.FCONST_1;
360        } else if (value == 2f) {
361            return Constants.FCONST_2;
362        } else {
363            return -1; // error
364        }
365    }
366
367    public static int DCONST(double value) {
368        if (value == 0d) {
369            return Constants.DCONST_0;
370        } else if (value == 1d) {
371            return Constants.DCONST_1;
372        } else {
373            return -1; // error
374        }
375    }
376
377    public static int NEWARRAY(Type type) {
378        switch (type.getSort()) {
379        case Type.BYTE:
380            return Constants.T_BYTE;
381        case Type.CHAR:
382            return Constants.T_CHAR;
383        case Type.DOUBLE:
384            return Constants.T_DOUBLE;
385        case Type.FLOAT:
386            return Constants.T_FLOAT;
387        case Type.INT:
388            return Constants.T_INT;
389        case Type.LONG:
390            return Constants.T_LONG;
391        case Type.SHORT:
392            return Constants.T_SHORT;
393        case Type.BOOLEAN:
394            return Constants.T_BOOLEAN;
395        default:
396            return -1; // error
397        }
398    }
399
400    public static String escapeType(String s) {
401        StringBuffer sb = new StringBuffer();
402        for (int i = 0, len = s.length(); i < len; i++) {
403            char c = s.charAt(i);
404            switch (c) {
405            case '$': sb.append("$24"); break;
406            case '.': sb.append("$2E"); break;
407            case '[': sb.append("$5B"); break;
408            case ';': sb.append("$3B"); break;
409            case '(': sb.append("$28"); break;
410            case ')': sb.append("$29"); break;
411            case '/': sb.append("$2F"); break;
412            default:
413                sb.append(c);
414            }
415        }
416        return sb.toString();
417    }
418}
419