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
67
68
69 _paramTypeMap.put("java.lang.Object", "Ljava/lang/Object;");
70 _paramTypeMap.put("short", "S");
71 _paramTypeMap.put("boolean", "Z");
72
73
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
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
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;
121 }
122 if (i > 1) {
123
124 stringbuffer.append(" ");
125 }
126 i = jvmFormatToJavaFormat(jvmSignature, i, stringbuffer);
127
128
129 j++;
130 }
131
132
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 * @TODO this an extremely ugly method (the int an stringbuffer params must be removed)
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 */
154 private static int jvmFormatToJavaFormat(final String jvmFormat, int i, StringBuffer stringbuffer) {
155 String s1 = "";
156
157
158 for (; jvmFormat.charAt(i) == '['; i++) {
159 s1 = s1 + "[]";
160 }
161 startover: switch (jvmFormat.charAt(i)) {
162 case 66:
163 stringbuffer.append("byte");
164 break;
165 case 67:
166 stringbuffer.append("char");
167 break;
168 case 68:
169 stringbuffer.append("double");
170 break;
171 case 70:
172 stringbuffer.append("float");
173 break;
174 case 73:
175 stringbuffer.append("int");
176 break;
177 case 74:
178 stringbuffer.append("long");
179 break;
180 case 83:
181 stringbuffer.append("short");
182 break;
183 case 90:
184 stringbuffer.append("boolean");
185 break;
186 case 86:
187 stringbuffer.append("void");
188 break;
189 case 76:
190
191
192 for (i++; i < jvmFormat.length(); i++) {
193 if (jvmFormat.charAt(i) == '/') {
194
195 stringbuffer.append('.');
196 } else {
197 if (jvmFormat.charAt(i) == ';') {
198
199 break startover;
200 }
201
202
203 stringbuffer.append(jvmFormat.charAt(i));
204 }
205 }
206 break;
207 default:
208 return jvmFormat.length();
209 }
210 stringbuffer = stringbuffer.append(s1);
211 return ++i;
212 }
213 }