1/*
2 * Javassist, a Java-bytecode translator toolkit.
3 * Copyright (C) 1999-2007 Shigeru Chiba. All Rights Reserved.
4 *
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License.  Alternatively, the contents of this file may be used under
8 * the terms of the GNU Lesser General Public License Version 2.1 or later.
9 *
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
14 */
15
16package javassist.runtime;
17
18/**
19 * A support class for implementing <code>$sig</code> and
20 * <code>$type</code>.
21 * This support class is required at runtime
22 * only if <code>$sig</code> or <code>$type</code> is used.
23 */
24public class Desc {
25
26    /**
27     * Specifies how a <code>java.lang.Class</code> object is loaded.
28     *
29     * <p>If true, it is loaded by:
30     * <ul><pre>Thread.currentThread().getContextClassLoader().loadClass()</pre></ul>
31     * <p>If false, it is loaded by <code>Class.forName()</code>.
32     * The default value is false.
33     */
34    public static boolean useContextClassLoader = false;
35
36    private static Class getClassObject(String name)
37        throws ClassNotFoundException
38    {
39        if (useContextClassLoader)
40            return Thread.currentThread().getContextClassLoader()
41                   .loadClass(name);
42        else
43            return Class.forName(name);
44    }
45
46    /**
47     * Interprets the given class name.
48     * It is used for implementing <code>$class</code>.
49     */
50    public static Class getClazz(String name) {
51        try {
52            return getClassObject(name);
53        }
54        catch (ClassNotFoundException e) {
55            throw new RuntimeException(
56                    "$class: internal error, could not find class '" + name
57                    + "' (Desc.useContextClassLoader: "
58                    + Boolean.toString(useContextClassLoader) + ")", e);
59        }
60    }
61
62    /**
63     * Interprets the given type descriptor representing a method
64     * signature.  It is used for implementing <code>$sig</code>.
65     */
66    public static Class[] getParams(String desc) {
67        if (desc.charAt(0) != '(')
68            throw new RuntimeException("$sig: internal error");
69
70        return getType(desc, desc.length(), 1, 0);
71    }
72
73    /**
74     * Interprets the given type descriptor.
75     * It is used for implementing <code>$type</code>.
76     */
77    public static Class getType(String desc) {
78        Class[] result = getType(desc, desc.length(), 0, 0);
79        if (result == null || result.length != 1)
80            throw new RuntimeException("$type: internal error");
81
82        return result[0];
83    }
84
85    private static Class[] getType(String desc, int descLen,
86                                   int start, int num) {
87        Class clazz;
88        if (start >= descLen)
89            return new Class[num];
90
91        char c = desc.charAt(start);
92        switch (c) {
93        case 'Z' :
94            clazz = Boolean.TYPE;
95            break;
96        case 'C' :
97            clazz = Character.TYPE;
98            break;
99        case 'B' :
100            clazz = Byte.TYPE;
101            break;
102        case 'S' :
103            clazz = Short.TYPE;
104            break;
105        case 'I' :
106            clazz = Integer.TYPE;
107            break;
108        case 'J' :
109            clazz = Long.TYPE;
110            break;
111        case 'F' :
112            clazz = Float.TYPE;
113            break;
114        case 'D' :
115            clazz = Double.TYPE;
116            break;
117        case 'V' :
118            clazz = Void.TYPE;
119            break;
120        case 'L' :
121        case '[' :
122            return getClassType(desc, descLen, start, num);
123        default :
124            return new Class[num];
125        }
126
127        Class[] result = getType(desc, descLen, start + 1, num + 1);
128        result[num] = clazz;
129        return result;
130    }
131
132    private static Class[] getClassType(String desc, int descLen,
133                                        int start, int num) {
134        int end = start;
135        while (desc.charAt(end) == '[')
136            ++end;
137
138        if (desc.charAt(end) == 'L') {
139            end = desc.indexOf(';', end);
140            if (end < 0)
141                throw new IndexOutOfBoundsException("bad descriptor");
142        }
143
144        String cname;
145        if (desc.charAt(start) == 'L')
146            cname = desc.substring(start + 1, end);
147        else
148            cname = desc.substring(start, end + 1);
149
150        Class[] result = getType(desc, descLen, end + 1, num + 1);
151        try {
152            result[num] = getClassObject(cname.replace('/', '.'));
153        }
154        catch (ClassNotFoundException e) {
155            // "new RuntimeException(e)" is not available in JDK 1.3.
156            throw new RuntimeException(e.getMessage());
157        }
158
159        return result;
160    }
161}
162