KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javassist > bytecode > Descriptor


1 /*
2  * Javassist, a Java-bytecode translator toolkit.
3  * Copyright (C) 1999-2005 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
16 package javassist.bytecode;
17
18 import javassist.ClassPool;
19 import javassist.CtClass;
20 import javassist.CtPrimitiveType;
21 import javassist.NotFoundException;
22 import java.util.Map JavaDoc;
23
24 /**
25  * A support class for dealing with descriptors.
26  *
27  * <p>See chapter 4.3 in "The Java Virtual Machine Specification (2nd ed.)"
28  */

29 public class Descriptor {
30     /**
31      * Converts a class name into the internal representation used in
32      * the JVM.
33      *
34      * <p>Note that <code>toJvmName(toJvmName(s))</code> is equivalent
35      * to <code>toJvmName(s)</code>.
36      */

37     public static String JavaDoc toJvmName(String JavaDoc classname) {
38         return classname.replace('.', '/');
39     }
40
41     /**
42      * Converts a class name from the internal representation used in
43      * the JVM to the normal one used in Java.
44      */

45     public static String JavaDoc toJavaName(String JavaDoc classname) {
46         return classname.replace('/', '.');
47     }
48
49     /**
50      * Returns the internal representation of the class name in the
51      * JVM.
52      */

53     public static String JavaDoc toJvmName(CtClass clazz) {
54         if (clazz.isArray())
55             return of(clazz);
56         else
57             return toJvmName(clazz.getName());
58     }
59
60     /**
61      * Converts to a Java class name from a descriptor
62      */

63     public static String JavaDoc toClassName(String JavaDoc descriptor) {
64         if (descriptor.equals("V"))
65             return "void";
66         else if (descriptor.equals("I"))
67             return "int";
68         else if (descriptor.equals("B"))
69             return "byte";
70         else if (descriptor.equals("J"))
71             return "long";
72         else if (descriptor.equals("D"))
73             return "double";
74         else if (descriptor.equals("F"))
75             return "float";
76         else if (descriptor.equals("C"))
77             return "char";
78         else if (descriptor.equals("S"))
79             return "short";
80         else if (descriptor.equals("Z"))
81             return "boolean";
82         else {
83             String JavaDoc newname = toJavaName(descriptor);
84             return newname.substring(1, newname.length() - 1);
85         }
86     }
87
88     /**
89      * Converts to a descriptor from a Java class name
90      */

91     public static String JavaDoc of(String JavaDoc classname) {
92         if (classname.equals("void"))
93             return "V";
94         else if (classname.equals("int"))
95             return "I";
96         else if (classname.equals("byte"))
97             return "B";
98         else if (classname.equals("long"))
99             return "J";
100         else if (classname.equals("double"))
101             return "D";
102         else if (classname.equals("float"))
103             return "F";
104         else if (classname.equals("char"))
105             return "C";
106         else if (classname.equals("short"))
107             return "S";
108         else if (classname.equals("boolean"))
109             return "Z";
110         else
111             return "L" + toJvmName(classname) + ";";
112     }
113
114     /**
115      * Substitutes a class name
116      * in the given descriptor string.
117      *
118      * @param desc descriptor string
119      * @param oldname replaced JVM class name
120      * @param newname substituted JVM class name
121      *
122      * @see Descriptor#toJvmName(String)
123      */

124     public static String JavaDoc rename(String JavaDoc desc, String JavaDoc oldname, String JavaDoc newname) {
125         if (desc.indexOf(oldname) < 0)
126             return desc;
127
128         StringBuffer JavaDoc newdesc = new StringBuffer JavaDoc();
129         int head = 0;
130         int i = 0;
131         for (;;) {
132             int j = desc.indexOf('L', i);
133             if (j < 0)
134                 break;
135             else if (desc.startsWith(oldname, j + 1)
136                      && desc.charAt(j + oldname.length() + 1) == ';') {
137                 newdesc.append(desc.substring(head, j));
138                 newdesc.append('L');
139                 newdesc.append(newname);
140                 newdesc.append(';');
141                 head = i = j + oldname.length() + 2;
142             }
143             else {
144                 i = desc.indexOf(';', j) + 1;
145                 if (i < 1)
146                     break; // ';' was not found.
147
}
148         }
149
150         if (head == 0)
151             return desc;
152         else {
153             int len = desc.length();
154             if (head < len)
155                 newdesc.append(desc.substring(head, len));
156
157             return newdesc.toString();
158         }
159     }
160
161     /**
162      * Substitutes class names in the given descriptor string
163      * according to the given <code>map</code>.
164      *
165      * @param map a map between replaced and substituted
166      * JVM class names.
167      * @see Descriptor#toJvmName(String)
168      */

169     public static String JavaDoc rename(String JavaDoc desc, Map JavaDoc map) {
170         if (map == null)
171             return desc;
172
173         StringBuffer JavaDoc newdesc = new StringBuffer JavaDoc();
174         int head = 0;
175         int i = 0;
176         for (;;) {
177             int j = desc.indexOf('L', i);
178             if (j < 0)
179                 break;
180
181             int k = desc.indexOf(';', j);
182             if (k < 0)
183                 break;
184
185             i = k + 1;
186             String JavaDoc name = desc.substring(j + 1, k);
187             String JavaDoc name2 = (String JavaDoc)map.get(name);
188             if (name2 != null) {
189                 newdesc.append(desc.substring(head, j));
190                 newdesc.append('L');
191                 newdesc.append(name2);
192                 newdesc.append(';');
193                 head = i;
194             }
195         }
196
197         if (head == 0)
198             return desc;
199         else {
200             int len = desc.length();
201             if (head < len)
202                 newdesc.append(desc.substring(head, len));
203
204             return newdesc.toString();
205         }
206     }
207
208     /**
209      * Returns the descriptor representing the given type.
210      */

211     public static String JavaDoc of(CtClass type) {
212         StringBuffer JavaDoc sbuf = new StringBuffer JavaDoc();
213         toDescriptor(sbuf, type);
214         return sbuf.toString();
215     }
216
217     private static void toDescriptor(StringBuffer JavaDoc desc, CtClass type) {
218         if (type.isArray()) {
219             desc.append('[');
220             try {
221                 toDescriptor(desc, type.getComponentType());
222             }
223             catch (NotFoundException e) {
224                 desc.append('L');
225                 String JavaDoc name = type.getName();
226                 desc.append(toJvmName(name.substring(0, name.length() - 2)));
227                 desc.append(';');
228             }
229         }
230         else if (type.isPrimitive()) {
231             CtPrimitiveType pt = (CtPrimitiveType)type;
232             desc.append(pt.getDescriptor());
233         }
234         else { // class type
235
desc.append('L');
236             desc.append(type.getName().replace('.', '/'));
237             desc.append(';');
238         }
239     }
240
241     /**
242      * Returns the descriptor representing a constructor receiving
243      * the given parameter types.
244      *
245      * @param paramTypes parameter types
246      */

247     public static String JavaDoc ofConstructor(CtClass[] paramTypes) {
248         return ofMethod(CtClass.voidType, paramTypes);
249     }
250
251     /**
252      * Returns the descriptor representing a method that receives
253      * the given parameter types and returns the given type.
254      *
255      * @param returnType return type
256      * @param paramTypes parameter types
257      */

258     public static String JavaDoc ofMethod(CtClass returnType, CtClass[] paramTypes) {
259         StringBuffer JavaDoc desc = new StringBuffer JavaDoc();
260         desc.append('(');
261         if (paramTypes != null) {
262             int n = paramTypes.length;
263             for (int i = 0; i < n; ++i)
264                 toDescriptor(desc, paramTypes[i]);
265         }
266
267         desc.append(')');
268         if (returnType != null)
269             toDescriptor(desc, returnType);
270
271         return desc.toString();
272     }
273
274     /**
275      * Returns the descriptor representing a list of parameter types.
276      * For example, if the given parameter types are two <code>int</code>,
277      * then this method returns <code>"(II)"</code>.
278      *
279      * @param paramTypes parameter types
280      */

281     public static String JavaDoc ofParameters(CtClass[] paramTypes) {
282         return ofMethod(null, paramTypes);
283     }
284
285     /**
286      * Appends a parameter type to the parameter list represented
287      * by the given descriptor.
288      *
289      * <p><code>classname</code> must not be an array type.
290      *
291      * @param classname parameter type (not primitive type)
292      * @param desc descriptor
293      */

294     public static String JavaDoc appendParameter(String JavaDoc classname, String JavaDoc desc) {
295         int i = desc.indexOf(')');
296         if (i < 0)
297             return desc;
298         else {
299             StringBuffer JavaDoc newdesc = new StringBuffer JavaDoc();
300             newdesc.append(desc.substring(0, i));
301             newdesc.append('L');
302             newdesc.append(classname.replace('.', '/'));
303             newdesc.append(';');
304             newdesc.append(desc.substring(i));
305             return newdesc.toString();
306         }
307     }
308
309     /**
310      * Inserts a parameter type at the beginning of the parameter
311      * list represented
312      * by the given descriptor.
313      *
314      * <p><code>classname</code> must not be an array type.
315      *
316      * @param classname parameter type (not primitive type)
317      * @param desc descriptor
318      */

319     public static String JavaDoc insertParameter(String JavaDoc classname, String JavaDoc desc) {
320         if (desc.charAt(0) != '(')
321             return desc;
322         else
323             return "(L" + classname.replace('.', '/') + ';'
324                    + desc.substring(1);
325     }
326
327     /**
328      * Changes the return type included in the given descriptor.
329      *
330      * <p><code>classname</code> must not be an array type.
331      *
332      * @param classname return type
333      * @param desc descriptor
334      */

335     public static String JavaDoc changeReturnType(String JavaDoc classname, String JavaDoc desc) {
336         int i = desc.indexOf(')');
337         if (i < 0)
338             return desc;
339         else {
340             StringBuffer JavaDoc newdesc = new StringBuffer JavaDoc();
341             newdesc.append(desc.substring(0, i + 1));
342             newdesc.append('L');
343             newdesc.append(classname.replace('.', '/'));
344             newdesc.append(';');
345             return newdesc.toString();
346         }
347     }
348
349     /**
350      * Returns the <code>CtClass</code> objects representing the parameter
351      * types specified by the given descriptor.
352      *
353      * @param desc descriptor
354      * @param cp the class pool used for obtaining
355      * a <code>CtClass</code> object.
356      */

357     public static CtClass[] getParameterTypes(String JavaDoc desc, ClassPool cp)
358         throws NotFoundException
359     {
360         if (desc.charAt(0) != '(')
361             return null;
362         else {
363             int num = numOfParameters(desc);
364             CtClass[] args = new CtClass[num];
365             int n = 0;
366             int i = 1;
367             do {
368                 i = toCtClass(cp, desc, i, args, n++);
369             } while (i > 0);
370             return args;
371         }
372     }
373
374     /**
375      * Returns true if the list of the parameter types of desc1 is equal to
376      * that of desc2.
377      * For example, "(II)V" and "(II)I" are equal.
378      */

379     public static boolean eqParamTypes(String JavaDoc desc1, String JavaDoc desc2) {
380         if (desc1.charAt(0) != '(')
381             return false;
382
383         for (int i = 0; true; ++i) {
384             char c = desc1.charAt(i);
385             if (c != desc2.charAt(i))
386                 return false;
387
388             if (c == ')')
389                 return true;
390         }
391     }
392
393     /**
394      * Returns the signature of the given descriptor. The signature does
395      * not include the return type. For example, the signature of "(I)V"
396      * is "(I)".
397      */

398     public static String JavaDoc getParamDescriptor(String JavaDoc decl) {
399         return decl.substring(0, decl.indexOf(')') + 1);
400     }
401
402     /**
403      * Returns the <code>CtClass</code> object representing the return
404      * type specified by the given descriptor.
405      *
406      * @param desc descriptor
407      * @param cp the class pool used for obtaining
408      * a <code>CtClass</code> object.
409      */

410     public static CtClass getReturnType(String JavaDoc desc, ClassPool cp)
411         throws NotFoundException
412     {
413         int i = desc.indexOf(')');
414         if (i < 0)
415             return null;
416         else {
417             CtClass[] type = new CtClass[1];
418             toCtClass(cp, desc, i + 1, type, 0);
419             return type[0];
420         }
421     }
422
423     /**
424      * Returns the number of the prameters included in the given
425      * descriptor.
426      *
427      * @param desc descriptor
428      */

429     public static int numOfParameters(String JavaDoc desc) {
430         int n = 0;
431         int i = 1;
432         for (;;) {
433             char c = desc.charAt(i);
434             if (c == ')')
435                 break;
436
437             while (c == '[')
438                 c = desc.charAt(++i);
439
440             if (c == 'L') {
441                 i = desc.indexOf(';', i) + 1;
442                 if (i <= 0)
443                     throw new IndexOutOfBoundsException JavaDoc("bad descriptor");
444             }
445             else
446                 ++i;
447
448             ++n;
449         }
450
451         return n;
452     }
453
454     /**
455      * Returns a <code>CtClass</code> object representing the type
456      * specified by the given descriptor.
457      *
458      * <p>This method works even if the package-class separator is
459      * not <code>/</code> but <code>.</code> (period). For example,
460      * it accepts <code>Ljava.lang.Object;</code>
461      * as well as <code>Ljava/lang/Object;</code>.
462      *
463      * @param desc descriptor
464      * @param cp the class pool used for obtaining
465      * a <code>CtClass</code> object.
466      */

467     public static CtClass toCtClass(String JavaDoc desc, ClassPool cp)
468         throws NotFoundException
469     {
470         CtClass[] clazz = new CtClass[1];
471         int res = toCtClass(cp, desc, 0, clazz, 0);
472         if (res >= 0)
473             return clazz[0];
474         else {
475             // maybe, you forgot to surround the class name with
476
// L and ;. It violates the protocol, but I'm tolerant...
477
return cp.get(desc.replace('/', '.'));
478         }
479     }
480
481     private static int toCtClass(ClassPool cp, String JavaDoc desc, int i,
482                                  CtClass[] args, int n)
483         throws NotFoundException
484     {
485         int i2;
486         String JavaDoc name;
487
488         int arrayDim = 0;
489         char c = desc.charAt(i);
490         while (c == '[') {
491             ++arrayDim;
492             c = desc.charAt(++i);
493         }
494
495         if (c == 'L') {
496             i2 = desc.indexOf(';', ++i);
497             name = desc.substring(i, i2++).replace('/', '.');
498         }
499         else {
500             CtClass type = toPrimitiveClass(c);
501             if (type == null)
502                 return -1; // error
503

504             i2 = i + 1;
505             if (arrayDim == 0) {
506                 args[n] = type;
507                 return i2; // neither an array type or a class type
508
}
509             else
510                 name = type.getName();
511         }
512
513         if (arrayDim > 0) {
514             StringBuffer JavaDoc sbuf = new StringBuffer JavaDoc(name);
515             while (arrayDim-- > 0)
516                 sbuf.append("[]");
517
518             name = sbuf.toString();
519         }
520
521         args[n] = cp.get(name);
522         return i2;
523     }
524
525     private static CtClass toPrimitiveClass(char c) {
526         CtClass type = null;
527         switch (c) {
528         case 'Z' :
529             type = CtClass.booleanType;
530             break;
531         case 'C' :
532             type = CtClass.charType;
533             break;
534         case 'B' :
535             type = CtClass.byteType;
536             break;
537         case 'S' :
538             type = CtClass.shortType;
539             break;
540         case 'I' :
541             type = CtClass.intType;
542             break;
543         case 'J' :
544             type = CtClass.longType;
545             break;
546         case 'F' :
547             type = CtClass.floatType;
548             break;
549         case 'D' :
550             type = CtClass.doubleType;
551             break;
552         case 'V' :
553             type = CtClass.voidType;
554             break;
555         }
556
557         return type;
558     }
559
560     /**
561      * Computes the dimension of the array represented by the given
562      * descriptor. For example, if the descriptor is <code>"[[I"</code>,
563      * then this method returns 2.
564      *
565      * @param desc the descriptor.
566      * @return 0 if the descriptor does not represent an array type.
567      */

568     public static int arrayDimension(String JavaDoc desc) {
569         int dim = 0;
570         while (desc.charAt(dim) == '[')
571             ++dim;
572
573         return dim;
574     }
575
576     /**
577      * Returns the descriptor of the type of the array component.
578      * For example, if the given descriptor is
579      * <code>"[[Ljava/lang/String;"</code> and the given dimension is 2,
580      * then this method returns <code>"Ljava/lang/String;"</code>.
581      *
582      * @param desc the descriptor.
583      * @param dim the array dimension.
584      */

585     public static String JavaDoc toArrayComponent(String JavaDoc desc, int dim) {
586         return desc.substring(dim);
587     }
588
589     /**
590      * Computes the data size specified by the given descriptor.
591      * For example, if the descriptor is "D", this method returns 2.
592      *
593      * <p>If the descriptor represents a method type, this method returns
594      * (the size of the returned value) - (the sum of the data sizes
595      * of all the parameters). For example, if the descriptor is
596      * "(I)D", then this method returns 1 (= 2 - 1).
597      *
598      * @param desc descriptor
599      */

600     public static int dataSize(String JavaDoc desc) {
601         int n = 0;
602         char c = desc.charAt(0);
603         if (c == '(') {
604             int i = 1;
605             for (;;) {
606                 c = desc.charAt(i);
607                 if (c == ')') {
608                     c = desc.charAt(i + 1);
609                     break;
610                 }
611
612                 boolean array = false;
613                 while (c == '[') {
614                     array = true;
615                     c = desc.charAt(++i);
616                 }
617
618                 if (c == 'L') {
619                     i = desc.indexOf(';', i) + 1;
620                     if (i <= 0)
621                         throw new IndexOutOfBoundsException JavaDoc("bad descriptor");
622                 }
623                 else
624                     ++i;
625
626                 if (!array && (c == 'J' || c == 'D'))
627                     n -= 2;
628                 else
629                     --n;
630             }
631         }
632
633         if (c == 'J' || c == 'D')
634             n += 2;
635         else if (c != 'V')
636             ++n;
637
638         return n;
639     }
640 }
641
Popular Tags