View Javadoc

    1   package org.codehaus.aspectwerkz.definition;
    2
    3   import java.util.HashMap;
    4   import java.util.Map;
    5   import java.util.StringTokenizer;
    6
    7   /***
    8    * The signature of a method that is available from the BCEL library uses descriptors as defined in Section 4.3 of the
    9    * Java Virtual Machine specificaiton. Javadoc and Java do not use signatures in this same format. This class converts
    10   * the Javadoc/Java signature format to that used by the JVM spec. To summarize the descriptors <code> A method
    11   * descriptor represents the parameters that the method takes and the value that it returns:
    12   * <p/>
    13   * MethodDescriptor: ( ParameterDescriptor* ) ReturnDescriptor
    14   * <p/>
    15   * A parameter descriptor represents a parameter passed to a method:
    16   * <p/>
    17   * ParameterDescriptor: FieldType
    18   * <p/>
    19   * A return descriptor represents the type of the value returned from a method. It is a series of characters generated
    20   * by the grammar:
    21   * <p/>
    22   * ReturnDescriptor: FieldType V
    23   * <p/>
    24   * The character V indicates that the method returns no value (its return type is void). </code>
    25   * <p/>
    26   * <code> A field descriptor represents the type of a class, instance, or local variable. It is a series of characters
    27   * generated by the grammar:
    28   * <p/>
    29   * FieldDescriptor: FieldType
    30   * <p/>
    31   * ComponentType: FieldType
    32   * <p/>
    33   * FieldType: BaseType ObjectType ArrayType
    34   * <p/>
    35   * BaseType: B C D F I J S Z
    36   * <p/>
    37   * ObjectType: L <classname> ;
    38   * <p/>
    39   * ArrayType: [ ComponentType
    40   * <p/>
    41   * The characters of BaseType, the L and ; of ObjectType, and the [ of ArrayType are all ASCII characters. The
    42   * <classname> represents a fully qualified class or interface name. For historical reasons it is encoded in internal
    43   * form (4.2).  The interpretation of the field types is as shown in Table 4.2.
    44   * <p/>
    45   * BaseType Character  Type       Interpretation ---------------------------------------------- B                   byte
    46   * signed byte C                   char       Unicode character D                   double     double-precision
    47   * floating-point value F                   float      single-precision floating-point value I                   int
    48   * integer J                   long       long integer L<classname>;       reference  an instance of class <classname> S
    49   * short      signed short Z                   boolean    true or false [ reference  one array dimension
    50   *
    51   * @author <a href="mailto:mpollack@speakeasy.org">Mark Pollack</a>
    52   */
    53  public class DescriptorUtil {
    54      private static Map _paramTypeMap = new HashMap();
    55
    56      private static Map _returnTypeMap = new HashMap();
    57
    58      static {
    59          _paramTypeMap.put("byte", "B");
    60          _paramTypeMap.put("char", "C");
    61          _paramTypeMap.put("double", "D");
    62          _paramTypeMap.put("float", "F");
    63          _paramTypeMap.put("int", "I");
    64          _paramTypeMap.put("long", "J");
    65
    66          //todo: make generic...look for 'dots' of package. that algorithm doesn't handle
    67          // packageless (default package)
    68          // classes though..
    69          _paramTypeMap.put("java.lang.Object", "Ljava/lang/Object;");
    70          _paramTypeMap.put("short", "S");
    71          _paramTypeMap.put("boolean", "Z");
    72
    73          //todo
    74          _paramTypeMap.put("array reference", "[");
    75          _returnTypeMap.put("void", "V");
    76      }
    77
    78      /***
    79       * Converts from the Java/Javadoc method signature the JVM spec format.
    80       *
    81       * @param javadocSig        method signature as returned via Javadoc API.
    82       * @param javadocReturnType return type as returned via Javadoc API.
    83       * @return mtehod signature as defined in the JVM spec.
    84       */
    85      public static String convert(String javadocSig, String javadocReturnType) {
    86          //remove the leading and trailing parens
    87          String javadocSigTrim = javadocSig.substring(1, javadocSig.length() - 1);
    88          StringTokenizer st = new StringTokenizer(javadocSigTrim, ",");
    89          StringBuffer jvmBuff = new StringBuffer("(");
    90          while (st.hasMoreTokens()) {
    91              //remove the leading space character.
    92              String sigElement = st.nextToken().trim();
    93              if (_paramTypeMap.containsKey(sigElement)) {
    94                  jvmBuff.append(_paramTypeMap.get(sigElement));
    95              }
    96          }
    97          jvmBuff.append(")");
    98          if (_returnTypeMap.containsKey(javadocReturnType)) {
    99              jvmBuff.append(_returnTypeMap.get(javadocReturnType));
    100         }
    101         return jvmBuff.toString();
    102     }
    103
    104     /***
    105      * Convert a JVM signature as defined in the JVM spec to that used in the Java.
    106      *
    107      * @param jvmSignature The JVM format signature.
    108      * @return a <code>String[]</code> containing the method parameter as elements of the array.
    109      */
    110     public static String[] getParameters(final String jvmSignature) {
    111         int i = 0;
    112         if (jvmSignature.charAt(i) != '(') {
    113             return null;
    114         }
    115         int j = 0;
    116         StringBuffer stringbuffer = new StringBuffer();
    117         for (i++; i < jvmSignature.length();) {
    118             if (jvmSignature.charAt(i) == ')') {
    119                 i++;
    120                 break; //we are at the end of the signature.
    121             }
    122             if (i > 1) {
    123                 //put in spaces to later tokenize on.
    124                 stringbuffer.append(" ");
    125             }
    126             i = jvmFormatToJavaFormat(jvmSignature, i, stringbuffer);
    127
    128             //count number of elements parsed.
    129             j++;
    130         }
    131
    132         //convert to string array.
    133         String convertedString = stringbuffer.toString();
    134         String[] as = new String[j];
    135         int k = 0;
    136         StringTokenizer st = new StringTokenizer(convertedString);
    137         while (st.hasMoreTokens()) {
    138             as[k++] = st.nextToken();
    139         }
    140         return as;
    141     }
    142
    143     /***
    144      * The utility method that does the real work of parsing through the JVM formatted string and adding an converted
    145      * method parameter description to the StringBuffer.
    146      *
    147      * @param jvmFormat    The JVM formatted string that is being parsed.
    148      * @param i            The offset into the string being parsed.
    149      * @param stringbuffer The storage for building the converted method signature.
    150      * @return new offset location for parsing.
    151      * @TODO this an extremely ugly method (the int an stringbuffer params must be removed)
    152      */
    153     private static int jvmFormatToJavaFormat(final String jvmFormat, int i, StringBuffer stringbuffer) {
    154         String s1 = "";
    155
    156         //arrays.
    157         for (; jvmFormat.charAt(i) == '['; i++) {
    158             s1 = s1 + "[]";
    159         }
    160         startover: switch (jvmFormat.charAt(i)) {
    161             case 66: // 'B'
    162                 stringbuffer.append("byte");
    163                 break;
    164             case 67: // 'C'
    165                 stringbuffer.append("char");
    166                 break;
    167             case 68: // 'D'
    168                 stringbuffer.append("double");
    169                 break;
    170             case 70: // 'F'
    171                 stringbuffer.append("float");
    172                 break;
    173             case 73: // 'I'
    174                 stringbuffer.append("int");
    175                 break;
    176             case 74: // 'J'
    177                 stringbuffer.append("long");
    178                 break;
    179             case 83: // 'S'
    180                 stringbuffer.append("short");
    181                 break;
    182             case 90: // 'Z'
    183                 stringbuffer.append("boolean");
    184                 break;
    185             case 86: // 'V'
    186                 stringbuffer.append("void");
    187                 break;
    188             case 76: // 'L'
    189
    190                 //special case for objects.
    191                 for (i++; i < jvmFormat.length(); i++) {
    192                     if (jvmFormat.charAt(i) == '/') {
    193                         //convert to period
    194                         stringbuffer.append('.');
    195                     } else {
    196                         if (jvmFormat.charAt(i) == ';') {
    197                             //we reached the end
    198                             break startover;
    199                         }
    200
    201                         //copy contents.
    202                         stringbuffer.append(jvmFormat.charAt(i));
    203                     }
    204                 }
    205                 break;
    206             default:
    207                 return jvmFormat.length();
    208         }
    209         stringbuffer = stringbuffer.append(s1);
    210         return ++i;
    211     }
    212 }