Home | History | Annotate | Download | only in bytecode
      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 
     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;
     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 toJvmName(String 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      * This method does not deal with an array type name such as
     45      * "[Ljava/lang/Object;" and "[I;".  For such names, use
     46      * <code>toClassName()</code>.
     47      *
     48      * @see #toClassName(String)
     49      */
     50     public static String toJavaName(String classname) {
     51         return classname.replace('/', '.');
     52     }
     53 
     54     /**
     55      * Returns the internal representation of the class name in the
     56      * JVM.
     57      */
     58     public static String toJvmName(CtClass clazz) {
     59         if (clazz.isArray())
     60             return of(clazz);
     61         else
     62             return toJvmName(clazz.getName());
     63     }
     64 
     65     /**
     66      * Converts to a Java class name from a descriptor.
     67      *
     68      * @param descriptor        type descriptor.
     69      */
     70     public static String toClassName(String descriptor) {
     71         int arrayDim = 0;
     72         int i = 0;
     73         char c = descriptor.charAt(0);
     74         while (c == '[') {
     75             ++arrayDim;
     76             c = descriptor.charAt(++i);
     77         }
     78 
     79         String name;
     80         if (c == 'L') {
     81             int i2 = descriptor.indexOf(';', i++);
     82             name = descriptor.substring(i, i2).replace('/', '.');
     83             i = i2;
     84         }
     85         else if (c == 'V')
     86             name =  "void";
     87         else if (c == 'I')
     88             name = "int";
     89         else if (c == 'B')
     90             name = "byte";
     91         else if (c == 'J')
     92             name = "long";
     93         else if (c == 'D')
     94             name = "double";
     95         else if (c == 'F')
     96             name = "float";
     97         else if (c == 'C')
     98             name = "char";
     99         else if (c == 'S')
    100             name = "short";
    101         else if (c == 'Z')
    102             name = "boolean";
    103         else
    104             throw new RuntimeException("bad descriptor: " + descriptor);
    105 
    106         if (i + 1 != descriptor.length())
    107             throw new RuntimeException("multiple descriptors?: " + descriptor);
    108 
    109         if (arrayDim == 0)
    110             return name;
    111         else {
    112             StringBuffer sbuf = new StringBuffer(name);
    113             do {
    114                 sbuf.append("[]");
    115             } while (--arrayDim > 0);
    116 
    117             return sbuf.toString();
    118         }
    119     }
    120 
    121     /**
    122      * Converts to a descriptor from a Java class name
    123      */
    124     public static String of(String classname) {
    125         if (classname.equals("void"))
    126             return "V";
    127         else if (classname.equals("int"))
    128             return "I";
    129         else if (classname.equals("byte"))
    130             return "B";
    131         else if (classname.equals("long"))
    132             return "J";
    133         else if (classname.equals("double"))
    134             return "D";
    135         else if (classname.equals("float"))
    136             return "F";
    137         else if (classname.equals("char"))
    138             return "C";
    139         else if (classname.equals("short"))
    140             return "S";
    141         else if (classname.equals("boolean"))
    142             return "Z";
    143         else
    144             return "L" + toJvmName(classname) + ";";
    145     }
    146 
    147     /**
    148      * Substitutes a class name
    149      * in the given descriptor string.
    150      *
    151      * @param desc    descriptor string
    152      * @param oldname replaced JVM class name
    153      * @param newname substituted JVM class name
    154      *
    155      * @see Descriptor#toJvmName(String)
    156      */
    157     public static String rename(String desc, String oldname, String newname) {
    158         if (desc.indexOf(oldname) < 0)
    159             return desc;
    160 
    161         StringBuffer newdesc = new StringBuffer();
    162         int head = 0;
    163         int i = 0;
    164         for (;;) {
    165             int j = desc.indexOf('L', i);
    166             if (j < 0)
    167                 break;
    168             else if (desc.startsWith(oldname, j + 1)
    169                      && desc.charAt(j + oldname.length() + 1) == ';') {
    170                 newdesc.append(desc.substring(head, j));
    171                 newdesc.append('L');
    172                 newdesc.append(newname);
    173                 newdesc.append(';');
    174                 head = i = j + oldname.length() + 2;
    175             }
    176             else {
    177                 i = desc.indexOf(';', j) + 1;
    178                 if (i < 1)
    179                     break; // ';' was not found.
    180             }
    181         }
    182 
    183         if (head == 0)
    184             return desc;
    185         else {
    186             int len = desc.length();
    187             if (head < len)
    188                 newdesc.append(desc.substring(head, len));
    189 
    190             return newdesc.toString();
    191         }
    192     }
    193 
    194     /**
    195      * Substitutes class names in the given descriptor string
    196      * according to the given <code>map</code>.
    197      *
    198      * @param map a map between replaced and substituted
    199      *            JVM class names.
    200      * @see Descriptor#toJvmName(String)
    201      */
    202     public static String rename(String desc, Map map) {
    203         if (map == null)
    204             return desc;
    205 
    206         StringBuffer newdesc = new StringBuffer();
    207         int head = 0;
    208         int i = 0;
    209         for (;;) {
    210             int j = desc.indexOf('L', i);
    211             if (j < 0)
    212                 break;
    213 
    214             int k = desc.indexOf(';', j);
    215             if (k < 0)
    216                 break;
    217 
    218             i = k + 1;
    219             String name = desc.substring(j + 1, k);
    220             String name2 = (String)map.get(name);
    221             if (name2 != null) {
    222                 newdesc.append(desc.substring(head, j));
    223                 newdesc.append('L');
    224                 newdesc.append(name2);
    225                 newdesc.append(';');
    226                 head = i;
    227             }
    228         }
    229 
    230         if (head == 0)
    231             return desc;
    232         else {
    233             int len = desc.length();
    234             if (head < len)
    235                 newdesc.append(desc.substring(head, len));
    236 
    237             return newdesc.toString();
    238         }
    239     }
    240 
    241     /**
    242      * Returns the descriptor representing the given type.
    243      */
    244     public static String of(CtClass type) {
    245         StringBuffer sbuf = new StringBuffer();
    246         toDescriptor(sbuf, type);
    247         return sbuf.toString();
    248     }
    249 
    250     private static void toDescriptor(StringBuffer desc, CtClass type) {
    251         if (type.isArray()) {
    252             desc.append('[');
    253             try {
    254                 toDescriptor(desc, type.getComponentType());
    255             }
    256             catch (NotFoundException e) {
    257                 desc.append('L');
    258                 String name = type.getName();
    259                 desc.append(toJvmName(name.substring(0, name.length() - 2)));
    260                 desc.append(';');
    261             }
    262         }
    263         else if (type.isPrimitive()) {
    264             CtPrimitiveType pt = (CtPrimitiveType)type;
    265             desc.append(pt.getDescriptor());
    266         }
    267         else { // class type
    268             desc.append('L');
    269             desc.append(type.getName().replace('.', '/'));
    270             desc.append(';');
    271         }
    272     }
    273 
    274     /**
    275      * Returns the descriptor representing a constructor receiving
    276      * the given parameter types.
    277      *
    278      * @param paramTypes parameter types
    279      */
    280     public static String ofConstructor(CtClass[] paramTypes) {
    281         return ofMethod(CtClass.voidType, paramTypes);
    282     }
    283 
    284     /**
    285      * Returns the descriptor representing a method that receives
    286      * the given parameter types and returns the given type.
    287      *
    288      * @param returnType return type
    289      * @param paramTypes parameter types
    290      */
    291     public static String ofMethod(CtClass returnType, CtClass[] paramTypes) {
    292         StringBuffer desc = new StringBuffer();
    293         desc.append('(');
    294         if (paramTypes != null) {
    295             int n = paramTypes.length;
    296             for (int i = 0; i < n; ++i)
    297                 toDescriptor(desc, paramTypes[i]);
    298         }
    299 
    300         desc.append(')');
    301         if (returnType != null)
    302             toDescriptor(desc, returnType);
    303 
    304         return desc.toString();
    305     }
    306 
    307     /**
    308      * Returns the descriptor representing a list of parameter types.
    309      * For example, if the given parameter types are two <code>int</code>,
    310      * then this method returns <code>"(II)"</code>.
    311      *
    312      * @param paramTypes parameter types
    313      */
    314     public static String ofParameters(CtClass[] paramTypes) {
    315         return ofMethod(null, paramTypes);
    316     }
    317 
    318     /**
    319      * Appends a parameter type to the parameter list represented
    320      * by the given descriptor.
    321      *
    322      * <p><code>classname</code> must not be an array type.
    323      *
    324      * @param classname parameter type (not primitive type)
    325      * @param desc      descriptor
    326      */
    327     public static String appendParameter(String classname, String desc) {
    328         int i = desc.indexOf(')');
    329         if (i < 0)
    330             return desc;
    331         else {
    332             StringBuffer newdesc = new StringBuffer();
    333             newdesc.append(desc.substring(0, i));
    334             newdesc.append('L');
    335             newdesc.append(classname.replace('.', '/'));
    336             newdesc.append(';');
    337             newdesc.append(desc.substring(i));
    338             return newdesc.toString();
    339         }
    340     }
    341 
    342     /**
    343      * Inserts a parameter type at the beginning of the parameter
    344      * list represented
    345      * by the given descriptor.
    346      *
    347      * <p><code>classname</code> must not be an array type.
    348      *
    349      * @param classname parameter type (not primitive type)
    350      * @param desc      descriptor
    351      */
    352     public static String insertParameter(String classname, String desc) {
    353         if (desc.charAt(0) != '(')
    354             return desc;
    355         else
    356             return "(L" + classname.replace('.', '/') + ';'
    357                    + desc.substring(1);
    358     }
    359 
    360     /**
    361      * Appends a parameter type to the parameter list represented
    362      * by the given descriptor.  The appended parameter becomes
    363      * the last parameter.
    364      *
    365      * @param type      the type of the appended parameter.
    366      * @param descriptor      the original descriptor.
    367      */
    368     public static String appendParameter(CtClass type, String descriptor) {
    369         int i = descriptor.indexOf(')');
    370         if (i < 0)
    371             return descriptor;
    372         else {
    373             StringBuffer newdesc = new StringBuffer();
    374             newdesc.append(descriptor.substring(0, i));
    375             toDescriptor(newdesc, type);
    376             newdesc.append(descriptor.substring(i));
    377             return newdesc.toString();
    378         }
    379     }
    380 
    381     /**
    382      * Inserts a parameter type at the beginning of the parameter
    383      * list represented
    384      * by the given descriptor.
    385      *
    386      * @param type              the type of the inserted parameter.
    387      * @param descriptor        the descriptor of the method.
    388      */
    389     public static String insertParameter(CtClass type,
    390                                          String descriptor) {
    391         if (descriptor.charAt(0) != '(')
    392             return descriptor;
    393         else
    394             return "(" + of(type) + descriptor.substring(1);
    395     }
    396 
    397     /**
    398      * Changes the return type included in the given descriptor.
    399      *
    400      * <p><code>classname</code> must not be an array type.
    401      *
    402      * @param classname return type
    403      * @param desc      descriptor
    404      */
    405     public static String changeReturnType(String classname, String desc) {
    406         int i = desc.indexOf(')');
    407         if (i < 0)
    408             return desc;
    409         else {
    410             StringBuffer newdesc = new StringBuffer();
    411             newdesc.append(desc.substring(0, i + 1));
    412             newdesc.append('L');
    413             newdesc.append(classname.replace('.', '/'));
    414             newdesc.append(';');
    415             return newdesc.toString();
    416         }
    417     }
    418 
    419     /**
    420      * Returns the <code>CtClass</code> objects representing the parameter
    421      * types specified by the given descriptor.
    422      *
    423      * @param desc descriptor
    424      * @param cp   the class pool used for obtaining
    425      *             a <code>CtClass</code> object.
    426      */
    427     public static CtClass[] getParameterTypes(String desc, ClassPool cp)
    428         throws NotFoundException
    429     {
    430         if (desc.charAt(0) != '(')
    431             return null;
    432         else {
    433             int num = numOfParameters(desc);
    434             CtClass[] args = new CtClass[num];
    435             int n = 0;
    436             int i = 1;
    437             do {
    438                 i = toCtClass(cp, desc, i, args, n++);
    439             } while (i > 0);
    440             return args;
    441         }
    442     }
    443 
    444     /**
    445      * Returns true if the list of the parameter types of desc1 is equal to
    446      * that of desc2.
    447      * For example, "(II)V" and "(II)I" are equal.
    448      */
    449     public static boolean eqParamTypes(String desc1, String desc2) {
    450         if (desc1.charAt(0) != '(')
    451             return false;
    452 
    453         for (int i = 0; true; ++i) {
    454             char c = desc1.charAt(i);
    455             if (c != desc2.charAt(i))
    456                 return false;
    457 
    458             if (c == ')')
    459                 return true;
    460         }
    461     }
    462 
    463     /**
    464      * Returns the signature of the given descriptor.  The signature does
    465      * not include the return type.  For example, the signature of "(I)V"
    466      * is "(I)".
    467      */
    468     public static String getParamDescriptor(String decl) {
    469         return decl.substring(0, decl.indexOf(')') + 1);
    470     }
    471 
    472     /**
    473      * Returns the <code>CtClass</code> object representing the return
    474      * type specified by the given descriptor.
    475      *
    476      * @param desc descriptor
    477      * @param cp   the class pool used for obtaining
    478      *             a <code>CtClass</code> object.
    479      */
    480     public static CtClass getReturnType(String desc, ClassPool cp)
    481         throws NotFoundException
    482     {
    483         int i = desc.indexOf(')');
    484         if (i < 0)
    485             return null;
    486         else {
    487             CtClass[] type = new CtClass[1];
    488             toCtClass(cp, desc, i + 1, type, 0);
    489             return type[0];
    490         }
    491     }
    492 
    493     /**
    494      * Returns the number of the prameters included in the given
    495      * descriptor.
    496      *
    497      * @param desc descriptor
    498      */
    499     public static int numOfParameters(String desc) {
    500         int n = 0;
    501         int i = 1;
    502         for (;;) {
    503             char c = desc.charAt(i);
    504             if (c == ')')
    505                 break;
    506 
    507             while (c == '[')
    508                 c = desc.charAt(++i);
    509 
    510             if (c == 'L') {
    511                 i = desc.indexOf(';', i) + 1;
    512                 if (i <= 0)
    513                     throw new IndexOutOfBoundsException("bad descriptor");
    514             }
    515             else
    516                 ++i;
    517 
    518             ++n;
    519         }
    520 
    521         return n;
    522     }
    523 
    524     /**
    525      * Returns a <code>CtClass</code> object representing the type
    526      * specified by the given descriptor.
    527      *
    528      * <p>This method works even if the package-class separator is
    529      * not <code>/</code> but <code>.</code> (period).  For example,
    530      * it accepts <code>Ljava.lang.Object;</code>
    531      * as well as <code>Ljava/lang/Object;</code>.
    532      *
    533      * @param desc descriptor.
    534      * @param cp   the class pool used for obtaining
    535      *             a <code>CtClass</code> object.
    536      */
    537     public static CtClass toCtClass(String desc, ClassPool cp)
    538         throws NotFoundException
    539     {
    540         CtClass[] clazz = new CtClass[1];
    541         int res = toCtClass(cp, desc, 0, clazz, 0);
    542         if (res >= 0)
    543             return clazz[0];
    544         else {
    545             // maybe, you forgot to surround the class name with
    546             // L and ;.  It violates the protocol, but I'm tolerant...
    547             return cp.get(desc.replace('/', '.'));
    548         }
    549     }
    550 
    551     private static int toCtClass(ClassPool cp, String desc, int i,
    552                                  CtClass[] args, int n)
    553         throws NotFoundException
    554     {
    555         int i2;
    556         String name;
    557 
    558         int arrayDim = 0;
    559         char c = desc.charAt(i);
    560         while (c == '[') {
    561             ++arrayDim;
    562             c = desc.charAt(++i);
    563         }
    564 
    565         if (c == 'L') {
    566             i2 = desc.indexOf(';', ++i);
    567             name = desc.substring(i, i2++).replace('/', '.');
    568         }
    569         else {
    570             CtClass type = toPrimitiveClass(c);
    571             if (type == null)
    572                 return -1; // error
    573 
    574             i2 = i + 1;
    575             if (arrayDim == 0) {
    576                 args[n] = type;
    577                 return i2; // neither an array type or a class type
    578             }
    579             else
    580                 name = type.getName();
    581         }
    582 
    583         if (arrayDim > 0) {
    584             StringBuffer sbuf = new StringBuffer(name);
    585             while (arrayDim-- > 0)
    586                 sbuf.append("[]");
    587 
    588             name = sbuf.toString();
    589         }
    590 
    591         args[n] = cp.get(name);
    592         return i2;
    593     }
    594 
    595     static CtClass toPrimitiveClass(char c) {
    596         CtClass type = null;
    597         switch (c) {
    598         case 'Z' :
    599             type = CtClass.booleanType;
    600             break;
    601         case 'C' :
    602             type = CtClass.charType;
    603             break;
    604         case 'B' :
    605             type = CtClass.byteType;
    606             break;
    607         case 'S' :
    608             type = CtClass.shortType;
    609             break;
    610         case 'I' :
    611             type = CtClass.intType;
    612             break;
    613         case 'J' :
    614             type = CtClass.longType;
    615             break;
    616         case 'F' :
    617             type = CtClass.floatType;
    618             break;
    619         case 'D' :
    620             type = CtClass.doubleType;
    621             break;
    622         case 'V' :
    623             type = CtClass.voidType;
    624             break;
    625         }
    626 
    627         return type;
    628     }
    629 
    630     /**
    631      * Computes the dimension of the array represented by the given
    632      * descriptor.  For example, if the descriptor is <code>"[[I"</code>,
    633      * then this method returns 2.
    634      *
    635      * @param desc the descriptor.
    636      * @return 0        if the descriptor does not represent an array type.
    637      */
    638     public static int arrayDimension(String desc) {
    639         int dim = 0;
    640         while (desc.charAt(dim) == '[')
    641             ++dim;
    642 
    643         return dim;
    644     }
    645 
    646     /**
    647      * Returns the descriptor of the type of the array component.
    648      * For example, if the given descriptor is
    649      * <code>"[[Ljava/lang/String;"</code> and the given dimension is 2,
    650      * then this method returns <code>"Ljava/lang/String;"</code>.
    651      *
    652      * @param desc the descriptor.
    653      * @param dim  the array dimension.
    654      */
    655     public static String toArrayComponent(String desc, int dim) {
    656         return desc.substring(dim);
    657     }
    658 
    659     /**
    660      * Computes the data size specified by the given descriptor.
    661      * For example, if the descriptor is "D", this method returns 2.
    662      *
    663      * <p>If the descriptor represents a method type, this method returns
    664      * (the size of the returned value) - (the sum of the data sizes
    665      * of all the parameters).  For example, if the descriptor is
    666      * <code>"(I)D"</code>, then this method returns 1 (= 2 - 1).
    667      *
    668      * @param desc descriptor
    669      */
    670     public static int dataSize(String desc) {
    671         return dataSize(desc, true);
    672     }
    673 
    674     /**
    675      * Computes the data size of parameters.
    676      * If one of the parameters is double type, the size of that parameter
    677      * is 2 words.  For example, if the given descriptor is
    678      *  <code>"(IJ)D"</code>, then this method returns 3.  The size of the
    679      * return type is not computed.
    680      *
    681      * @param desc      a method descriptor.
    682      */
    683     public static int paramSize(String desc) {
    684         return -dataSize(desc, false);
    685     }
    686 
    687     private static int dataSize(String desc, boolean withRet) {
    688         int n = 0;
    689         char c = desc.charAt(0);
    690         if (c == '(') {
    691             int i = 1;
    692             for (;;) {
    693                 c = desc.charAt(i);
    694                 if (c == ')') {
    695                     c = desc.charAt(i + 1);
    696                     break;
    697                 }
    698 
    699                 boolean array = false;
    700                 while (c == '[') {
    701                     array = true;
    702                     c = desc.charAt(++i);
    703                 }
    704 
    705                 if (c == 'L') {
    706                     i = desc.indexOf(';', i) + 1;
    707                     if (i <= 0)
    708                         throw new IndexOutOfBoundsException("bad descriptor");
    709                 }
    710                 else
    711                     ++i;
    712 
    713                 if (!array && (c == 'J' || c == 'D'))
    714                     n -= 2;
    715                 else
    716                     --n;
    717             }
    718         }
    719 
    720         if (withRet)
    721             if (c == 'J' || c == 'D')
    722                 n += 2;
    723             else if (c != 'V')
    724                 ++n;
    725 
    726         return n;
    727     }
    728 
    729     /**
    730      * Returns a human-readable representation of the
    731      * given descriptor.  For example, <code>Ljava/lang/Object;</code>
    732      * is converted into <code>java.lang.Object</code>.
    733      * <code>(I[I)V</code> is converted into <code>(int, int[])</code>
    734      * (the return type is ignored).
    735      */
    736     public static String toString(String desc) {
    737         return PrettyPrinter.toString(desc);
    738     }
    739 
    740     static class PrettyPrinter {
    741         static String toString(String desc) {
    742             StringBuffer sbuf = new StringBuffer();
    743             if (desc.charAt(0) == '(') {
    744                 int pos = 1;
    745                 sbuf.append('(');
    746                 while (desc.charAt(pos) != ')') {
    747                     if (pos > 1)
    748                         sbuf.append(',');
    749 
    750                     pos = readType(sbuf, pos, desc);
    751                 }
    752 
    753                 sbuf.append(')');
    754             }
    755             else
    756                 readType(sbuf, 0, desc);
    757 
    758             return sbuf.toString();
    759         }
    760 
    761         static int readType(StringBuffer sbuf, int pos, String desc) {
    762             char c = desc.charAt(pos);
    763             int arrayDim = 0;
    764             while (c == '[') {
    765                 arrayDim++;
    766                 c = desc.charAt(++pos);
    767             }
    768 
    769             if (c == 'L')
    770                 while (true) {
    771                     c = desc.charAt(++pos);
    772                     if (c == ';')
    773                         break;
    774 
    775                     if (c == '/')
    776                         c = '.';
    777 
    778                     sbuf.append(c);
    779                 }
    780             else {
    781                 CtClass t = toPrimitiveClass(c);
    782                 sbuf.append(t.getName());
    783             }
    784 
    785             while (arrayDim-- > 0)
    786                 sbuf.append("[]");
    787 
    788             return pos + 1;
    789         }
    790     }
    791 
    792     /**
    793      * An Iterator over a descriptor.
    794      */
    795     public static class Iterator {
    796         private String desc;
    797         private int index, curPos;
    798         private boolean param;
    799 
    800         /**
    801          * Constructs an iterator.
    802          *
    803          * @param s         descriptor.
    804          */
    805         public Iterator(String s) {
    806             desc = s;
    807             index = curPos = 0;
    808             param = false;
    809         }
    810 
    811         /**
    812          * Returns true if the iteration has more elements.
    813          */
    814         public boolean hasNext() {
    815             return index < desc.length();
    816         }
    817 
    818         /**
    819          * Returns true if the current element is a parameter type.
    820          */
    821         public boolean isParameter() { return param; }
    822 
    823         /**
    824          * Returns the first character of the current element.
    825          */
    826         public char currentChar() { return desc.charAt(curPos); }
    827 
    828         /**
    829          * Returns true if the current element is double or long type.
    830          */
    831         public boolean is2byte() {
    832             char c = currentChar();
    833             return c == 'D' || c == 'J';
    834         }
    835 
    836         /**
    837          * Returns the position of the next type character.
    838          * That type character becomes a new current element.
    839          */
    840         public int next() {
    841             int nextPos = index;
    842             char c = desc.charAt(nextPos);
    843             if (c == '(') {
    844                 ++index;
    845                 c = desc.charAt(++nextPos);
    846                 param = true;
    847             }
    848 
    849             if (c == ')') {
    850                 ++index;
    851                 c = desc.charAt(++nextPos);
    852                 param = false;
    853             }
    854 
    855             while (c == '[')
    856                 c = desc.charAt(++nextPos);
    857 
    858             if (c == 'L') {
    859                 nextPos = desc.indexOf(';', nextPos) + 1;
    860                 if (nextPos <= 0)
    861                     throw new IndexOutOfBoundsException("bad descriptor");
    862             }
    863             else
    864                 ++nextPos;
    865 
    866             curPos = index;
    867             index = nextPos;
    868             return curPos;
    869         }
    870     }
    871 }
    872