KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2  * The Apache Software License, Version 1.1
3  *
4  *
5  * Copyright (c) 2002-2003 The Apache Software Foundation. All rights
6  * reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in
17  * the documentation and/or other materials provided with the
18  * distribution.
19  *
20  * 3. The end-user documentation included with the redistribution,
21  * if any, must include the following acknowledgment:
22  * "This product includes software developed by the
23  * Apache Software Foundation (http://www.apache.org/)."
24  * Alternately, this acknowledgment may appear in the software itself,
25  * if and wherever such third-party acknowledgments normally appear.
26  *
27  * 4. The names "Axis" and "Apache Software Foundation" must
28  * not be used to endorse or promote products derived from this
29  * software without prior written permission. For written
30  * permission, please contact apache@apache.org.
31  *
32  * 5. Products derived from this software may not be called "Apache",
33  * nor may "Apache" appear in their name, without prior written
34  * permission of the Apache Software Foundation.
35  *
36  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39  * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
40  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
42  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
43  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
44  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
45  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
46  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47  * SUCH DAMAGE.
48  * ====================================================================
49  *
50  * This software consists of voluntary contributions made by many
51  * individuals on behalf of the Apache Software Foundation. For more
52  * information on the Apache Software Foundation, please see
53  * <http://www.apache.org/>.
54  */

55
56 package org.jboss.axis.utils.bytecode;
57
58 import org.jboss.axis.utils.Messages;
59
60 import java.io.ByteArrayInputStream JavaDoc;
61 import java.io.ByteArrayOutputStream JavaDoc;
62 import java.io.EOFException JavaDoc;
63 import java.io.IOException JavaDoc;
64 import java.io.InputStream JavaDoc;
65 import java.lang.reflect.Constructor JavaDoc;
66 import java.lang.reflect.Field JavaDoc;
67 import java.lang.reflect.InvocationTargetException JavaDoc;
68 import java.lang.reflect.Member JavaDoc;
69 import java.lang.reflect.Method JavaDoc;
70 import java.util.HashMap JavaDoc;
71 import java.util.Map JavaDoc;
72
73 /**
74  * This is the class file reader for obtaining the parameter names
75  * for declared methods in a class. The class must have debugging
76  * attributes for us to obtain this information. <p>
77  * <p/>
78  * This does not work for inherited methods. To obtain parameter
79  * names for inherited methods, you must use a paramReader for the
80  * class that originally declared the method. <p>
81  * <p/>
82  * don't get tricky, it's the bare minimum. Instances of this class
83  * are not threadsafe -- don't share them. <p>
84  *
85  * @author Edwin Smith, Macromedia
86  */

87 public class ClassReader extends ByteArrayInputStream JavaDoc
88 {
89    // constants values that appear in java class files,
90
// from jvm spec 2nd ed, section 4.4, pp 103
91
private static final int CONSTANT_Class = 7;
92    private static final int CONSTANT_Fieldref = 9;
93    private static final int CONSTANT_Methodref = 10;
94    private static final int CONSTANT_InterfaceMethodref = 11;
95    private static final int CONSTANT_String = 8;
96    private static final int CONSTANT_Integer = 3;
97    private static final int CONSTANT_Float = 4;
98    private static final int CONSTANT_Long = 5;
99    private static final int CONSTANT_Double = 6;
100    private static final int CONSTANT_NameAndType = 12;
101    private static final int CONSTANT_Utf8 = 1;
102    /**
103     * the constant pool. constant pool indices in the class file
104     * directly index into this array. The value stored in this array
105     * is the position in the class file where that constant begins.
106     */

107    private int[] cpoolIndex;
108    private Object JavaDoc[] cpool;
109
110    private Map JavaDoc attrMethods;
111
112    /**
113     * load the bytecode for a given class, by using the class's defining
114     * classloader and assuming that for a class named P.C, the bytecodes are
115     * in a resource named /P/C.class.
116     *
117     * @param c the class of interest
118     * @return a byte array containing the bytecode
119     * @throws IOException
120     */

121    protected static byte[] getBytes(Class JavaDoc c) throws IOException JavaDoc
122    {
123       InputStream JavaDoc fin = c.getResourceAsStream('/' + c.getName().replace('.', '/') + ".class");
124       if (fin == null)
125       {
126          throw new IOException JavaDoc(Messages.getMessage("cantLoadByecode", c.getName()));
127       }
128       try
129       {
130          ByteArrayOutputStream JavaDoc out = new ByteArrayOutputStream JavaDoc();
131          byte[] buf = new byte[1024];
132          int actual;
133          do
134          {
135             actual = fin.read(buf);
136             if (actual > 0)
137             {
138                out.write(buf, 0, actual);
139             }
140          }
141          while (actual > 0);
142          return out.toByteArray();
143       }
144       finally
145       {
146          fin.close();
147       }
148    }
149
150    static String JavaDoc classDescriptorToName(String JavaDoc desc)
151    {
152       return desc.replace('/', '.');
153    }
154
155    protected static Map JavaDoc findAttributeReaders(Class JavaDoc c)
156    {
157       HashMap JavaDoc map = new HashMap JavaDoc();
158       Method JavaDoc[] methods = c.getMethods();
159
160       for (int i = 0; i < methods.length; i++)
161       {
162          String JavaDoc name = methods[i].getName();
163          if (name.startsWith("read") && methods[i].getReturnType() == void.class)
164          {
165             map.put(name.substring(4), methods[i]);
166          }
167       }
168
169       return map;
170    }
171
172
173    protected static String JavaDoc getSignature(Member JavaDoc method, Class JavaDoc[] paramTypes)
174    {
175       // compute the method descriptor
176

177       StringBuffer JavaDoc b = new StringBuffer JavaDoc((method instanceof Method JavaDoc) ? method.getName() : "<init>");
178       b.append('(');
179
180       for (int i = 0; i < paramTypes.length; i++)
181       {
182          addDescriptor(b, paramTypes[i]);
183       }
184
185       b.append(')');
186       if (method instanceof Method JavaDoc)
187       {
188          addDescriptor(b, ((Method JavaDoc)method).getReturnType());
189       }
190       else if (method instanceof Constructor JavaDoc)
191       {
192          addDescriptor(b, void.class);
193       }
194
195       return b.toString();
196    }
197
198    private static void addDescriptor(StringBuffer JavaDoc b, Class JavaDoc c)
199    {
200       if (c.isPrimitive())
201       {
202          if (c == void.class)
203             b.append('V');
204          else if (c == int.class)
205             b.append('I');
206          else if (c == boolean.class)
207             b.append('Z');
208          else if (c == byte.class)
209             b.append('B');
210          else if (c == short.class)
211             b.append('S');
212          else if (c == long.class)
213             b.append('J');
214          else if (c == char.class)
215             b.append('C');
216          else if (c == float.class)
217             b.append('F');
218          else if (c == double.class) b.append('D');
219       }
220       else if (c.isArray())
221       {
222          b.append('[');
223          addDescriptor(b, c.getComponentType());
224       }
225       else
226       {
227          b.append('L').append(c.getName().replace('.', '/')).append(';');
228       }
229    }
230
231
232    /**
233     * @return the next unsigned 16 bit value
234     */

235    protected final int readShort()
236    {
237       return (read() << 8) | read();
238    }
239
240    /**
241     * @return the next signed 32 bit value
242     */

243    protected final int readInt()
244    {
245       return (read() << 24) | (read() << 16) | (read() << 8) | read();
246    }
247
248    /**
249     * skip n bytes in the input stream.
250     */

251    protected void skipFully(int n) throws IOException JavaDoc
252    {
253       while (n > 0)
254       {
255          int c = (int)skip(n);
256          if (c <= 0)
257             throw new EOFException JavaDoc(Messages.getMessage("unexpectedEOF00"));
258          n -= c;
259       }
260    }
261
262    protected final Member JavaDoc resolveMethod(int index) throws IOException JavaDoc, ClassNotFoundException JavaDoc, NoSuchMethodException JavaDoc
263    {
264       int oldPos = pos;
265       try
266       {
267          Member JavaDoc m = (Member JavaDoc)cpool[index];
268          if (m == null)
269          {
270             pos = cpoolIndex[index];
271             Class JavaDoc owner = resolveClass(readShort());
272             NameAndType nt = resolveNameAndType(readShort());
273             String JavaDoc signature = nt.name + nt.type;
274             if (nt.name.equals("<init>"))
275             {
276                Constructor JavaDoc[] ctors = owner.getConstructors();
277                for (int i = 0; i < ctors.length; i++)
278                {
279                   String JavaDoc sig = getSignature(ctors[i], ctors[i].getParameterTypes());
280                   if (sig.equals(signature))
281                   {
282                      cpool[index] = m = ctors[i];
283                      return m;
284                   }
285                }
286             }
287             else
288             {
289                Method JavaDoc[] methods = owner.getDeclaredMethods();
290                for (int i = 0; i < methods.length; i++)
291                {
292                   String JavaDoc sig = getSignature(methods[i], methods[i].getParameterTypes());
293                   if (sig.equals(signature))
294                   {
295                      cpool[index] = m = methods[i];
296                      return m;
297                   }
298                }
299             }
300             throw new NoSuchMethodException JavaDoc(signature);
301          }
302          return m;
303       }
304       finally
305       {
306          pos = oldPos;
307       }
308
309    }
310
311    protected final Field JavaDoc resolveField(int i) throws IOException JavaDoc, ClassNotFoundException JavaDoc, NoSuchFieldException JavaDoc
312    {
313       int oldPos = pos;
314       try
315       {
316          Field JavaDoc f = (Field JavaDoc)cpool[i];
317          if (f == null)
318          {
319             pos = cpoolIndex[i];
320             Class JavaDoc owner = resolveClass(readShort());
321             NameAndType nt = resolveNameAndType(readShort());
322             cpool[i] = f = owner.getDeclaredField(nt.name);
323          }
324          return f;
325       }
326       finally
327       {
328          pos = oldPos;
329       }
330    }
331
332    private static class NameAndType
333    {
334       String JavaDoc name;
335       String JavaDoc type;
336
337       public NameAndType(String JavaDoc name, String JavaDoc type)
338       {
339          this.name = name;
340          this.type = type;
341       }
342    }
343
344    protected final NameAndType resolveNameAndType(int i) throws IOException JavaDoc
345    {
346       int oldPos = pos;
347       try
348       {
349          NameAndType nt = (NameAndType)cpool[i];
350          if (nt == null)
351          {
352             pos = cpoolIndex[i];
353             String JavaDoc name = resolveUtf8(readShort());
354             String JavaDoc type = resolveUtf8(readShort());
355             cpool[i] = nt = new NameAndType(name, type);
356          }
357          return nt;
358       }
359       finally
360       {
361          pos = oldPos;
362       }
363    }
364
365
366    protected final Class JavaDoc resolveClass(int i) throws IOException JavaDoc, ClassNotFoundException JavaDoc
367    {
368       int oldPos = pos;
369       try
370       {
371          Class JavaDoc c = (Class JavaDoc)cpool[i];
372          if (c == null)
373          {
374             pos = cpoolIndex[i];
375             String JavaDoc name = resolveUtf8(readShort());
376             cpool[i] = c = Class.forName(classDescriptorToName(name));
377          }
378          return c;
379       }
380       finally
381       {
382          pos = oldPos;
383       }
384    }
385
386    protected final String JavaDoc resolveUtf8(int i) throws IOException JavaDoc
387    {
388       int oldPos = pos;
389       try
390       {
391          String JavaDoc s = (String JavaDoc)cpool[i];
392          if (s == null)
393          {
394             pos = cpoolIndex[i];
395             int len = readShort();
396             skipFully(len);
397             cpool[i] = s = new String JavaDoc(buf, pos - len, len, "utf-8");
398          }
399          return s;
400       }
401       finally
402       {
403          pos = oldPos;
404       }
405    }
406
407    protected final void readCpool() throws IOException JavaDoc
408    {
409       int count = readShort(); // cpool count
410
cpoolIndex = new int[count];
411       cpool = new Object JavaDoc[count];
412       for (int i = 1; i < count; i++)
413       {
414          int c = read();
415          cpoolIndex[i] = super.pos;
416          switch (c) // constant pool tag
417
{
418             case CONSTANT_Fieldref:
419             case CONSTANT_Methodref:
420             case CONSTANT_InterfaceMethodref:
421             case CONSTANT_NameAndType:
422
423                readShort(); // class index or (12) name index
424
// fall through
425

426             case CONSTANT_Class:
427             case CONSTANT_String:
428
429                readShort(); // string index or class index
430
break;
431
432             case CONSTANT_Long:
433             case CONSTANT_Double:
434
435                readInt(); // hi-value
436

437                // see jvm spec section 4.4.5 - double and long cpool
438
// entries occupy two "slots" in the cpool table.
439
i++;
440                // fall through
441

442             case CONSTANT_Integer:
443             case CONSTANT_Float:
444
445                readInt(); // value
446
break;
447
448             case CONSTANT_Utf8:
449
450                int len = readShort();
451                skipFully(len);
452                break;
453
454             default:
455                // corrupt class file
456
throw new IllegalStateException JavaDoc(Messages.getMessage("unexpectedBytes00"));
457          }
458       }
459    }
460
461    protected final void skipAttributes() throws IOException JavaDoc
462    {
463       int count = readShort();
464       for (int i = 0; i < count; i++)
465       {
466          readShort(); // name index
467
skipFully(readInt());
468       }
469    }
470
471    /**
472     * read an attributes array. the elements of a class file that
473     * can contain attributes are: fields, methods, the class itself,
474     * and some other types of attributes.
475     */

476    protected final void readAttributes() throws IOException JavaDoc
477    {
478       int count = readShort();
479       for (int i = 0; i < count; i++)
480       {
481          int nameIndex = readShort(); // name index
482
int attrLen = readInt();
483          int curPos = pos;
484
485          String JavaDoc attrName = resolveUtf8(nameIndex);
486
487          Method JavaDoc m = (Method JavaDoc)attrMethods.get(attrName);
488
489          if (m != null)
490          {
491             try
492             {
493                m.invoke(this, new Object JavaDoc[]{});
494             }
495             catch (IllegalAccessException JavaDoc e)
496             {
497                pos = curPos;
498                skipFully(attrLen);
499             }
500             catch (InvocationTargetException JavaDoc e)
501             {
502                try
503                {
504                   throw e.getTargetException();
505                }
506                catch (Error JavaDoc ex)
507                {
508                   throw ex;
509                }
510                catch (RuntimeException JavaDoc ex)
511                {
512                   throw ex;
513                }
514                catch (IOException JavaDoc ex)
515                {
516                   throw ex;
517                }
518                catch (Throwable JavaDoc ex)
519                {
520                   pos = curPos;
521                   skipFully(attrLen);
522                }
523             }
524          }
525          else
526          {
527             // don't care what attribute this is
528
skipFully(attrLen);
529          }
530       }
531    }
532
533    /**
534     * read a code attribute
535     *
536     * @throws IOException
537     */

538    public void readCode() throws IOException JavaDoc
539    {
540       readShort(); // max stack
541
readShort(); // max locals
542
skipFully(readInt()); // code
543
skipFully(8 * readShort()); // exception table
544

545       // read the code attributes (recursive). This is where
546
// we will find the LocalVariableTable attribute.
547
readAttributes();
548    }
549
550    protected ClassReader(byte buf[], Map JavaDoc attrMethods)
551    {
552       super(buf);
553
554       this.attrMethods = attrMethods;
555    }
556 }
557
558
Popular Tags