KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > go > trove > classfile > ClassFile


1 /* ====================================================================
2  * Trove - Copyright (c) 1997-2000 Walt Disney Internet Group
3  * ====================================================================
4  * The Tea Software License, Version 1.1
5  *
6  * Copyright (c) 2000 Walt Disney Internet Group. All rights 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  * Walt Disney Internet Group (http://opensource.go.com/)."
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 "Tea", "TeaServlet", "Kettle", "Trove" and "BeanDoc" 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 opensource@dig.com.
31  *
32  * 5. Products derived from this software may not be called "Tea",
33  * "TeaServlet", "Kettle" or "Trove", nor may "Tea", "TeaServlet",
34  * "Kettle", "Trove" or "BeanDoc" appear in their name, without prior
35  * written permission of the Walt Disney Internet Group.
36  *
37  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
38  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
39  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
40  * DISCLAIMED. IN NO EVENT SHALL THE WALT DISNEY INTERNET GROUP OR ITS
41  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
42  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
43  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
44  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
45  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
46  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
47  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
48  * ====================================================================
49  *
50  * For more information about Tea, please see http://opensource.go.com/.
51  */

52
53 package com.go.trove.classfile;
54
55 import java.lang.reflect.*;
56 import java.util.Set JavaDoc;
57 import java.util.HashSet JavaDoc;
58 import java.util.List JavaDoc;
59 import java.util.ArrayList JavaDoc;
60 import java.util.Map JavaDoc;
61 import java.util.HashMap JavaDoc;
62 import java.io.*;
63
64 /******************************************************************************
65  * A class used to create Java class files. Call the writeTo method
66  * to produce a class file.
67  *
68  * <p>See <i>The Java Virtual Machine Specification</i> (ISBN 0-201-63452-X)
69  * for information on how class files are structured. Section 4.1 describes
70  * the ClassFile structure.
71  *
72  * @author Brian S O'Neill
73  * @version
74  * <!--$$Revision:--> 38 <!-- $-->, <!--$$JustDate:--> 01/05/17 <!-- $-->
75  */

76 public class ClassFile {
77     private static final int MAGIC = 0xCAFEBABE;
78     private static final int JDK1_1_MAJOR_VERSION = 45;
79     private static final int JDK1_1_MINOR_VERSION = 3;
80     
81     private int mMajorVersion = JDK1_1_MAJOR_VERSION;
82     private int mMinorVersion = JDK1_1_MINOR_VERSION;
83
84     private String JavaDoc mClassName;
85     private String JavaDoc mSuperClassName;
86     private String JavaDoc mInnerClassName;
87     private TypeDescriptor mType;
88
89     private ConstantPool mCp;
90     
91     private AccessFlags mAccessFlags;
92
93     private ConstantClassInfo mThisClass;
94     private ConstantClassInfo mSuperClass;
95     
96     // Holds ConstantInfo objects.
97
private List JavaDoc mInterfaces = new ArrayList JavaDoc(2);
98     private Set JavaDoc mInterfaceSet = new HashSet JavaDoc(7);
99     
100     // Holds objects.
101
private List JavaDoc mFields = new ArrayList JavaDoc();
102     private List JavaDoc mMethods = new ArrayList JavaDoc();
103     private List JavaDoc mAttributes = new ArrayList JavaDoc();
104     
105     private SourceFileAttr mSource;
106
107     private List JavaDoc mInnerClasses;
108     private int mAnonymousInnerClassCount = 0;
109     private InnerClassesAttr mInnerClassesAttr;
110
111     // Is non-null for inner classes.
112
private ClassFile mOuterClass;
113
114     /**
115      * By default, the ClassFile defines public, non-final, concrete classes.
116      * This constructor creates a ClassFile for a class that extends
117      * java.lang.Object.
118      * <p>
119      * Use the {@link #getAccessFlags access flags} to change the default
120      * modifiers for this class or to turn it into an interface.
121      *
122      * @param className Full class name of the form ex: "java.lang.String".
123      */

124     public ClassFile(String JavaDoc className) {
125         this(className, (String JavaDoc)null);
126     }
127     
128     /**
129      * By default, the ClassFile defines public, non-final, concrete classes.
130      * <p>
131      * Use the {@link #getAccessFlags access flags} to change the default
132      * modifiers for this class or to turn it into an interface.
133      *
134      * @param className Full class name of the form ex: "java.lang.String".
135      * @param superClass Super class.
136      */

137     public ClassFile(String JavaDoc className, Class JavaDoc superClass) {
138         this(className, superClass.getName());
139     }
140
141     /**
142      * By default, the ClassFile defines public, non-final, concrete classes.
143      * <p>
144      * Use the {@link #getAccessFlags access flags} to change the default
145      * modifiers for this class or to turn it into an interface.
146      *
147      * @param className Full class name of the form ex: "java.lang.String".
148      * @param superClassName Full super class name.
149      */

150     public ClassFile(String JavaDoc className, String JavaDoc superClassName) {
151         if (superClassName == null) {
152             if (!className.equals(Object JavaDoc.class.getName())) {
153                 superClassName = Object JavaDoc.class.getName();
154             }
155         }
156
157         mCp = new ConstantPool();
158
159         // public, non-final, concrete class
160
mAccessFlags = new AccessFlags(Modifier.PUBLIC);
161
162         mThisClass = ConstantClassInfo.make(mCp, className);
163         mSuperClass = ConstantClassInfo.make(mCp, superClassName);
164
165         mClassName = className;
166         mSuperClassName = superClassName;
167     }
168
169     /**
170      * Used to construct a ClassFile when read from a stream.
171      */

172     private ClassFile(ConstantPool cp, AccessFlags accessFlags,
173                       ConstantClassInfo thisClass,
174                       ConstantClassInfo superClass,
175                       ClassFile outerClass) {
176
177         mCp = cp;
178
179         mAccessFlags = accessFlags;
180
181         mThisClass = thisClass;
182         mSuperClass = superClass;
183
184         mClassName = thisClass.getClassName();
185         if (superClass != null) {
186             mSuperClassName = superClass.getClassName();
187         }
188
189         mOuterClass = outerClass;
190     }
191
192     public String JavaDoc getClassName() {
193         return mClassName;
194     }
195
196     public String JavaDoc getSuperClassName() {
197         return mSuperClassName;
198     }
199
200     /**
201      * Returns a TypeDescriptor for the type of this ClassFile.
202      */

203     public TypeDescriptor getType() {
204         if (mType == null) {
205             mType = new TypeDescriptor(mClassName);
206         }
207         return mType;
208     }
209
210     public AccessFlags getAccessFlags() {
211         return mAccessFlags;
212     }
213
214     /**
215      * Returns the names of all the interfaces that this class implements.
216      */

217     public String JavaDoc[] getInterfaces() {
218         int size = mInterfaces.size();
219         String JavaDoc[] names = new String JavaDoc[size];
220
221         for (int i=0; i<size; i++) {
222             names[i] = ((ConstantClassInfo)mInterfaces.get(i)).getClassName();
223         }
224
225         return names;
226     }
227
228     /**
229      * Returns all the fields defined in this class.
230      */

231     public FieldInfo[] getFields() {
232         FieldInfo[] fields = new FieldInfo[mFields.size()];
233         return (FieldInfo[])mFields.toArray(fields);
234     }
235
236     /**
237      * Returns all the methods defined in this class, not including
238      * constructors and static initializers.
239      */

240     public MethodInfo[] getMethods() {
241         int size = mMethods.size();
242         List JavaDoc methodsOnly = new ArrayList JavaDoc(size);
243
244         for (int i=0; i<size; i++) {
245             MethodInfo method = (MethodInfo)mMethods.get(i);
246             String JavaDoc name = method.getName();
247             if (!"<init>".equals(name) && !"<clinit>".equals(name)) {
248                 methodsOnly.add(method);
249             }
250         }
251
252         MethodInfo[] methodsArray = new MethodInfo[methodsOnly.size()];
253         return (MethodInfo[])methodsOnly.toArray(methodsArray);
254     }
255
256     /**
257      * Returns all the constructors defined in this class.
258      */

259     public MethodInfo[] getConstructors() {
260         int size = mMethods.size();
261         List JavaDoc ctorsOnly = new ArrayList JavaDoc(size);
262
263         for (int i=0; i<size; i++) {
264             MethodInfo method = (MethodInfo)mMethods.get(i);
265             if ("<init>".equals(method.getName())) {
266                 ctorsOnly.add(method);
267             }
268         }
269
270         MethodInfo[] ctorsArray = new MethodInfo[ctorsOnly.size()];
271         return (MethodInfo[])ctorsOnly.toArray(ctorsArray);
272     }
273
274     /**
275      * Returns the static initializer defined in this class or null if there
276      * isn't one.
277      */

278     public MethodInfo getInitializer() {
279         int size = mMethods.size();
280
281         for (int i=0; i<size; i++) {
282             MethodInfo method = (MethodInfo)mMethods.get(i);
283             if ("<clinit>".equals(method.getName())) {
284                 return method;
285             }
286         }
287
288         return null;
289     }
290
291     /**
292      * Returns all the inner classes defined in this class. If no inner classes
293      * are defined, then an array of length zero is returned.
294      */

295     public ClassFile[] getInnerClasses() {
296         if (mInnerClasses == null) {
297             return new ClassFile[0];
298         }
299
300         ClassFile[] innerClasses = new ClassFile[mInnerClasses.size()];
301         return (ClassFile[])mInnerClasses.toArray(innerClasses);
302     }
303
304     /**
305      * Returns true if this ClassFile represents an inner class.
306      */

307     public boolean isInnerClass() {
308         return mOuterClass != null;
309     }
310
311     /**
312      * If this ClassFile represents a non-anonymous inner class, returns its
313      * short inner class name.
314      */

315     public String JavaDoc getInnerClassName() {
316         return mInnerClassName;
317     }
318
319     /**
320      * Returns null if this ClassFile does not represent an inner class.
321      *
322      * @see #isInnerClass()
323      */

324     public ClassFile getOuterClass() {
325         return mOuterClass;
326     }
327
328     /**
329      * Returns a value indicating how deeply nested an inner class is with
330      * respect to its outermost enclosing class. For top level classes, 0
331      * is returned. For first level inner classes, 1 is returned, etc.
332      */

333     public int getClassDepth() {
334         int depth = 0;
335
336         ClassFile outer = mOuterClass;
337         while (outer != null) {
338             depth++;
339             outer = outer.mOuterClass;
340         }
341
342         return depth;
343     }
344
345     /**
346      * Returns the source file of this class file or null if not set.
347      */

348     public String JavaDoc getSourceFile() {
349         if (mSource == null) {
350             return null;
351         }
352         else {
353             return mSource.getFileName();
354         }
355     }
356
357     public boolean isSynthetic() {
358         for (int i = mAttributes.size(); --i >= 0; ) {
359             Object JavaDoc obj = mAttributes.get(i);
360             if (obj instanceof SyntheticAttr) {
361                 return true;
362             }
363         }
364         return false;
365     }
366
367     public boolean isDeprecated() {
368         for (int i = mAttributes.size(); --i >= 0; ) {
369             Object JavaDoc obj = mAttributes.get(i);
370             if (obj instanceof DeprecatedAttr) {
371                 return true;
372             }
373         }
374         return false;
375     }
376
377     /**
378      * Provides access to the ClassFile's ContantPool.
379      *
380      * @return The constant pool for this class file.
381      */

382     public ConstantPool getConstantPool() {
383         return mCp;
384     }
385     
386     /**
387      * Add an interface that this class implements.
388      *
389      * @param interfaceName Full interface name.
390      */

391     public void addInterface(String JavaDoc interfaceName) {
392         if (!mInterfaceSet.contains(interfaceName)) {
393             mInterfaces.add(ConstantClassInfo.make(mCp, interfaceName));
394             mInterfaceSet.add(interfaceName);
395         }
396     }
397     
398     /**
399      * Add an interface that this class implements.
400      */

401     public void addInterface(Class JavaDoc i) {
402         addInterface(i.getName());
403     }
404     
405     /**
406      * Add a field to this class.
407      */

408     public FieldInfo addField(AccessFlags flags,
409                               String JavaDoc fieldName,
410                               TypeDescriptor type) {
411         FieldInfo fi = new FieldInfo(this, flags, fieldName, type);
412         mFields.add(fi);
413         return fi;
414     }
415     
416     /**
417      * Add a method to this class.
418      *
419      * @param ret Is null if method returns void.
420      * @param params May be null if method accepts no parameters.
421      */

422     public MethodInfo addMethod(AccessFlags flags,
423                                 String JavaDoc methodName,
424                                 TypeDescriptor ret,
425                                 TypeDescriptor[] params) {
426         MethodDescriptor md = new MethodDescriptor(ret, params);
427         return addMethod(flags, methodName, md);
428     }
429
430     /**
431      * Add a method to this class.
432      */

433     public MethodInfo addMethod(AccessFlags flags,
434                                 String JavaDoc methodName,
435                                 MethodDescriptor md) {
436         MethodInfo mi = new MethodInfo(this, flags, methodName, md);
437         mMethods.add(mi);
438         return mi;
439     }
440
441     /**
442      * Add a method to this class. This method is handy for implementing
443      * methods defined by a pre-existing interface.
444      */

445     public MethodInfo addMethod(Method method) {
446         AccessFlags flags = new AccessFlags(method.getModifiers());
447         flags.setAbstract(false);
448
449         TypeDescriptor ret = new TypeDescriptor(method.getReturnType());
450
451         Class JavaDoc[] paramClasses = method.getParameterTypes();
452         TypeDescriptor[] params = new TypeDescriptor[paramClasses.length];
453         for (int i=0; i<params.length; i++) {
454             params[i] = new TypeDescriptor(paramClasses[i]);
455         }
456
457         MethodInfo mi = addMethod(flags, method.getName(), ret, params);
458         
459         // exception stuff...
460
Class JavaDoc[] exceptions = method.getExceptionTypes();
461         for (int i=0; i<exceptions.length; i++) {
462             mi.addException(exceptions[i].getName());
463         }
464
465         return mi;
466     }
467
468     /**
469      * Add a constructor to this class.
470      *
471      * @param params May be null if constructor accepts no parameters.
472      */

473     public MethodInfo addConstructor(AccessFlags flags,
474                                      TypeDescriptor[] params) {
475         MethodDescriptor md = new MethodDescriptor(null, params);
476         MethodInfo mi = new MethodInfo(this, flags, "<init>", md);
477         mMethods.add(mi);
478         return mi;
479     }
480
481     /**
482      * Add a static initializer to this class.
483      */

484     public MethodInfo addInitializer() {
485         MethodDescriptor md = new MethodDescriptor(null, null);
486         AccessFlags af = new AccessFlags();
487         af.setStatic(true);
488         MethodInfo mi = new MethodInfo(this, af, "<clinit>", md);
489         mMethods.add(mi);
490         return mi;
491     }
492
493     /**
494      * Add an inner class to this class. By default, inner classes are private
495      * static.
496      *
497      * @param innerClassName Optional short inner class name.
498      */

499     public ClassFile addInnerClass(String JavaDoc innerClassName) {
500         return addInnerClass(innerClassName, (String JavaDoc)null);
501     }
502
503     /**
504      * Add an inner class to this class. By default, inner classes are private
505      * static.
506      *
507      * @param innerClassName Optional short inner class name.
508      * @param superClass Super class.
509      */

510     public ClassFile addInnerClass(String JavaDoc innerClassName, Class JavaDoc superClass) {
511         return addInnerClass(innerClassName, superClass.getName());
512     }
513
514     /**
515      * Add an inner class to this class. By default, inner classes are private
516      * static.
517      *
518      * @param innerClassName Optional short inner class name.
519      * @param superClassName Full super class name.
520      * @param isStatic True specifies a static inner class.
521      */

522     public ClassFile addInnerClass(String JavaDoc innerClassName,
523                                    String JavaDoc superClassName) {
524         String JavaDoc fullInnerClassName;
525         if (innerClassName == null) {
526             fullInnerClassName =
527                 mClassName + '$' + (++mAnonymousInnerClassCount);
528         }
529         else {
530             fullInnerClassName = mClassName + '$' + innerClassName;
531         }
532
533         ClassFile inner = new ClassFile(fullInnerClassName, superClassName);
534         AccessFlags access = inner.getAccessFlags();
535         access.setPrivate(true);
536         access.setStatic(true);
537         inner.mInnerClassName = innerClassName;
538         inner.mOuterClass = this;
539
540         if (mInnerClasses == null) {
541             mInnerClasses = new ArrayList JavaDoc();
542         }
543
544         mInnerClasses.add(inner);
545         
546         // Record the inner class in this, the outer class.
547
if (mInnerClassesAttr == null) {
548             addAttribute(new InnerClassesAttr(mCp));
549         }
550
551         mInnerClassesAttr.addInnerClass(fullInnerClassName, mClassName,
552                                         innerClassName, access);
553
554         // Record the inner class in itself.
555
inner.addAttribute(new InnerClassesAttr(inner.getConstantPool()));
556         inner.mInnerClassesAttr.addInnerClass(fullInnerClassName, mClassName,
557                                               innerClassName, access);
558
559         return inner;
560     }
561
562     /**
563      * Set the source file of this class file by adding a source file
564      * attribute. The source doesn't actually have to be a file,
565      * but the virtual machine spec names the attribute "SourceFile_attribute".
566      */

567     public void setSourceFile(String JavaDoc fileName) {
568         addAttribute(new SourceFileAttr(mCp, fileName));
569     }
570
571     /**
572      * Mark this class as being synthetic by adding a special attribute.
573      */

574     public void markSynthetic() {
575         addAttribute(new SyntheticAttr(mCp));
576     }
577
578     /**
579      * Mark this class as being deprecated by adding a special attribute.
580      */

581     public void markDeprecated() {
582         addAttribute(new DeprecatedAttr(mCp));
583     }
584
585     /**
586      * Add an attribute to this class.
587      */

588     public void addAttribute(Attribute attr) {
589         if (attr instanceof SourceFileAttr) {
590             if (mSource != null) {
591                 mAttributes.remove(mSource);
592             }
593             mSource = (SourceFileAttr)attr;
594         }
595         else if (attr instanceof InnerClassesAttr) {
596             if (mInnerClassesAttr != null) {
597                 mAttributes.remove(mInnerClassesAttr);
598             }
599             mInnerClassesAttr = (InnerClassesAttr)attr;
600         }
601
602         mAttributes.add(attr);
603     }
604
605     public Attribute[] getAttributes() {
606         Attribute[] attrs = new Attribute[mAttributes.size()];
607         return (Attribute[])mAttributes.toArray(attrs);
608     }
609
610     /**
611      * Sets the version to use when writing the generated ClassFile. Currently,
612      * only version 45, 3 is supported, and is set by default.
613      *
614      * @exception IllegalArgumentException when the version isn't supported
615      */

616     public void setVersion(int major, int minor)
617         throws IllegalArgumentException JavaDoc {
618
619         if (major != JDK1_1_MAJOR_VERSION ||
620             minor != JDK1_1_MINOR_VERSION) {
621
622             throw new IllegalArgumentException JavaDoc("Version " + major + ", " +
623                                                minor + " is not supported");
624         }
625
626         mMajorVersion = major;
627         mMinorVersion = minor;
628     }
629
630     /**
631      * Writes the ClassFile to the given OutputStream. When finished, the
632      * stream is flushed, but not closed.
633      */

634     public void writeTo(OutputStream out) throws IOException {
635         if (!(out instanceof DataOutput)) {
636             out = new DataOutputStream(out);
637         }
638
639         writeTo((DataOutput)out);
640         
641         out.flush();
642     }
643
644     /**
645      * Writes the ClassFile to the given DataOutput.
646      */

647     public void writeTo(DataOutput dout) throws IOException {
648         dout.writeInt(MAGIC);
649         dout.writeShort(mMinorVersion);
650         dout.writeShort(mMajorVersion);
651         
652         mCp.writeTo(dout);
653         
654         int modifier = mAccessFlags.getModifier();
655         dout.writeShort(modifier | Modifier.SYNCHRONIZED);
656
657         dout.writeShort(mThisClass.getIndex());
658         if (mSuperClass != null) {
659             dout.writeShort(mSuperClass.getIndex());
660         }
661         else {
662             dout.writeShort(0);
663         }
664         
665         int size = mInterfaces.size();
666         if (size > 65535) {
667             throw new RuntimeException JavaDoc
668                 ("Interfaces count cannot exceed 65535: " + size);
669         }
670         dout.writeShort(size);
671         for (int i=0; i<size; i++) {
672             int index = ((ConstantInfo)mInterfaces.get(i)).getIndex();
673             dout.writeShort(index);
674         }
675         
676         size = mFields.size();
677         if (size > 65535) {
678             throw new RuntimeException JavaDoc
679                 ("Field count cannot exceed 65535: " + size);
680         }
681         dout.writeShort(size);
682         for (int i=0; i<size; i++) {
683             FieldInfo field = (FieldInfo)mFields.get(i);
684             field.writeTo(dout);
685         }
686         
687         size = mMethods.size();
688         if (size > 65535) {
689             throw new RuntimeException JavaDoc
690                 ("Method count cannot exceed 65535: " + size);
691         }
692         dout.writeShort(size);
693         for (int i=0; i<size; i++) {
694             MethodInfo method = (MethodInfo)mMethods.get(i);
695             method.writeTo(dout);
696         }
697         
698         size = mAttributes.size();
699         if (size > 65535) {
700             throw new RuntimeException JavaDoc
701                 ("Attribute count cannot exceed 65535: " + size);
702         }
703         dout.writeShort(size);
704         for (int i=0; i<size; i++) {
705             Attribute attr = (Attribute)mAttributes.get(i);
706             attr.writeTo(dout);
707         }
708     }
709
710     /**
711      * Reads a ClassFile from the given InputStream. With this method, inner
712      * classes cannot be loaded, and custom attributes cannot be defined.
713      *
714      * @param in source of class file data
715      * @throws IOException for I/O error or if classfile is invalid.
716      * @throws ArrayIndexOutOfBoundsException if a constant pool index is out
717      * of range.
718      * @throws ClassCastException if a constant pool index references the
719      * wrong type.
720      */

721     public static ClassFile readFrom(InputStream in) throws IOException {
722         return readFrom(in, null, null);
723     }
724
725     /**
726      * Reads a ClassFile from the given DataInput. With this method, inner
727      * classes cannot be loaded, and custom attributes cannot be defined.
728      *
729      * @param din source of class file data
730      * @throws IOException for I/O error or if classfile is invalid.
731      * @throws ArrayIndexOutOfBoundsException if a constant pool index is out
732      * of range.
733      * @throws ClassCastException if a constant pool index references the
734      * wrong type.
735      */

736     public static ClassFile readFrom(DataInput din) throws IOException {
737         return readFrom(din, null, null);
738     }
739
740     /**
741      * Reads a ClassFile from the given InputStream. A
742      * {@link ClassFileDataLoader} may be provided, which allows inner class
743      * definitions to be loaded. Also, an {@link AttributeFactory} may be
744      * provided, which allows non-standard attributes to be read. All
745      * remaining unknown attribute types are captured, but are not decoded.
746      *
747      * @param in source of class file data
748      * @param loader optional loader for reading inner class definitions
749      * @param attrFactory optional factory for reading custom attributes
750      * @throws IOException for I/O error or if classfile is invalid.
751      * @throws ArrayIndexOutOfBoundsException if a constant pool index is out
752      * of range.
753      * @throws ClassCastException if a constant pool index references the
754      * wrong type.
755      */

756     public static ClassFile readFrom(InputStream in,
757                                      ClassFileDataLoader loader,
758                                      AttributeFactory attrFactory)
759         throws IOException
760     {
761         if (!(in instanceof DataInput)) {
762             in = new DataInputStream(in);
763         }
764         return readFrom((DataInput)in, loader, attrFactory);
765     }
766
767     /**
768      * Reads a ClassFile from the given DataInput. A
769      * {@link ClassFileDataLoader} may be provided, which allows inner class
770      * definitions to be loaded. Also, an {@link AttributeFactory} may be
771      * provided, which allows non-standard attributes to be read. All
772      * remaining unknown attribute types are captured, but are not decoded.
773      *
774      * @param din source of class file data
775      * @param loader optional loader for reading inner class definitions
776      * @param attrFactory optional factory for reading custom attributes
777      * @throws IOException for I/O error or if classfile is invalid.
778      * @throws ArrayIndexOutOfBoundsException if a constant pool index is out
779      * of range.
780      * @throws ClassCastException if a constant pool index references the
781      * wrong type.
782      */

783     public static ClassFile readFrom(DataInput din,
784                                      ClassFileDataLoader loader,
785                                      AttributeFactory attrFactory)
786         throws IOException
787     {
788         return readFrom(din, loader, attrFactory, new HashMap JavaDoc(11), null);
789     }
790
791     /**
792      * @param loadedClassFiles Maps name to ClassFiles for classes already
793      * loaded. This prevents infinite loop: inner loads outer loads inner...
794      */

795     private static ClassFile readFrom(DataInput din,
796                                       ClassFileDataLoader loader,
797                                       AttributeFactory attrFactory,
798                                       Map JavaDoc loadedClassFiles,
799                                       ClassFile outerClass)
800         throws IOException
801     {
802         int magic = din.readInt();
803         if (magic != MAGIC) {
804             throw new IOException("Incorrect magic number: 0x" +
805                                   Integer.toHexString(magic));
806         }
807
808         int minor = din.readUnsignedShort();
809         /*
810         if (minor != JDK1_1_MINOR_VERSION) {
811             throw new IOException("Minor version " + minor +
812                                   " not supported, version " +
813                                   JDK1_1_MINOR_VERSION + " is.");
814         }
815         */

816
817         int major = din.readUnsignedShort();
818         /*
819         if (major != JDK1_1_MAJOR_VERSION) {
820             throw new IOException("Major version " + major +
821                                   "not supported, version " +
822                                   JDK1_1_MAJOR_VERSION + " is.");
823         }
824         */

825
826         ConstantPool cp = ConstantPool.readFrom(din);
827         AccessFlags accessFlags = new AccessFlags(din.readUnsignedShort());
828         accessFlags.setSynchronized(false);
829
830         int index = din.readUnsignedShort();
831         ConstantClassInfo thisClass = (ConstantClassInfo)cp.getConstant(index);
832
833         index = din.readUnsignedShort();
834         ConstantClassInfo superClass = null;
835         if (index > 0) {
836             superClass = (ConstantClassInfo)cp.getConstant(index);
837         }
838
839         ClassFile cf =
840             new ClassFile(cp, accessFlags, thisClass, superClass, outerClass);
841         loadedClassFiles.put(cf.getClassName(), cf);
842
843         // Read interfaces.
844
int size = din.readUnsignedShort();
845         for (int i=0; i<size; i++) {
846             index = din.readUnsignedShort();
847             ConstantClassInfo info = (ConstantClassInfo)cp.getConstant(index);
848             cf.addInterface(info.getClassName());
849         }
850         
851         // Read fields.
852
size = din.readUnsignedShort();
853         for (int i=0; i<size; i++) {
854             cf.mFields.add(FieldInfo.readFrom(cf, din, attrFactory));
855         }
856         
857         // Read methods.
858
size = din.readUnsignedShort();
859         for (int i=0; i<size; i++) {
860             cf.mMethods.add(MethodInfo.readFrom(cf, din, attrFactory));
861         }
862
863         // Read attributes.
864
size = din.readUnsignedShort();
865         for (int i=0; i<size; i++) {
866             Attribute attr = Attribute.readFrom(cp, din, attrFactory);
867             cf.addAttribute(attr);
868             if (attr instanceof InnerClassesAttr) {
869                 cf.mInnerClassesAttr = (InnerClassesAttr)attr;
870             }
871         }
872
873         // Load inner and outer classes.
874
if (cf.mInnerClassesAttr != null && loader != null) {
875             InnerClassesAttr.Info[] infos =
876                 cf.mInnerClassesAttr.getInnerClassesInfo();
877             for (int i=0; i<infos.length; i++) {
878                 InnerClassesAttr.Info info = infos[i];
879
880                 if (thisClass.equals(info.getInnerClass())) {
881                     // This class is an inner class.
882
if (info.getInnerClassName() != null) {
883                         cf.mInnerClassName = info.getInnerClassName();
884                     }
885                     ConstantClassInfo outer = info.getOuterClass();
886                     if (cf.mOuterClass == null && outer != null) {
887                         cf.mOuterClass = readOuterClass
888                             (outer, loader, attrFactory, loadedClassFiles);
889                     }
890                     AccessFlags innerFlags = info.getAccessFlags();
891                     accessFlags.setStatic(innerFlags.isStatic());
892                     accessFlags.setPrivate(innerFlags.isPrivate());
893                     accessFlags.setProtected(innerFlags.isProtected());
894                     accessFlags.setPublic(innerFlags.isPublic());
895                 }
896                 else if (thisClass.equals(info.getOuterClass())) {
897                     // This class is an outer class.
898
ConstantClassInfo inner = info.getInnerClass();
899                     if (inner != null) {
900                         ClassFile innerClass = readInnerClass
901                             (inner, loader, attrFactory, loadedClassFiles, cf);
902                         
903                         if (innerClass != null) {
904                             if (innerClass.getInnerClassName() == null) {
905                                 innerClass.mInnerClassName =
906                                     info.getInnerClassName();
907                             }
908                             if (cf.mInnerClasses == null) {
909                                 cf.mInnerClasses = new ArrayList JavaDoc();
910                             }
911                             cf.mInnerClasses.add(innerClass);
912                         }
913                     }
914                 }
915             }
916         }
917
918         return cf;
919     }
920
921     private static ClassFile readOuterClass(ConstantClassInfo outer,
922                                             ClassFileDataLoader loader,
923                                             AttributeFactory attrFactory,
924                                             Map JavaDoc loadedClassFiles)
925         throws IOException
926     {
927         String JavaDoc name = outer.getClassName();
928
929         ClassFile outerClass = (ClassFile)loadedClassFiles.get(name);
930         if (outerClass != null) {
931             return outerClass;
932         }
933
934         InputStream in = loader.getClassData(name);
935         if (in == null) {
936             return null;
937         }
938
939         if (!(in instanceof DataInput)) {
940             in = new DataInputStream(in);
941         }
942
943         return readFrom
944             ((DataInput)in, loader, attrFactory, loadedClassFiles, null);
945     }
946
947     private static ClassFile readInnerClass(ConstantClassInfo inner,
948                                             ClassFileDataLoader loader,
949                                             AttributeFactory attrFactory,
950                                             Map JavaDoc loadedClassFiles,
951                                             ClassFile outerClass)
952         throws IOException
953     {
954         String JavaDoc name = inner.getClassName();
955
956         ClassFile innerClass = (ClassFile)loadedClassFiles.get(name);
957         if (innerClass != null) {
958             return innerClass;
959         }
960
961         InputStream in = loader.getClassData(name);
962         if (in == null) {
963             return null;
964         }
965
966         if (!(in instanceof DataInput)) {
967             in = new DataInputStream(in);
968         }
969
970         return readFrom
971             ((DataInput)in, loader, attrFactory, loadedClassFiles, outerClass);
972     }
973 }
974
Popular Tags