1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.bcel.generic;
18
19 import java.util.ArrayList;
20 import java.util.List;
21 import org.apache.bcel.Constants;
22 import org.apache.bcel.classfile.ClassFormatException;
23 import org.apache.bcel.classfile.Utility;
24
25 /***
26 * Abstract super class for all possible java types, namely basic types
27 * such as int, object types like String and array types, e.g. int[]
28 *
29 * @version $Id: Type.java 393344 2006-04-12 00:38:34Z tcurdt $
30 * @author <A HREF="mailto:m.dahm@gmx.de">M. Dahm</A>
31 */
32 public abstract class Type implements java.io.Serializable {
33
34 protected byte type;
35 protected String signature;
36 /*** Predefined constants
37 */
38 public static final BasicType VOID = new BasicType(Constants.T_VOID);
39 public static final BasicType BOOLEAN = new BasicType(Constants.T_BOOLEAN);
40 public static final BasicType INT = new BasicType(Constants.T_INT);
41 public static final BasicType SHORT = new BasicType(Constants.T_SHORT);
42 public static final BasicType BYTE = new BasicType(Constants.T_BYTE);
43 public static final BasicType LONG = new BasicType(Constants.T_LONG);
44 public static final BasicType DOUBLE = new BasicType(Constants.T_DOUBLE);
45 public static final BasicType FLOAT = new BasicType(Constants.T_FLOAT);
46 public static final BasicType CHAR = new BasicType(Constants.T_CHAR);
47 public static final ObjectType OBJECT = new ObjectType("java.lang.Object");
48 public static final ObjectType CLASS = new ObjectType("java.lang.Class");
49 public static final ObjectType STRING = new ObjectType("java.lang.String");
50 public static final ObjectType STRINGBUFFER = new ObjectType("java.lang.StringBuffer");
51 public static final ObjectType THROWABLE = new ObjectType("java.lang.Throwable");
52 public static final Type[] NO_ARGS = new Type[0];
53 public static final ReferenceType NULL = new ReferenceType() {
54 };
55 public static final Type UNKNOWN = new Type(Constants.T_UNKNOWN, "<unknown object>") {
56 };
57
58
59 protected Type(byte t, String s) {
60 type = t;
61 signature = s;
62 }
63
64
65 /***
66 * @return hashcode of Type
67 */
68 public int hashCode() {
69 return type ^ signature.hashCode();
70 }
71
72
73 /***
74 * @return whether the Types are equal
75 */
76 public boolean equals(Object o) {
77 if (o instanceof Type) {
78 Type t = (Type)o;
79 return (type == t.type) && signature.equals(t.signature);
80 }
81 return false;
82 }
83
84
85 /***
86 * @return signature for given type.
87 */
88 public String getSignature() {
89 return signature;
90 }
91
92
93 /***
94 * @return type as defined in Constants
95 */
96 public byte getType() {
97 return type;
98 }
99
100
101 /***
102 * @return stack size of this type (2 for long and double, 0 for void, 1 otherwise)
103 */
104 public int getSize() {
105 switch (type) {
106 case Constants.T_DOUBLE:
107 case Constants.T_LONG:
108 return 2;
109 case Constants.T_VOID:
110 return 0;
111 default:
112 return 1;
113 }
114 }
115
116
117 /***
118 * @return Type string, e.g. `int[]'
119 */
120 public String toString() {
121 return ((this.equals(Type.NULL) || (type >= Constants.T_UNKNOWN))) ? signature : Utility
122 .signatureToString(signature, false);
123 }
124
125
126 /***
127 * Convert type to Java method signature, e.g. int[] f(java.lang.String x)
128 * becomes (Ljava/lang/String;)[I
129 *
130 * @param return_type what the method returns
131 * @param arg_types what are the argument types
132 * @return method signature for given type(s).
133 */
134 public static String getMethodSignature( Type return_type, Type[] arg_types ) {
135 StringBuffer buf = new StringBuffer("(");
136 int length = (arg_types == null) ? 0 : arg_types.length;
137 for (int i = 0; i < length; i++) {
138 buf.append(arg_types[i].getSignature());
139 }
140 buf.append(')');
141 buf.append(return_type.getSignature());
142 return buf.toString();
143 }
144
145 private static ThreadLocal consumed_chars = new ThreadLocal() {
146
147 protected Object initialValue() {
148 return new Integer(0);
149 }
150 };
151
152
153 private static int unwrap( ThreadLocal tl ) {
154 return ((Integer) tl.get()).intValue();
155 }
156
157
158 private static void wrap( ThreadLocal tl, int value ) {
159 tl.set(new Integer(value));
160 }
161
162
163 /***
164 * Convert signature to a Type object.
165 * @param signature signature string such as Ljava/lang/String;
166 * @return type object
167 */
168 public static final Type getType( String signature ) throws StringIndexOutOfBoundsException {
169 byte type = Utility.typeOfSignature(signature);
170 if (type <= Constants.T_VOID) {
171
172 wrap(consumed_chars, 1);
173 return BasicType.getType(type);
174 } else if (type == Constants.T_ARRAY) {
175 int dim = 0;
176 do {
177 dim++;
178 } while (signature.charAt(dim) == '[');
179
180 Type t = getType(signature.substring(dim));
181
182
183 int _temp = unwrap(consumed_chars) + dim;
184 wrap(consumed_chars, _temp);
185 return new ArrayType(t, dim);
186 } else {
187 int index = signature.indexOf(';');
188 if (index < 0) {
189 throw new ClassFormatException("Invalid signature: " + signature);
190 }
191
192 wrap(consumed_chars, index + 1);
193 return new ObjectType(signature.substring(1, index).replace('/', '.'));
194 }
195 }
196
197
198 /***
199 * Convert return value of a method (signature) to a Type object.
200 *
201 * @param signature signature string such as (Ljava/lang/String;)V
202 * @return return type
203 */
204 public static Type getReturnType( String signature ) {
205 try {
206
207 int index = signature.lastIndexOf(')') + 1;
208 return getType(signature.substring(index));
209 } catch (StringIndexOutOfBoundsException e) {
210 throw new ClassFormatException("Invalid method signature: " + signature);
211 }
212 }
213
214
215 /***
216 * Convert arguments of a method (signature) to an array of Type objects.
217 * @param signature signature string such as (Ljava/lang/String;)V
218 * @return array of argument types
219 */
220 public static Type[] getArgumentTypes( String signature ) {
221 List vec = new ArrayList();
222 int index;
223 Type[] types;
224 try {
225 if (signature.charAt(0) != '(') {
226 throw new ClassFormatException("Invalid method signature: " + signature);
227 }
228 index = 1;
229 while (signature.charAt(index) != ')') {
230 vec.add(getType(signature.substring(index)));
231
232 index += unwrap(consumed_chars);
233 }
234 } catch (StringIndexOutOfBoundsException e) {
235 throw new ClassFormatException("Invalid method signature: " + signature);
236 }
237 types = new Type[vec.size()];
238 vec.toArray(types);
239 return types;
240 }
241
242
243 /*** Convert runtime java.lang.Class to BCEL Type object.
244 * @param cl Java class
245 * @return corresponding Type object
246 */
247 public static Type getType( java.lang.Class cl ) {
248 if (cl == null) {
249 throw new IllegalArgumentException("Class must not be null");
250 }
251
252
253
254 if (cl.isArray()) {
255 return getType(cl.getName());
256 } else if (cl.isPrimitive()) {
257 if (cl == Integer.TYPE) {
258 return INT;
259 } else if (cl == Void.TYPE) {
260 return VOID;
261 } else if (cl == Double.TYPE) {
262 return DOUBLE;
263 } else if (cl == Float.TYPE) {
264 return FLOAT;
265 } else if (cl == Boolean.TYPE) {
266 return BOOLEAN;
267 } else if (cl == Byte.TYPE) {
268 return BYTE;
269 } else if (cl == Short.TYPE) {
270 return SHORT;
271 } else if (cl == Byte.TYPE) {
272 return BYTE;
273 } else if (cl == Long.TYPE) {
274 return LONG;
275 } else if (cl == Character.TYPE) {
276 return CHAR;
277 } else {
278 throw new IllegalStateException("Ooops, what primitive type is " + cl);
279 }
280 } else {
281 return new ObjectType(cl.getName());
282 }
283 }
284
285
286 /***
287 * Convert runtime java.lang.Class[] to BCEL Type objects.
288 * @param classes an array of runtime class objects
289 * @return array of corresponding Type objects
290 */
291 public static Type[] getTypes( java.lang.Class[] classes ) {
292 Type[] ret = new Type[classes.length];
293 for (int i = 0; i < ret.length; i++) {
294 ret[i] = getType(classes[i]);
295 }
296 return ret;
297 }
298
299
300 public static String getSignature( java.lang.reflect.Method meth ) {
301 StringBuffer sb = new StringBuffer("(");
302 Class[] params = meth.getParameterTypes();
303 for (int j = 0; j < params.length; j++) {
304 sb.append(getType(params[j]).getSignature());
305 }
306 sb.append(")");
307 sb.append(getType(meth.getReturnType()).getSignature());
308 return sb.toString();
309 }
310 }