KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > axis > utils > bytecode > ClassReader


1 /*
2  * Copyright 2002-2004 The Apache Software Foundation.
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.apache.axis.utils.bytecode;
18
19 import org.apache.axis.utils.Messages;
20
21 import java.io.ByteArrayInputStream JavaDoc;
22 import java.io.ByteArrayOutputStream JavaDoc;
23 import java.io.EOFException JavaDoc;
24 import java.io.IOException JavaDoc;
25 import java.io.InputStream JavaDoc;
26 import java.lang.reflect.Constructor JavaDoc;
27 import java.lang.reflect.Field JavaDoc;
28 import java.lang.reflect.InvocationTargetException JavaDoc;
29 import java.lang.reflect.Member JavaDoc;
30 import java.lang.reflect.Method JavaDoc;
31 import java.util.HashMap JavaDoc;
32 import java.util.Map JavaDoc;
33
34 /**
35  * This is the class file reader for obtaining the parameter names
36  * for declared methods in a class. The class must have debugging
37  * attributes for us to obtain this information. <p>
38  *
39  * This does not work for inherited methods. To obtain parameter
40  * names for inherited methods, you must use a paramReader for the
41  * class that originally declared the method. <p>
42  *
43  * don't get tricky, it's the bare minimum. Instances of this class
44  * are not threadsafe -- don't share them. <p>
45  *
46  * @author Edwin Smith, Macromedia
47  */

48 public class ClassReader extends ByteArrayInputStream JavaDoc {
49     // constants values that appear in java class files,
50
// from jvm spec 2nd ed, section 4.4, pp 103
51
private static final int CONSTANT_Class = 7;
52     private static final int CONSTANT_Fieldref = 9;
53     private static final int CONSTANT_Methodref = 10;
54     private static final int CONSTANT_InterfaceMethodref = 11;
55     private static final int CONSTANT_String = 8;
56     private static final int CONSTANT_Integer = 3;
57     private static final int CONSTANT_Float = 4;
58     private static final int CONSTANT_Long = 5;
59     private static final int CONSTANT_Double = 6;
60     private static final int CONSTANT_NameAndType = 12;
61     private static final int CONSTANT_Utf8 = 1;
62     /**
63      * the constant pool. constant pool indices in the class file
64      * directly index into this array. The value stored in this array
65      * is the position in the class file where that constant begins.
66      */

67     private int[] cpoolIndex;
68     private Object JavaDoc[] cpool;
69
70     private Map JavaDoc attrMethods;
71
72     /**
73      * load the bytecode for a given class, by using the class's defining
74      * classloader and assuming that for a class named P.C, the bytecodes are
75      * in a resource named /P/C.class.
76      * @param c the class of interest
77      * @return a byte array containing the bytecode
78      * @throws IOException
79      */

80     protected static byte[] getBytes(Class JavaDoc c) throws IOException JavaDoc {
81         InputStream JavaDoc fin = c.getResourceAsStream('/' + c.getName().replace('.', '/') + ".class");
82         if (fin == null) {
83             throw new IOException JavaDoc(
84                     Messages.getMessage("cantLoadByecode", c.getName()));
85         }
86         try {
87             ByteArrayOutputStream JavaDoc out = new ByteArrayOutputStream JavaDoc();
88             byte[] buf = new byte[1024];
89             int actual;
90             do {
91                 actual = fin.read(buf);
92                 if (actual > 0) {
93                     out.write(buf, 0, actual);
94                 }
95             } while (actual > 0);
96             return out.toByteArray();
97         } finally {
98             fin.close();
99         }
100     }
101
102     static String JavaDoc classDescriptorToName(String JavaDoc desc) {
103         return desc.replace('/', '.');
104     }
105
106     protected static Map JavaDoc findAttributeReaders(Class JavaDoc c) {
107         HashMap JavaDoc map = new HashMap JavaDoc();
108         Method JavaDoc[] methods = c.getMethods();
109
110         for (int i = 0; i < methods.length; i++) {
111             String JavaDoc name = methods[i].getName();
112             if (name.startsWith("read") && methods[i].getReturnType() == void.class) {
113                 map.put(name.substring(4), methods[i]);
114             }
115         }
116
117         return map;
118     }
119
120
121     protected static String JavaDoc getSignature(Member JavaDoc method, Class JavaDoc[] paramTypes) {
122         // compute the method descriptor
123

124         StringBuffer JavaDoc b = new StringBuffer JavaDoc((method instanceof Method JavaDoc) ? method.getName() : "<init>");
125         b.append('(');
126
127         for (int i = 0; i < paramTypes.length; i++) {
128             addDescriptor(b, paramTypes[i]);
129         }
130
131         b.append(')');
132         if (method instanceof Method JavaDoc) {
133             addDescriptor(b, ((Method JavaDoc) method).getReturnType());
134         } else if (method instanceof Constructor JavaDoc) {
135             addDescriptor(b, void.class);
136         }
137
138         return b.toString();
139     }
140
141     private static void addDescriptor(StringBuffer JavaDoc b, Class JavaDoc c) {
142         if (c.isPrimitive()) {
143             if (c == void.class)
144                 b.append('V');
145             else if (c == int.class)
146                 b.append('I');
147             else if (c == boolean.class)
148                 b.append('Z');
149             else if (c == byte.class)
150                 b.append('B');
151             else if (c == short.class)
152                 b.append('S');
153             else if (c == long.class)
154                 b.append('J');
155             else if (c == char.class)
156                 b.append('C');
157             else if (c == float.class)
158                 b.append('F');
159             else if (c == double.class) b.append('D');
160         } else if (c.isArray()) {
161             b.append('[');
162             addDescriptor(b, c.getComponentType());
163         } else {
164             b.append('L').append(c.getName().replace('.', '/')).append(';');
165         }
166     }
167
168
169     /**
170      * @return the next unsigned 16 bit value
171      */

172     protected final int readShort() {
173         return (read() << 8) | read();
174     }
175
176     /**
177      * @return the next signed 32 bit value
178      */

179     protected final int readInt() {
180         return (read() << 24) | (read() << 16) | (read() << 8) | read();
181     }
182
183     /**
184      * skip n bytes in the input stream.
185      */

186     protected void skipFully(int n) throws IOException JavaDoc {
187         while (n > 0) {
188             int c = (int) skip(n);
189             if (c <= 0)
190                 throw new EOFException JavaDoc(Messages.getMessage("unexpectedEOF00"));
191             n -= c;
192         }
193     }
194
195     protected final Member JavaDoc resolveMethod(int index) throws IOException JavaDoc, ClassNotFoundException JavaDoc, NoSuchMethodException JavaDoc {
196         int oldPos = pos;
197         try {
198             Member JavaDoc m = (Member JavaDoc) cpool[index];
199             if (m == null) {
200                 pos = cpoolIndex[index];
201                 Class JavaDoc owner = resolveClass(readShort());
202                 NameAndType nt = resolveNameAndType(readShort());
203                 String JavaDoc signature = nt.name + nt.type;
204                 if (nt.name.equals("<init>")) {
205                     Constructor JavaDoc[] ctors = owner.getConstructors();
206                     for (int i = 0; i < ctors.length; i++) {
207                         String JavaDoc sig = getSignature(ctors[i], ctors[i].getParameterTypes());
208                         if (sig.equals(signature)) {
209                             cpool[index] = m = ctors[i];
210                             return m;
211                         }
212                     }
213                 } else {
214                     Method JavaDoc[] methods = owner.getDeclaredMethods();
215                     for (int i = 0; i < methods.length; i++) {
216                         String JavaDoc sig = getSignature(methods[i], methods[i].getParameterTypes());
217                         if (sig.equals(signature)) {
218                             cpool[index] = m = methods[i];
219                             return m;
220                         }
221                     }
222                 }
223                 throw new NoSuchMethodException JavaDoc(signature);
224             }
225             return m;
226         } finally {
227             pos = oldPos;
228         }
229
230     }
231
232     protected final Field JavaDoc resolveField(int i) throws IOException JavaDoc, ClassNotFoundException JavaDoc, NoSuchFieldException JavaDoc {
233         int oldPos = pos;
234         try {
235             Field JavaDoc f = (Field JavaDoc) cpool[i];
236             if (f == null) {
237                 pos = cpoolIndex[i];
238                 Class JavaDoc owner = resolveClass(readShort());
239                 NameAndType nt = resolveNameAndType(readShort());
240                 cpool[i] = f = owner.getDeclaredField(nt.name);
241             }
242             return f;
243         } finally {
244             pos = oldPos;
245         }
246     }
247
248     private static class NameAndType {
249         String JavaDoc name;
250         String JavaDoc type;
251
252         public NameAndType(String JavaDoc name, String JavaDoc type) {
253             this.name = name;
254             this.type = type;
255         }
256     }
257
258     protected final NameAndType resolveNameAndType(int i) throws IOException JavaDoc {
259         int oldPos = pos;
260         try {
261             NameAndType nt = (NameAndType) cpool[i];
262             if (nt == null) {
263                 pos = cpoolIndex[i];
264                 String JavaDoc name = resolveUtf8(readShort());
265                 String JavaDoc type = resolveUtf8(readShort());
266                 cpool[i] = nt = new NameAndType(name, type);
267             }
268             return nt;
269         } finally {
270             pos = oldPos;
271         }
272     }
273
274
275     protected final Class JavaDoc resolveClass(int i) throws IOException JavaDoc, ClassNotFoundException JavaDoc {
276         int oldPos = pos;
277         try {
278             Class JavaDoc c = (Class JavaDoc) cpool[i];
279             if (c == null) {
280                 pos = cpoolIndex[i];
281                 String JavaDoc name = resolveUtf8(readShort());
282                 cpool[i] = c = Class.forName(classDescriptorToName(name));
283             }
284             return c;
285         } finally {
286             pos = oldPos;
287         }
288     }
289
290     protected final String JavaDoc resolveUtf8(int i) throws IOException JavaDoc {
291         int oldPos = pos;
292         try {
293             String JavaDoc s = (String JavaDoc) cpool[i];
294             if (s == null) {
295                 pos = cpoolIndex[i];
296                 int len = readShort();
297                 skipFully(len);
298                 cpool[i] = s = new String JavaDoc(buf, pos - len, len, "utf-8");
299             }
300             return s;
301         } finally {
302             pos = oldPos;
303         }
304     }
305
306     protected final void readCpool() throws IOException JavaDoc {
307         int count = readShort(); // cpool count
308
cpoolIndex = new int[count];
309         cpool = new Object JavaDoc[count];
310         for (int i = 1; i < count; i++) {
311             int c = read();
312             cpoolIndex[i] = super.pos;
313             switch (c) // constant pool tag
314
{
315                 case CONSTANT_Fieldref:
316                 case CONSTANT_Methodref:
317                 case CONSTANT_InterfaceMethodref:
318                 case CONSTANT_NameAndType:
319
320                     readShort(); // class index or (12) name index
321
// fall through
322

323                 case CONSTANT_Class:
324                 case CONSTANT_String:
325
326                     readShort(); // string index or class index
327
break;
328
329                 case CONSTANT_Long:
330                 case CONSTANT_Double:
331
332                     readInt(); // hi-value
333

334                     // see jvm spec section 4.4.5 - double and long cpool
335
// entries occupy two "slots" in the cpool table.
336
i++;
337                     // fall through
338

339                 case CONSTANT_Integer:
340                 case CONSTANT_Float:
341
342                     readInt(); // value
343
break;
344
345                 case CONSTANT_Utf8:
346
347                     int len = readShort();
348                     skipFully(len);
349                     break;
350
351                 default:
352                     // corrupt class file
353
throw new IllegalStateException JavaDoc(
354                             Messages.getMessage("unexpectedBytes00"));
355             }
356         }
357     }
358
359     protected final void skipAttributes() throws IOException JavaDoc {
360         int count = readShort();
361         for (int i = 0; i < count; i++) {
362             readShort(); // name index
363
skipFully(readInt());
364         }
365     }
366
367     /**
368      * read an attributes array. the elements of a class file that
369      * can contain attributes are: fields, methods, the class itself,
370      * and some other types of attributes.
371      */

372     protected final void readAttributes() throws IOException JavaDoc {
373         int count = readShort();
374         for (int i = 0; i < count; i++) {
375             int nameIndex = readShort(); // name index
376
int attrLen = readInt();
377             int curPos = pos;
378
379             String JavaDoc attrName = resolveUtf8(nameIndex);
380
381             Method JavaDoc m = (Method JavaDoc) attrMethods.get(attrName);
382
383             if (m != null) {
384                 try {
385                     m.invoke(this, new Object JavaDoc[]{});
386                 } catch (IllegalAccessException JavaDoc e) {
387                     pos = curPos;
388                     skipFully(attrLen);
389                 } catch (InvocationTargetException JavaDoc e) {
390                     try {
391                         throw e.getTargetException();
392                     } catch (Error JavaDoc ex) {
393                         throw ex;
394                     } catch (RuntimeException JavaDoc ex) {
395                         throw ex;
396                     } catch (IOException JavaDoc ex) {
397                         throw ex;
398                     } catch (Throwable JavaDoc ex) {
399                         pos = curPos;
400                         skipFully(attrLen);
401                     }
402                 }
403             } else {
404                 // don't care what attribute this is
405
skipFully(attrLen);
406             }
407         }
408     }
409
410     /**
411      * read a code attribute
412      * @throws IOException
413      */

414     public void readCode() throws IOException JavaDoc {
415         readShort(); // max stack
416
readShort(); // max locals
417
skipFully(readInt()); // code
418
skipFully(8 * readShort()); // exception table
419

420         // read the code attributes (recursive). This is where
421
// we will find the LocalVariableTable attribute.
422
readAttributes();
423     }
424
425     protected ClassReader(byte buf[], Map JavaDoc attrMethods) {
426         super(buf);
427
428         this.attrMethods = attrMethods;
429     }
430 }
431
432
Popular Tags