1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.bcel.generic;
19
20 import java.util.ArrayList;
21 import java.util.List;
22
23 import org.apache.bcel.Constants;
24 import org.apache.bcel.classfile.ClassFormatException;
25 import org.apache.bcel.classfile.Utility;
26
27
28
29
30
31
32
33
34 public abstract class Type implements java.io.Serializable {
35
36 private static final long serialVersionUID = -1985077286871826895L;
37 protected byte type;
38 protected String signature;
39
40
41 public static final BasicType VOID = new BasicType(Constants.T_VOID);
42 public static final BasicType BOOLEAN = new BasicType(Constants.T_BOOLEAN);
43 public static final BasicType INT = new BasicType(Constants.T_INT);
44 public static final BasicType SHORT = new BasicType(Constants.T_SHORT);
45 public static final BasicType BYTE = new BasicType(Constants.T_BYTE);
46 public static final BasicType LONG = new BasicType(Constants.T_LONG);
47 public static final BasicType DOUBLE = new BasicType(Constants.T_DOUBLE);
48 public static final BasicType FLOAT = new BasicType(Constants.T_FLOAT);
49 public static final BasicType CHAR = new BasicType(Constants.T_CHAR);
50 public static final ObjectType OBJECT = new ObjectType("java.lang.Object");
51 public static final ObjectType CLASS = new ObjectType("java.lang.Class");
52 public static final ObjectType STRING = new ObjectType("java.lang.String");
53 public static final ObjectType STRINGBUFFER = new ObjectType("java.lang.StringBuffer");
54 public static final ObjectType THROWABLE = new ObjectType("java.lang.Throwable");
55 public static final Type[] NO_ARGS = new Type[0];
56 public static final ReferenceType NULL = new ReferenceType() {
57
58 private static final long serialVersionUID = 4526765862386946282L;
59 };
60 public static final Type UNKNOWN = new Type(Constants.T_UNKNOWN, "<unknown object>") {
61
62 private static final long serialVersionUID = 1321113605813486066L;
63 };
64
65
66 protected Type(byte t, String s) {
67 type = t;
68 signature = s;
69 }
70
71
72
73
74
75 @Override
76 public int hashCode() {
77 return type ^ signature.hashCode();
78 }
79
80
81
82
83
84 @Override
85 public boolean equals(Object o) {
86 if (o instanceof Type) {
87 Type t = (Type)o;
88 return (type == t.type) && signature.equals(t.signature);
89 }
90 return false;
91 }
92
93
94
95
96
97 public String getSignature() {
98 return signature;
99 }
100
101
102
103
104
105 public byte getType() {
106 return type;
107 }
108
109
110
111
112
113 public int getSize() {
114 switch (type) {
115 case Constants.T_DOUBLE:
116 case Constants.T_LONG:
117 return 2;
118 case Constants.T_VOID:
119 return 0;
120 default:
121 return 1;
122 }
123 }
124
125
126
127
128
129 @Override
130 public String toString() {
131 return ((this.equals(Type.NULL) || (type >= Constants.T_UNKNOWN))) ? signature : Utility
132 .signatureToString(signature, false);
133 }
134
135
136
137
138
139
140
141
142
143
144 public static String getMethodSignature( Type return_type, Type[] arg_types ) {
145 StringBuilder buf = new StringBuilder("(");
146 if (arg_types != null) {
147 for (Type arg_type : arg_types) {
148 buf.append(arg_type.getSignature());
149 }
150 }
151 buf.append(')');
152 buf.append(return_type.getSignature());
153 return buf.toString();
154 }
155
156 private static final ThreadLocal<Integer> consumed_chars = new ThreadLocal<Integer>() {
157
158 @Override
159 protected Integer initialValue() {
160 return Integer.valueOf(0);
161 }
162 };
163
164
165 private static int unwrap( ThreadLocal<Integer> tl ) {
166 return tl.get().intValue();
167 }
168
169
170 private static void wrap( ThreadLocal<Integer> tl, int value ) {
171 tl.set(Integer.valueOf(value));
172 }
173
174
175
176
177
178
179
180 public static final Type getType( String signature ) throws StringIndexOutOfBoundsException {
181 byte type = Utility.typeOfSignature(signature);
182 if (type <= Constants.T_VOID) {
183
184 wrap(consumed_chars, 1);
185 return BasicType.getType(type);
186 } else if (type == Constants.T_ARRAY) {
187 int dim = 0;
188 do {
189 dim++;
190 } while (signature.charAt(dim) == '[');
191
192 Type t = getType(signature.substring(dim));
193
194
195 int _temp = unwrap(consumed_chars) + dim;
196 wrap(consumed_chars, _temp);
197 return new ArrayType(t, dim);
198 } else {
199 int index = signature.indexOf(';');
200 if (index < 0) {
201 throw new ClassFormatException("Invalid signature: " + signature);
202 }
203
204 wrap(consumed_chars, index + 1);
205 return new ObjectType(signature.substring(1, index).replace('/', '.'));
206 }
207 }
208
209
210
211
212
213
214
215
216 public static Type getReturnType( String signature ) {
217 try {
218
219 int index = signature.lastIndexOf(')') + 1;
220 return getType(signature.substring(index));
221 } catch (StringIndexOutOfBoundsException e) {
222 throw new ClassFormatException("Invalid method signature: " + signature, e);
223 }
224 }
225
226
227
228
229
230
231
232 public static Type[] getArgumentTypes( String signature ) {
233 List<Type> vec = new ArrayList<Type>();
234 int index;
235 Type[] types;
236 try {
237 if (signature.charAt(0) != '(') {
238 throw new ClassFormatException("Invalid method signature: " + signature);
239 }
240 index = 1;
241 while (signature.charAt(index) != ')') {
242 vec.add(getType(signature.substring(index)));
243
244 index += unwrap(consumed_chars);
245 }
246 } catch (StringIndexOutOfBoundsException e) {
247 throw new ClassFormatException("Invalid method signature: " + signature, e);
248 }
249 types = new Type[vec.size()];
250 vec.toArray(types);
251 return types;
252 }
253
254
255
256
257
258
259 public static Type getType( java.lang.Class<?> cl ) {
260 if (cl == null) {
261 throw new IllegalArgumentException("Class must not be null");
262 }
263
264
265
266 if (cl.isArray()) {
267 return getType(cl.getName());
268 } else if (cl.isPrimitive()) {
269 if (cl == Integer.TYPE) {
270 return INT;
271 } else if (cl == Void.TYPE) {
272 return VOID;
273 } else if (cl == Double.TYPE) {
274 return DOUBLE;
275 } else if (cl == Float.TYPE) {
276 return FLOAT;
277 } else if (cl == Boolean.TYPE) {
278 return BOOLEAN;
279 } else if (cl == Byte.TYPE) {
280 return BYTE;
281 } else if (cl == Short.TYPE) {
282 return SHORT;
283 } else if (cl == Byte.TYPE) {
284 return BYTE;
285 } else if (cl == Long.TYPE) {
286 return LONG;
287 } else if (cl == Character.TYPE) {
288 return CHAR;
289 } else {
290 throw new IllegalStateException("Ooops, what primitive type is " + cl);
291 }
292 } else {
293 return new ObjectType(cl.getName());
294 }
295 }
296
297
298
299
300
301
302
303 public static Type[] getTypes( java.lang.Class<?>[] classes ) {
304 Type[] ret = new Type[classes.length];
305 for (int i = 0; i < ret.length; i++) {
306 ret[i] = getType(classes[i]);
307 }
308 return ret;
309 }
310
311
312 public static String getSignature( java.lang.reflect.Method meth ) {
313 StringBuilder sb = new StringBuilder("(");
314 Class<?>[] params = meth.getParameterTypes();
315 for (int j = 0; j < params.length; j++) {
316 sb.append(getType(params[j]).getSignature());
317 }
318 sb.append(")");
319 sb.append(getType(meth.getReturnType()).getSignature());
320 return sb.toString();
321 }
322
323 static int size(int coded) {
324 return coded & 3;
325 }
326
327 static int consumed(int coded) {
328 return coded >> 2;
329 }
330
331 static int encode(int size, int consumed) {
332 return consumed << 2 | size;
333 }
334
335 static int getArgumentTypesSize( String signature ) {
336 int res = 0;
337 int index;
338 try {
339 if (signature.charAt(0) != '(') {
340 throw new ClassFormatException("Invalid method signature: " + signature);
341 }
342 index = 1;
343 while (signature.charAt(index) != ')') {
344 int coded = getTypeSize(signature.substring(index));
345 res += size(coded);
346 index += consumed(coded);
347 }
348 } catch (StringIndexOutOfBoundsException e) {
349 throw new ClassFormatException("Invalid method signature: " + signature, e);
350 }
351 return res;
352 }
353
354 static final int getTypeSize( String signature ) throws StringIndexOutOfBoundsException {
355 byte type = Utility.typeOfSignature(signature);
356 if (type <= Constants.T_VOID) {
357 return encode(BasicType.getType(type).getSize(), 1);
358 } else if (type == Constants.T_ARRAY) {
359 int dim = 0;
360 do {
361 dim++;
362 } while (signature.charAt(dim) == '[');
363
364 int consumed = consumed(getTypeSize(signature.substring(dim)));
365 return encode(1, dim + consumed);
366 } else {
367 int index = signature.indexOf(';');
368 if (index < 0) {
369 throw new ClassFormatException("Invalid signature: " + signature);
370 }
371 return encode(1, index + 1);
372 }
373 }
374
375
376 static int getReturnTypeSize(String signature) {
377 int index = signature.lastIndexOf(')') + 1;
378 return Type.size(getTypeSize(signature.substring(index)));
379 }
380 }