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