KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > cojen > classfile > MethodDesc


1 /*
2  * Copyright 2004 Brian S O'Neill
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.cojen.classfile;
18
19 import java.io.Serializable JavaDoc;
20 import java.io.Externalizable JavaDoc;
21 import java.io.ObjectOutput JavaDoc;
22 import java.io.ObjectInput JavaDoc;
23 import java.io.IOException JavaDoc;
24 import java.io.ObjectStreamException JavaDoc;
25 import java.lang.reflect.Method JavaDoc;
26 import java.util.List JavaDoc;
27 import java.util.ArrayList JavaDoc;
28 import org.cojen.util.WeakCanonicalSet;
29
30 /**
31  * This class is used to build method descriptor strings as
32  * defined in <i>The Java Virtual Machine Specification</i>, section 4.3.3.
33  * MethodDesc instances are canonicalized and therefore "==" comparable.
34  *
35  * @author Brian S O'Neill
36  */

37 public class MethodDesc extends Descriptor implements Serializable JavaDoc {
38     private static final TypeDesc[] EMPTY_PARAMS = new TypeDesc[0];
39
40     // MethodDesc and TypeDesc can share the same instance cache.
41
private final static WeakCanonicalSet mInstances = TypeDesc.cInstances;
42
43     static MethodDesc intern(MethodDesc desc) {
44         return (MethodDesc)mInstances.put(desc);
45     }
46
47     /**
48      * Acquire a MethodDesc from a set of arguments.
49      * @param ret return type of method; null implies void
50      * @param params parameters to method; null implies none
51      */

52     public static MethodDesc forArguments(TypeDesc ret, TypeDesc[] params) {
53         if (ret == null) {
54             ret = TypeDesc.VOID;
55         }
56         if (params == null || params.length == 0) {
57             params = EMPTY_PARAMS;
58         }
59         return intern(new MethodDesc(ret, params));
60     }
61
62     /**
63      * Acquire a MethodDesc from a type descriptor. This syntax is described in
64      * section 4.3.3, Method Descriptors.
65      */

66     public static MethodDesc forDescriptor(String JavaDoc desc)
67         throws IllegalArgumentException JavaDoc
68     {
69         try {
70             int cursor = 0;
71             char c;
72
73             if ((c = desc.charAt(cursor++)) != '(') {
74                 throw invalidDescriptor(desc);
75             }
76
77             StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
78             List JavaDoc list = new ArrayList JavaDoc();
79
80             while ((c = desc.charAt(cursor++)) != ')') {
81                 switch (c) {
82                 case 'V':
83                 case 'I':
84                 case 'C':
85                 case 'Z':
86                 case 'D':
87                 case 'F':
88                 case 'J':
89                 case 'B':
90                 case 'S':
91                     buf.append(c);
92                     break;
93                 case '[':
94                     buf.append(c);
95                     continue;
96                 case 'L':
97                     while (true) {
98                         buf.append(c);
99                         if (c == ';') {
100                             break;
101                         }
102                         c = desc.charAt(cursor++);
103                     }
104                     break;
105                 default:
106                     throw invalidDescriptor(desc);
107                 }
108
109                 list.add(TypeDesc.forDescriptor(buf.toString()));
110                 buf.setLength(0);
111             }
112
113             TypeDesc ret = TypeDesc.forDescriptor(desc.substring(cursor));
114
115             TypeDesc[] tds = new TypeDesc[list.size()];
116             tds = (TypeDesc[])list.toArray(tds);
117
118             return intern(new MethodDesc(desc, ret, tds));
119         } catch (NullPointerException JavaDoc e) {
120             throw invalidDescriptor(desc);
121         } catch (IndexOutOfBoundsException JavaDoc e) {
122             throw invalidDescriptor(desc);
123         }
124     }
125
126     public static MethodDesc forMethod(Method JavaDoc method) {
127         Class JavaDoc[] paramClasses = method.getParameterTypes();
128         TypeDesc[] paramTypes;
129         if (paramClasses == null || paramClasses.length == 0) {
130             paramTypes = EMPTY_PARAMS;
131         } else {
132             paramTypes = new TypeDesc[paramClasses.length];
133             for (int i=paramClasses.length; --i>=0; ) {
134                 paramTypes[i] = TypeDesc.forClass(paramClasses[i]);
135             }
136         }
137         return forArguments(TypeDesc.forClass(method.getReturnType()), paramTypes);
138     }
139
140     private static IllegalArgumentException JavaDoc invalidDescriptor(String JavaDoc desc) {
141         return new IllegalArgumentException JavaDoc("Invalid descriptor: " + desc);
142     }
143
144     private transient final String JavaDoc mDescriptor;
145     private transient final TypeDesc mRetType;
146     private transient final TypeDesc[] mParams;
147     
148     private MethodDesc(TypeDesc ret, TypeDesc[] params) {
149         mDescriptor = generateDescriptor(ret, params);
150         mRetType = ret;
151         mParams = params;
152     }
153
154     private MethodDesc(String JavaDoc desc, TypeDesc ret, TypeDesc[] params) {
155         mDescriptor = desc;
156         mRetType = ret;
157         mParams = params;
158     }
159
160     /**
161      * Returns a method descriptor string, excluding generics.
162      */

163     public String JavaDoc getDescriptor() {
164         return mDescriptor;
165     }
166
167     /**
168      * Returns a method descriptor string, including any generics.
169      */

170     //public abstract String getGenericDescriptor();
171

172     /**
173      * Returns the described return type, which is TypeDesc.VOID if void.
174      */

175     public TypeDesc getReturnType() {
176         return mRetType;
177     }
178
179     public int getParameterCount() {
180         return mParams.length;
181     }
182
183     public TypeDesc[] getParameterTypes() {
184         TypeDesc[] params = mParams;
185         return (params != EMPTY_PARAMS) ? (TypeDesc[])params.clone() : params;
186     }
187
188     /**
189      * Returns this in Java method signature syntax.
190      *
191      * @param name method name
192      */

193     public String JavaDoc toMethodSignature(String JavaDoc name) {
194         return toMethodSignature(name, false);
195     }
196
197     /**
198      * Returns this in Java method signature syntax.
199      *
200      * @param name method name
201      * @param varargs request that the last argument, if it is an array, to
202      * be formatted in varargs syntax.
203      */

204     public String JavaDoc toMethodSignature(String JavaDoc name, boolean varargs) {
205         StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
206         buf.append(mRetType.getFullName());
207         buf.append(' ');
208         buf.append(name);
209         buf.append('(');
210
211         TypeDesc[] params = mParams;
212         for (int i=0; i<params.length; i++) {
213             if (i > 0) {
214                 buf.append(", ");
215             }
216             TypeDesc param = params[i];
217             if (varargs && param.isArray() && i == (params.length - 1)) {
218                 buf.append(param.getComponentType().getFullName());
219                 buf.append("...");
220             } else {
221                 buf.append(param.getFullName());
222             }
223         }
224
225         return buf.append(')').toString();
226     }
227
228     public String JavaDoc toString() {
229         // TODO: Return generic descriptor
230
return mDescriptor;
231     }
232
233     public int hashCode() {
234         return mDescriptor.hashCode();
235     }
236
237     public boolean equals(Object JavaDoc other) {
238         if (this == other) {
239             return true;
240         }
241         if (other instanceof MethodDesc) {
242             return ((MethodDesc)other).mDescriptor.equals(mDescriptor);
243         }
244         return false;
245     }
246
247     Object JavaDoc writeReplace() throws ObjectStreamException JavaDoc {
248         return new External(mDescriptor);
249     }
250
251     private static String JavaDoc generateDescriptor(TypeDesc ret, TypeDesc[] params) {
252         int length = ret.getDescriptor().length() + 2;
253         int paramsLength = params.length;
254         for (int i=paramsLength; --i >=0; ) {
255             length += params[i].getDescriptor().length();
256         }
257         char[] buf = new char[length];
258         buf[0] = '(';
259         int index = 1;
260         String JavaDoc paramDesc;
261         for (int i=0; i<paramsLength; i++) {
262             paramDesc = params[i].getDescriptor();
263             int paramDescLength = paramDesc.length();
264             paramDesc.getChars(0, paramDescLength, buf, index);
265             index += paramDescLength;
266         }
267         buf[index++] = ')';
268         paramDesc = ret.getDescriptor();
269         paramDesc.getChars(0, paramDesc.length(), buf, index);
270         return new String JavaDoc(buf);
271     }
272
273     private static class External implements Externalizable JavaDoc {
274         private String JavaDoc mDescriptor;
275
276         public External() {
277         }
278
279         public External(String JavaDoc desc) {
280             mDescriptor = desc;
281         }
282
283         public void writeExternal(ObjectOutput JavaDoc out) throws IOException JavaDoc {
284             out.writeUTF(mDescriptor);
285         }
286
287         public void readExternal(ObjectInput JavaDoc in) throws IOException JavaDoc {
288             mDescriptor = in.readUTF();
289         }
290
291         public Object JavaDoc readResolve() throws ObjectStreamException JavaDoc {
292             return forDescriptor(mDescriptor);
293         }
294     }
295 }
296
Popular Tags