KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > oracle > toplink > libraries > asm > Type


1 /***
2  * ASM: a very small and fast Java bytecode manipulation framework
3  * Copyright (c) 2000,2002,2003 INRIA, France Telecom
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  * 3. Neither the name of the copyright holders nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
28  * THE POSSIBILITY OF SUCH DAMAGE.
29  */

30
31 package oracle.toplink.libraries.asm;
32
33 import java.lang.reflect.Method JavaDoc;
34
35 /**
36  * A Java type. This class can be used to make it easier to manipulate type
37  * and method descriptors.
38  *
39  * @author Eric Bruneton, Chris Nokleberg
40  */

41
42 public class Type {
43
44   /**
45    * The sort of the <tt>void</tt> type. See {@link #getSort getSort}.
46    */

47
48   public final static int VOID = 0;
49
50   /**
51    * The sort of the <tt>boolean</tt> type. See {@link #getSort getSort}.
52    */

53
54   public final static int BOOLEAN = 1;
55
56   /**
57    * The sort of the <tt>char</tt> type. See {@link #getSort getSort}.
58    */

59
60   public final static int CHAR = 2;
61
62   /**
63    * The sort of the <tt>byte</tt> type. See {@link #getSort getSort}.
64    */

65
66   public final static int BYTE = 3;
67
68   /**
69    * The sort of the <tt>short</tt> type. See {@link #getSort getSort}.
70    */

71
72   public final static int SHORT = 4;
73
74   /**
75    * The sort of the <tt>int</tt> type. See {@link #getSort getSort}.
76    */

77
78   public final static int INT = 5;
79
80   /**
81    * The sort of the <tt>float</tt> type. See {@link #getSort getSort}.
82    */

83
84   public final static int FLOAT = 6;
85
86   /**
87    * The sort of the <tt>long</tt> type. See {@link #getSort getSort}.
88    */

89
90   public final static int LONG = 7;
91
92   /**
93    * The sort of the <tt>double</tt> type. See {@link #getSort getSort}.
94    */

95
96   public final static int DOUBLE = 8;
97
98   /**
99    * The sort of array reference types. See {@link #getSort getSort}.
100    */

101
102   public final static int ARRAY = 9;
103
104   /**
105    * The sort of object reference type. See {@link #getSort getSort}.
106    */

107
108   public final static int OBJECT = 10;
109
110   /**
111    * The <tt>void</tt> type.
112    */

113
114   public final static Type VOID_TYPE = new Type(VOID);
115
116   /**
117    * The <tt>boolean</tt> type.
118    */

119
120   public final static Type BOOLEAN_TYPE = new Type(BOOLEAN);
121
122   /**
123    * The <tt>char</tt> type.
124    */

125
126   public final static Type CHAR_TYPE = new Type(CHAR);
127
128   /**
129    * The <tt>byte</tt> type.
130    */

131
132   public final static Type BYTE_TYPE = new Type(BYTE);
133
134   /**
135    * The <tt>short</tt> type.
136    */

137
138   public final static Type SHORT_TYPE = new Type(SHORT);
139
140   /**
141    * The <tt>int</tt> type.
142    */

143
144   public final static Type INT_TYPE = new Type(INT);
145
146   /**
147    * The <tt>float</tt> type.
148    */

149
150   public final static Type FLOAT_TYPE = new Type(FLOAT);
151
152   /**
153    * The <tt>long</tt> type.
154    */

155
156   public final static Type LONG_TYPE = new Type(LONG);
157
158   /**
159    * The <tt>double</tt> type.
160    */

161
162   public final static Type DOUBLE_TYPE = new Type(DOUBLE);
163
164   // --------------------------------------------------------------------------
165
// Fields
166
// --------------------------------------------------------------------------
167

168   /**
169    * The sort of this Java type.
170    */

171
172   private final int sort;
173
174   /**
175    * A buffer containing the descriptor of this Java type.
176    * This field is only used for reference types.
177    */

178
179   private char[] buf;
180
181   /**
182    * The offset of the descriptor of this Java type in {@link #buf buf}.
183    * This field is only used for reference types.
184    */

185
186   private int off;
187
188   /**
189    * The length of the descriptor of this Java type.
190    */

191
192   private int len;
193
194   // --------------------------------------------------------------------------
195
// Constructors
196
// --------------------------------------------------------------------------
197

198   /**
199    * Constructs a primitive type.
200    *
201    * @param sort the sort of the primitive type to be constructed.
202    */

203
204   private Type (final int sort) {
205     this.sort = sort;
206     this.len = 1;
207   }
208
209   /**
210    * Constructs a reference type.
211    *
212    * @param sort the sort of the reference type to be constructed.
213    * @param buf a buffer containing the descriptor of the previous type.
214    * @param off the offset of this descriptor in the previous buffer.
215    * @param len the length of this descriptor.
216    */

217
218   private Type (
219     final int sort,
220     final char[] buf,
221     final int off,
222     final int len)
223   {
224     this.sort = sort;
225     this.buf = buf;
226     this.off = off;
227     this.len = len;
228   }
229
230   /**
231    * Returns the Java type corresponding to the given type descriptor.
232    *
233    * @param typeDescriptor a type descriptor.
234    * @return the Java type corresponding to the given type descriptor.
235    */

236
237   public static Type getType (final String JavaDoc typeDescriptor) {
238     return getType(typeDescriptor.toCharArray(), 0);
239   }
240
241   /**
242    * Returns the Java type corresponding to the given class.
243    *
244    * @param c a class.
245    * @return the Java type corresponding to the given class.
246    */

247
248   public static Type getType (final Class JavaDoc c) {
249     if (c.isPrimitive()) {
250       if (c == Integer.TYPE) {
251         return INT_TYPE;
252       } else if (c == Void.TYPE) {
253         return VOID_TYPE;
254       } else if (c == Boolean.TYPE) {
255         return BOOLEAN_TYPE;
256       } else if (c == Byte.TYPE) {
257         return BYTE_TYPE;
258       } else if (c == Character.TYPE) {
259         return CHAR_TYPE;
260       } else if (c == Short.TYPE) {
261         return SHORT_TYPE;
262       } else if (c == Double.TYPE) {
263         return DOUBLE_TYPE;
264       } else if (c == Float.TYPE) {
265         return FLOAT_TYPE;
266       } else /*if (c == Long.TYPE)*/ {
267         return LONG_TYPE;
268       }
269     } else {
270       return getType(getDescriptor(c));
271     }
272   }
273
274   /**
275    * Returns the Java types corresponding to the argument types of the given
276    * method descriptor.
277    *
278    * @param methodDescriptor a method descriptor.
279    * @return the Java types corresponding to the argument types of the given
280    * method descriptor.
281    */

282
283   public static Type[] getArgumentTypes (final String JavaDoc methodDescriptor) {
284     char[] buf = methodDescriptor.toCharArray();
285     int off = 1;
286     int size = 0;
287     while (true) {
288       char car = buf[off++];
289       if (car == ')') {
290         break;
291       } else if (car == 'L') {
292         while (buf[off++] != ';') {
293         }
294         ++size;
295       } else if (car != '[') {
296         ++size;
297       }
298     }
299     Type[] args = new Type[size];
300     off = 1;
301     size = 0;
302     while (buf[off] != ')') {
303       args[size] = getType(buf, off);
304       off += args[size].len;
305       size += 1;
306     }
307     return args;
308   }
309
310   /**
311    * Returns the Java types corresponding to the argument types of the given
312    * method.
313    *
314    * @param method a method.
315    * @return the Java types corresponding to the argument types of the given
316    * method.
317    */

318
319   public static Type[] getArgumentTypes (final Method JavaDoc method) {
320     Class JavaDoc[] classes = method.getParameterTypes();
321     Type[] types = new Type[classes.length];
322     for (int i = classes.length - 1; i >= 0; --i) {
323       types[i] = getType(classes[i]);
324     }
325     return types;
326   }
327
328   /**
329    * Returns the Java type corresponding to the return type of the given
330    * method descriptor.
331    *
332    * @param methodDescriptor a method descriptor.
333    * @return the Java type corresponding to the return type of the given
334    * method descriptor.
335    */

336
337   public static Type getReturnType (final String JavaDoc methodDescriptor) {
338     char[] buf = methodDescriptor.toCharArray();
339     return getType(buf, methodDescriptor.indexOf(')') + 1);
340   }
341
342   /**
343    * Returns the Java type corresponding to the return type of the given
344    * method.
345    *
346    * @param method a method.
347    * @return the Java type corresponding to the return type of the given
348    * method.
349    */

350
351   public static Type getReturnType (final Method JavaDoc method) {
352     return getType(method.getReturnType());
353   }
354
355   /**
356    * Returns the Java type corresponding to the given type descriptor.
357    *
358    * @param buf a buffer containing a type descriptor.
359    * @param off the offset of this descriptor in the previous buffer.
360    * @return the Java type corresponding to the given type descriptor.
361    */

362
363   private static Type getType (final char[] buf, final int off) {
364     int len;
365     switch (buf[off]) {
366       case 'V': return VOID_TYPE;
367       case 'Z': return BOOLEAN_TYPE;
368       case 'C': return CHAR_TYPE;
369       case 'B': return BYTE_TYPE;
370       case 'S': return SHORT_TYPE;
371       case 'I': return INT_TYPE;
372       case 'F': return FLOAT_TYPE;
373       case 'J': return LONG_TYPE;
374       case 'D': return DOUBLE_TYPE;
375       case '[':
376         len = 1;
377         while (buf[off + len] == '[') {
378           ++len;
379         }
380         if (buf[off + len] == 'L') {
381           ++len;
382           while (buf[off + len] != ';') {
383             ++len;
384           }
385         }
386         return new Type(ARRAY, buf, off, len + 1);
387       //case 'L':
388
default:
389         len = 1;
390         while (buf[off + len] != ';') {
391           ++len;
392         }
393         return new Type(OBJECT, buf, off, len + 1);
394     }
395   }
396
397   // --------------------------------------------------------------------------
398
// Accessors
399
// --------------------------------------------------------------------------
400

401   /**
402    * Returns the sort of this Java type.
403    *
404    * @return {@link #VOID VOID}, {@link #BOOLEAN BOOLEAN}, {@link #CHAR CHAR},
405    * {@link #BYTE BYTE}, {@link #SHORT SHORT}, {@link #INT INT}, {@link
406    * #FLOAT FLOAT}, {@link #LONG LONG}, {@link #DOUBLE DOUBLE}, {@link
407    * #ARRAY ARRAY} or {@link #OBJECT OBJECT}.
408    */

409
410   public int getSort () {
411     return sort;
412   }
413
414   /**
415    * Returns the number of dimensions of this array type.
416    * This method should only be used for an array type.
417    *
418    * @return the number of dimensions of this array type.
419    */

420
421   public int getDimensions () {
422     int i = 1;
423     while (buf[off + i] == '[') {
424       ++i;
425     }
426     return i;
427   }
428
429   /**
430    * Returns the type of the elements of this array type.
431    * This method should only be used for an array type.
432    *
433    * @return Returns the type of the elements of this array type.
434    */

435
436   public Type getElementType () {
437     return getType(buf, off + getDimensions());
438   }
439
440   /**
441    * Returns the name of the class corresponding to this type.
442    *
443    * @return the fully qualified name of the class corresponding to this type.
444    */

445
446   public String JavaDoc getClassName () {
447     switch (sort) {
448       case VOID: return "void";
449       case BOOLEAN: return "boolean";
450       case CHAR: return "char";
451       case BYTE: return "byte";
452       case SHORT: return "short";
453       case INT: return "int";
454       case FLOAT: return "float";
455       case LONG: return "long";
456       case DOUBLE: return "double";
457       case ARRAY:
458         StringBuffer JavaDoc b = new StringBuffer JavaDoc(getElementType().getClassName());
459         for (int i = getDimensions(); i > 0; --i) {
460           b.append("[]");
461         }
462         return b.toString();
463       //case OBJECT:
464
default:
465         return new String JavaDoc(buf, off + 1, len - 2).replace('/', '.');
466     }
467   }
468
469   /**
470    * Returns the internal name of the class corresponding to this object type.
471    * The internal name of a class is its fully qualified name, where '.' are
472    * replaced by '/'. This method should only be used for an object type.
473    *
474    * @return the internal name of the class corresponding to this object type.
475    */

476
477   public String JavaDoc getInternalName () {
478     return new String JavaDoc(buf, off + 1, len - 2);
479   }
480
481   // --------------------------------------------------------------------------
482
// Conversion to type descriptors
483
// --------------------------------------------------------------------------
484

485   /**
486    * Returns the descriptor corresponding to this Java type.
487    *
488    * @return the descriptor corresponding to this Java type.
489    */

490
491   public String JavaDoc getDescriptor () {
492     StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
493     getDescriptor(buf);
494     return buf.toString();
495   }
496
497   /**
498    * Returns the descriptor corresponding to the given argument and return
499    * types.
500    *
501    * @param returnType the return type of the method.
502    * @param argumentTypes the argument types of the method.
503    * @return the descriptor corresponding to the given argument and return
504    * types.
505    */

506
507   public static String JavaDoc getMethodDescriptor (
508     final Type returnType,
509     final Type[] argumentTypes)
510   {
511     StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
512     buf.append('(');
513     for (int i = 0; i < argumentTypes.length; ++i) {
514       argumentTypes[i].getDescriptor(buf);
515     }
516     buf.append(')');
517     returnType.getDescriptor(buf);
518     return buf.toString();
519   }
520
521   /**
522    * Appends the descriptor corresponding to this Java type to the given string
523    * buffer.
524    *
525    * @param buf the string buffer to which the descriptor must be appended.
526    */

527
528   private void getDescriptor (final StringBuffer JavaDoc buf) {
529     switch (sort) {
530       case VOID: buf.append('V'); return;
531       case BOOLEAN: buf.append('Z'); return;
532       case CHAR: buf.append('C'); return;
533       case BYTE: buf.append('B'); return;
534       case SHORT: buf.append('S'); return;
535       case INT: buf.append('I'); return;
536       case FLOAT: buf.append('F'); return;
537       case LONG: buf.append('J'); return;
538       case DOUBLE: buf.append('D'); return;
539       //case ARRAY:
540
//case OBJECT:
541
default: buf.append(this.buf, off, len);
542     }
543   }
544
545   // --------------------------------------------------------------------------
546
// Direct conversion from classes to type descriptors,
547
// without intermediate Type objects
548
// --------------------------------------------------------------------------
549

550   /**
551    * Returns the internal name of the given class. The internal name of a class
552    * is its fully qualified name, where '.' are replaced by '/'.
553    *
554    * @param c an object class.
555    * @return the internal name of the given class.
556    */

557
558   public static String JavaDoc getInternalName (final Class JavaDoc c) {
559     return c.getName().replace('.', '/');
560   }
561
562   /**
563    * Returns the descriptor corresponding to the given Java type.
564    *
565    * @param c an object class, a primitive class or an array class.
566    * @return the descriptor corresponding to the given class.
567    */

568
569   public static String JavaDoc getDescriptor (final Class JavaDoc c) {
570     StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
571     getDescriptor(buf, c);
572     return buf.toString();
573   }
574
575   /**
576    * Returns the descriptor corresponding to the given method.
577    *
578    * @param m a {@link Method Method} object.
579    * @return the descriptor of the given method.
580    */

581
582   public static String JavaDoc getMethodDescriptor (final Method JavaDoc m) {
583     Class JavaDoc[] parameters = m.getParameterTypes();
584     StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
585     buf.append('(');
586     for (int i = 0; i < parameters.length; ++i) {
587       getDescriptor(buf, parameters[i]);
588     }
589     buf.append(')');
590     getDescriptor(buf, m.getReturnType());
591     return buf.toString();
592   }
593
594   /**
595    * Appends the descriptor of the given class to the given string buffer.
596    *
597    * @param buf the string buffer to which the descriptor must be appended.
598    * @param c the class whose descriptor must be computed.
599    */

600
601   private static void getDescriptor (final StringBuffer JavaDoc buf, final Class JavaDoc c) {
602     Class JavaDoc d = c;
603     while (true) {
604       if (d.isPrimitive()) {
605         char car;
606         if (d == Integer.TYPE) {
607           car = 'I';
608         } else if (d == Void.TYPE) {
609           car = 'V';
610         } else if (d == Boolean.TYPE) {
611           car = 'Z';
612         } else if (d == Byte.TYPE) {
613           car = 'B';
614         } else if (d == Character.TYPE) {
615           car = 'C';
616         } else if (d == Short.TYPE) {
617           car = 'S';
618         } else if (d == Double.TYPE) {
619           car = 'D';
620         } else if (d == Float.TYPE) {
621           car = 'F';
622         } else /*if (d == Long.TYPE)*/ {
623           car = 'J';
624         }
625         buf.append(car);
626         return;
627       } else if (d.isArray()) {
628         buf.append('[');
629         d = d.getComponentType();
630       } else {
631         buf.append('L');
632         String JavaDoc name = d.getName();
633         int len = name.length();
634         for (int i = 0; i < len; ++i) {
635           char car = name.charAt(i);
636           buf.append(car == '.' ? '/' : car);
637         }
638         buf.append(';');
639         return;
640       }
641     }
642   }
643
644   // --------------------------------------------------------------------------
645
// Corresponding size and opcodes
646
// --------------------------------------------------------------------------
647

648   /**
649    * Returns the size of values of this type.
650    *
651    * @return the size of values of this type, i.e., 2 for <tt>long</tt> and
652    * <tt>double</tt>, and 1 otherwise.
653    */

654
655   public int getSize () {
656     return (sort == LONG || sort == DOUBLE ? 2 : 1);
657   }
658
659   /**
660    * Returns a JVM instruction opcode adapted to this Java type.
661    *
662    * @param opcode a JVM instruction opcode. This opcode must be one of ILOAD,
663    * ISTORE, IALOAD, IASTORE, IADD, ISUB, IMUL, IDIV, IREM, INEG, ISHL,
664    * ISHR, IUSHR, IAND, IOR, IXOR and IRETURN.
665    * @return an opcode that is similar to the given opcode, but adapted to this
666    * Java type. For example, if this type is <tt>float</tt> and
667    * <tt>opcode</tt> is IRETURN, this method returns FRETURN.
668    */

669
670   public int getOpcode (final int opcode) {
671     if (opcode == Constants.IALOAD || opcode == Constants.IASTORE) {
672       switch (sort) {
673         case BOOLEAN:
674         case BYTE:
675           return opcode + 5;
676         case CHAR:
677           return opcode + 6;
678         case SHORT:
679           return opcode + 7;
680         case INT:
681           return opcode;
682         case FLOAT:
683           return opcode + 2;
684         case LONG:
685           return opcode + 1;
686         case DOUBLE:
687           return opcode + 3;
688         //case ARRAY:
689
//case OBJECT:
690
default:
691           return opcode + 4;
692       }
693     } else {
694       switch (sort) {
695         case VOID:
696           return opcode + 5;
697         case BOOLEAN:
698         case CHAR:
699         case BYTE:
700         case SHORT:
701         case INT:
702           return opcode;
703         case FLOAT:
704           return opcode + 2;
705         case LONG:
706           return opcode + 1;
707         case DOUBLE:
708           return opcode + 3;
709         //case ARRAY:
710
//case OBJECT:
711
default:
712           return opcode + 4;
713       }
714     }
715   }
716
717   // --------------------------------------------------------------------------
718
// Equals, hashCode and toString
719
// --------------------------------------------------------------------------
720

721   /**
722    * Tests if the given object is equal to this type.
723    *
724    * @param o the object to be compared to this type.
725    * @return <tt>true</tt> if the given object is equal to this type.
726    */

727
728   public boolean equals (final Object JavaDoc o) {
729     if (this == o) {
730       return true;
731     }
732     if (o == null || !(o instanceof Type)) {
733       return false;
734     }
735     Type t = (Type)o;
736     if (sort != t.sort) {
737       return false;
738     }
739     if (sort == Type.OBJECT || sort == Type.ARRAY) {
740       if (len != t.len) {
741         return false;
742       }
743       for (int i = off, j = t.off, end = i + len; i < end; i++, j++) {
744         if (buf[i] != t.buf[j]) {
745           return false;
746         }
747       }
748     }
749     return true;
750   }
751
752   /**
753    * Returns a hash code value for this type.
754    *
755    * @return a hash code value for this type.
756    */

757
758   public int hashCode () {
759     int hc = 13 * sort;
760     if (sort == Type.OBJECT || sort == Type.ARRAY) {
761       for (int i = off, end = i + len; i < end; i++) {
762         hc = 17 * (hc + buf[i]);
763       }
764     }
765     return hc;
766   }
767
768   /**
769    * Returns a string representation of this type.
770    *
771    * @return the descriptor of this type.
772    */

773
774   public String JavaDoc toString () {
775     return getDescriptor();
776   }
777 }
778
Popular Tags