001: /*
002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright notice. All rights reserved.
003: */
004:
005: package com.tc.aspectwerkz.definition;
006:
007: import java.util.HashMap;
008: import java.util.Map;
009: import java.util.StringTokenizer;
010:
011: /**
012: * The signature of a method that is available from the BCEL library uses descriptors as defined in Section 4.3 of the
013: * Java Virtual Machine specificaiton. Javadoc and Java do not use signatures in this same format. This class converts
014: * the Javadoc/Java signature format to that used by the JVM spec. To summarize the descriptors <code> A method
015: * descriptor represents the parameters that the method takes and the value that it returns:
016: * <p/>
017: * MethodDescriptor: ( ParameterDescriptor* ) ReturnDescriptor
018: * <p/>
019: * A parameter descriptor represents a parameter passed to a method:
020: * <p/>
021: * ParameterDescriptor: FieldType
022: * <p/>
023: * A return descriptor represents the type of the value returned from a method. It is a series of characters generated
024: * by the grammar:
025: * <p/>
026: * ReturnDescriptor: FieldType V
027: * <p/>
028: * The character V indicates that the method returns no value (its return type is void). </code>
029: * <p/>
030: * <code> A field descriptor represents the type of a class, instance, or local variable. It is a series of characters
031: * generated by the grammar:
032: * <p/>
033: * FieldDescriptor: FieldType
034: * <p/>
035: * ComponentType: FieldType
036: * <p/>
037: * FieldType: BaseType ObjectType ArrayType
038: * <p/>
039: * BaseType: B C D F I J S Z
040: * <p/>
041: * ObjectType: L <classname> ;
042: * <p/>
043: * ArrayType: [ ComponentType
044: * <p/>
045: * The characters of BaseType, the L and ; of ObjectType, and the [ of ArrayType are all ASCII characters. The
046: * <classname> represents a fully qualified class or interface name. For historical reasons it is encoded in internal
047: * form (4.2). The interpretation of the field types is as shown in Table 4.2.
048: * <p/>
049: * BaseType Character Type Interpretation ---------------------------------------------- B byte
050: * signed byte C char Unicode character D double double-precision
051: * floating-point value F float single-precision floating-point value I int
052: * integer J long long integer L<classname>; reference an instance of class <classname> S
053: * short signed short Z boolean true or false [ reference one array dimension
054: *
055: * @author <a href="mailto:mpollack@speakeasy.org">Mark Pollack</a>
056: */
057: public class DescriptorUtil {
058: private static Map _paramTypeMap = new HashMap();
059:
060: private static Map _returnTypeMap = new HashMap();
061:
062: static {
063: _paramTypeMap.put("byte", "B");
064: _paramTypeMap.put("char", "C");
065: _paramTypeMap.put("double", "D");
066: _paramTypeMap.put("float", "F");
067: _paramTypeMap.put("int", "I");
068: _paramTypeMap.put("long", "J");
069:
070: //todo: make generic...look for 'dots' of package. that algorithm doesn't handle
071: // packageless (default package)
072: // classes though..
073: _paramTypeMap.put("java.lang.Object", "Ljava/lang/Object;");
074: _paramTypeMap.put("short", "S");
075: _paramTypeMap.put("boolean", "Z");
076:
077: //todo
078: _paramTypeMap.put("array reference", "[");
079: _returnTypeMap.put("void", "V");
080: }
081:
082: /**
083: * Converts from the Java/Javadoc method signature the JVM spec format.
084: *
085: * @param javadocSig method signature as returned via Javadoc API.
086: * @param javadocReturnType return type as returned via Javadoc API.
087: * @return mtehod signature as defined in the JVM spec.
088: */
089: public static String convert(String javadocSig,
090: String javadocReturnType) {
091: //remove the leading and trailing parens
092: String javadocSigTrim = javadocSig.substring(1, javadocSig
093: .length() - 1);
094: StringTokenizer st = new StringTokenizer(javadocSigTrim, ",");
095: StringBuffer jvmBuff = new StringBuffer("(");
096: while (st.hasMoreTokens()) {
097: //remove the leading space character.
098: String sigElement = st.nextToken().trim();
099: if (_paramTypeMap.containsKey(sigElement)) {
100: jvmBuff.append(_paramTypeMap.get(sigElement));
101: }
102: }
103: jvmBuff.append(")");
104: if (_returnTypeMap.containsKey(javadocReturnType)) {
105: jvmBuff.append(_returnTypeMap.get(javadocReturnType));
106: }
107: return jvmBuff.toString();
108: }
109:
110: /**
111: * Convert a JVM signature as defined in the JVM spec to that used in the Java.
112: *
113: * @param jvmSignature The JVM format signature.
114: * @return a <code>String[]</code> containing the method parameter as elements of the array.
115: */
116: public static String[] getParameters(final String jvmSignature) {
117: int i = 0;
118: if (jvmSignature.charAt(i) != '(') {
119: return null;
120: }
121: int j = 0;
122: StringBuffer stringbuffer = new StringBuffer();
123: for (i++; i < jvmSignature.length();) {
124: if (jvmSignature.charAt(i) == ')') {
125: i++;
126: break; //we are at the end of the signature.
127: }
128: if (i > 1) {
129: //put in spaces to later tokenize on.
130: stringbuffer.append(" ");
131: }
132: i = jvmFormatToJavaFormat(jvmSignature, i, stringbuffer);
133:
134: //count number of elements parsed.
135: j++;
136: }
137:
138: //convert to string array.
139: String convertedString = stringbuffer.toString();
140: String[] as = new String[j];
141: int k = 0;
142: StringTokenizer st = new StringTokenizer(convertedString);
143: while (st.hasMoreTokens()) {
144: as[k++] = st.nextToken();
145: }
146: return as;
147: }
148:
149: /**
150: * The utility method that does the real work of parsing through the JVM formatted string and adding an converted
151: * method parameter description to the StringBuffer.
152: *
153: * @param jvmFormat The JVM formatted string that is being parsed.
154: * @param i The offset into the string being parsed.
155: * @param stringbuffer The storage for building the converted method signature.
156: * @return new offset location for parsing.
157: * @TODO this an extremely ugly method (the int an stringbuffer params must be removed)
158: */
159: private static int jvmFormatToJavaFormat(final String jvmFormat,
160: int i, StringBuffer stringbuffer) {
161: String s1 = "";
162:
163: //arrays.
164: for (; jvmFormat.charAt(i) == '['; i++) {
165: s1 = s1 + "[]";
166: }
167: startover: switch (jvmFormat.charAt(i)) {
168: case 66: // 'B'
169: stringbuffer.append("byte");
170: break;
171: case 67: // 'C'
172: stringbuffer.append("char");
173: break;
174: case 68: // 'D'
175: stringbuffer.append("double");
176: break;
177: case 70: // 'F'
178: stringbuffer.append("float");
179: break;
180: case 73: // 'I'
181: stringbuffer.append("int");
182: break;
183: case 74: // 'J'
184: stringbuffer.append("long");
185: break;
186: case 83: // 'S'
187: stringbuffer.append("short");
188: break;
189: case 90: // 'Z'
190: stringbuffer.append("boolean");
191: break;
192: case 86: // 'V'
193: stringbuffer.append("void");
194: break;
195: case 76: // 'L'
196:
197: //special case for objects.
198: for (i++; i < jvmFormat.length(); i++) {
199: if (jvmFormat.charAt(i) == '/') {
200: //convert to period
201: stringbuffer.append('.');
202: } else {
203: if (jvmFormat.charAt(i) == ';') {
204: //we reached the end
205: break startover;
206: }
207:
208: //copy contents.
209: stringbuffer.append(jvmFormat.charAt(i));
210: }
211: }
212: break;
213: default:
214: return jvmFormat.length();
215: }
216: stringbuffer = stringbuffer.append(s1);
217: return ++i;
218: }
219: }
|