Main Page   Packages   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members  

JavaClass.java

00001 package de.fub.bytecode.classfile;
00002 
00003 import  de.fub.bytecode.Constants;
00004 import  de.fub.bytecode.Repository;
00005 import  java.io.*;
00006 import  java.util.StringTokenizer;
00007 
00008 /**
00009  * Represents a Java class, i.e., the data structures, constant pool,
00010  * fields, methods and commands contained in a Java .class file.
00011  * See <a href="ftp://java.sun.com/docs/specs/">JVM 
00012  * specification</a> for details.
00013  *
00014  * @version $Id: JavaClass.java,v 1.1.1.1 2002/01/24 03:41:37 pserver Exp $
00015  * @author  <A HREF="http://www.inf.fu-berlin.de/~dahm">M. Dahm</A>
00016  */
00017 public class JavaClass extends AccessFlags implements Cloneable {
00018   private String       file_name;
00019   private String       package_name;
00020   private String       source_file_name = "<Unknown>";
00021   private int          class_name_index;
00022   private int          superclass_name_index;
00023   private String       class_name;
00024   private String       superclass_name;
00025   private int          major, minor;  // Compiler version
00026   private ConstantPool constant_pool; // Constant pool
00027   private int[]        interfaces;    // implemented interfaces
00028   private String[]     interface_names;
00029   private Field[]      fields;        // Fields, i.e., variables of class
00030   private Method[]     methods;       // methods defined in the class
00031   private Attribute[]  attributes;    // attributes defined in the class
00032   private byte         source = HEAP; // Generated in memory
00033 
00034   public static final byte HEAP = 1;
00035   public static final byte FILE = 2;
00036   public static final byte ZIP  = 3;
00037 
00038   static boolean debug = false; // Debugging on/off
00039   static char    sep   = '/';   // directory separator
00040 
00041   static {
00042     // Debugging ... on/off
00043     String debug = System.getProperty("JavaClass.debug");
00044 
00045     if(debug != null)
00046       JavaClass.debug = new Boolean(debug).booleanValue();
00047 
00048     // Get path separator either / or \ usually
00049     String sep = System.getProperty("file.separator");
00050 
00051     if(sep != null)
00052       try {
00053     JavaClass.sep = sep.charAt(0);
00054     } catch(StringIndexOutOfBoundsException e) {} // Never reached
00055   }
00056 
00057   /**
00058    * Constructor gets all contents as arguments.
00059    *
00060    * @param class_name Class name
00061    * @param superclass_name Superclass name
00062    * @param file_name File name
00063    * @param major Major compiler version
00064    * @param minor Minor compiler version
00065    * @param access_flags Access rights defined by bit flags
00066    * @param constant_pool Array of constants
00067    * @param interfaces Implemented interfaces
00068    * @param fields Class fields
00069    * @param methods Class methods
00070    * @param attributes Class attributes
00071    */
00072   public JavaClass(int        class_name_index,
00073            int        superclass_name_index,
00074            String     file_name,
00075            int        major,
00076            int        minor,
00077            int        access_flags,
00078            ConstantPool constant_pool,
00079            int[]      interfaces,
00080            Field[]      fields,
00081            Method[]     methods,
00082            Attribute[]  attributes) {
00083     this(class_name_index, superclass_name_index, file_name, major, minor, access_flags,
00084      constant_pool, interfaces, fields, methods, attributes, HEAP);
00085   }  
00086   /**
00087    * Constructor gets all contents as arguments.
00088    *
00089    * @param class_name Class name
00090    * @param superclass_name Superclass name
00091    * @param file_name File name
00092    * @param major Major compiler version
00093    * @param minor Minor compiler version
00094    * @param access_flags Access rights defined by bit flags
00095    * @param constant_pool Array of constants
00096    * @param interfaces Implemented interfaces
00097    * @param fields Class fields
00098    * @param methods Class methods
00099    * @param attributes Class attributes
00100    * @param source Read from file or generated in memory?
00101    */
00102   public JavaClass(int        class_name_index,
00103            int        superclass_name_index,
00104            String     file_name,
00105            int        major,
00106            int        minor,
00107            int        access_flags,
00108            ConstantPool constant_pool,
00109            int[]      interfaces,
00110            Field[]      fields,
00111            Method[]     methods,
00112            Attribute[]  attributes,
00113            byte          source)
00114   {
00115     if(interfaces == null) // Allowed for backward compatibility
00116       interfaces = new int[0];
00117     if(attributes == null)
00118       this.attributes = new Attribute[0];
00119     if(fields == null)
00120       fields = new Field[0];
00121     if(methods == null)
00122       methods = new Method[0];
00123 
00124     this.class_name_index      = class_name_index;
00125     this.superclass_name_index = superclass_name_index;
00126     this.file_name             = file_name;
00127     this.major                 = major;
00128     this.minor                 = minor;
00129     this.access_flags          = access_flags;
00130     this.constant_pool         = constant_pool;
00131     this.interfaces            = interfaces;
00132     this.fields                = fields;
00133     this.methods               = methods;
00134     this.attributes            = attributes;
00135     this.source                = source;
00136 
00137     // Get source file name if available
00138     for(int i=0; i < attributes.length; i++) {
00139       if(attributes[i] instanceof SourceFile) {
00140     source_file_name = ((SourceFile)attributes[i]).getSourceFileName();
00141     break;
00142       }
00143     }
00144     
00145     // Get class name and superclass name
00146     ConstantUtf8  name;
00147 
00148     /* According to the specification the following entries must be of type
00149      * `ConstantClass' but we check that anyway via the 
00150      * `ConstPool.getConstant' method.
00151      */
00152     class_name = constant_pool.getConstantString(class_name_index, 
00153                          Constants.CONSTANT_Class);
00154     class_name = Utility.compactClassName(class_name, false);
00155 
00156     int index = class_name.lastIndexOf('.');
00157     if(index < 0)
00158       package_name = "";
00159     else
00160       package_name = class_name.substring(0, index);
00161 
00162     if(superclass_name_index > 0) { // May be zero -> class is java.lang.Object
00163       superclass_name = constant_pool.getConstantString(superclass_name_index,
00164                             Constants.CONSTANT_Class);
00165       superclass_name = Utility.compactClassName(superclass_name, false);
00166     }
00167     else
00168       superclass_name = "java.lang.Object";    
00169 
00170     interface_names = new String[interfaces.length];
00171     for(int i=0; i < interfaces.length; i++) {
00172       String str = constant_pool.getConstantString(interfaces[i], Constants.CONSTANT_Class);
00173       interface_names[i] = Utility.compactClassName(str, false);
00174     }
00175   }  
00176   /**
00177    * Called by objects that are traversing the nodes of the tree implicitely
00178    * defined by the contents of a Java class. I.e., the hierarchy of methods,
00179    * fields, attributes, etc. spawns a tree of objects.
00180    *
00181    * @param v Visitor object
00182    */
00183   public void accept(Visitor v) {
00184     v.visitJavaClass(this);
00185   }  
00186   /**
00187    * @return deep copy of this class
00188    */
00189   public JavaClass copy() {
00190     JavaClass c = null;
00191 
00192     try {
00193       c = (JavaClass)clone();
00194     } catch(CloneNotSupportedException e) {}
00195 
00196     c.constant_pool   = constant_pool.copy();
00197     c.interfaces      = (int[])interfaces.clone();
00198     c.interface_names = (String[])interface_names.clone();
00199 
00200     c.fields = new Field[fields.length];
00201     for(int i=0; i < fields.length; i++)
00202       c.fields[i] = fields[i].copy(c.constant_pool);
00203 
00204     c.methods = new Method[methods.length];
00205     for(int i=0; i < methods.length; i++)
00206       c.methods[i] = methods[i].copy(c.constant_pool);
00207 
00208     c.attributes = new Attribute[attributes.length];
00209     for(int i=0; i < attributes.length; i++)
00210       c.attributes[i] = attributes[i].copy(c.constant_pool);
00211 
00212     return c;
00213   }  
00214   /* Print debug information depending on `JavaClass.debug'
00215    */
00216   static final void Debug(String str) {
00217     if(debug)
00218       System.out.println(str);
00219   }  
00220   /**
00221    * Dump Java class to output stream in binary format.
00222    *
00223    * @param file Output stream
00224    * @exception IOException
00225    */
00226   public void dump(DataOutputStream file) throws IOException
00227   {
00228     file.writeInt(0xcafebabe);
00229     file.writeShort(minor);
00230     file.writeShort(major);
00231 
00232     constant_pool.dump(file);
00233     
00234     file.writeShort(access_flags);
00235     file.writeShort(class_name_index);
00236     file.writeShort(superclass_name_index);
00237 
00238     file.writeShort(interfaces.length);
00239     for(int i=0; i < interfaces.length; i++)
00240       file.writeShort(interfaces[i]);
00241 
00242     file.writeShort(fields.length);
00243     for(int i=0; i < fields.length; i++)
00244       fields[i].dump(file);
00245 
00246     file.writeShort(methods.length);
00247     for(int i=0; i < methods.length; i++)
00248       methods[i].dump(file);
00249 
00250     if(attributes != null) {
00251       file.writeShort(attributes.length);
00252       for(int i=0; i < attributes.length; i++)
00253     attributes[i].dump(file);
00254     }
00255     else
00256       file.writeShort(0);
00257 
00258     file.close();
00259   }  
00260   /** 
00261    * Dump class to a file.
00262    *
00263    * @param file Output file
00264    * @throw IOException
00265    */
00266   public void dump(File file) throws IOException
00267   {
00268     String parent = file.getParent();
00269 
00270     if(parent != null) {
00271       File dir = new File(parent);
00272       
00273       if(dir != null)
00274     dir.mkdirs();
00275     }
00276 
00277     dump(new DataOutputStream(new FileOutputStream(file)));
00278   }  
00279   /**
00280    * Dump Java class to output stream in binary format.
00281    *
00282    * @param file Output stream
00283    * @exception IOException
00284    */
00285   public void dump(OutputStream file) throws IOException {
00286     dump(new DataOutputStream(file));
00287   }  
00288   /** 
00289    * Dump class to a file named file_name.
00290    *
00291    * @param file_name Output file name
00292    * @exception IOException
00293    */
00294   public void dump(String file_name) throws IOException
00295   {
00296     dump(new File(file_name));
00297   }  
00298   /**
00299    * @return Attributes of the class.
00300    */
00301   public Attribute[] getAttributes() { return attributes; }  
00302   /**
00303    * @return class in binary format
00304    */
00305   public byte[] getBytes() {
00306     ByteArrayOutputStream s  = new ByteArrayOutputStream();
00307     DataOutputStream      ds = new DataOutputStream(s);
00308 
00309     try {
00310       dump(ds);
00311       ds.close();
00312     } catch(IOException e) { e.printStackTrace(); }
00313 
00314     return s.toByteArray();
00315   }  
00316   /**
00317    * @return Class name.
00318    */
00319   public String getClassName()       { return class_name; }  
00320   /**
00321    * @return Class name index.
00322    */
00323   public int getClassNameIndex()   { return class_name_index; }  
00324   /**
00325    * @return Constant pool.
00326    */
00327   public ConstantPool getConstantPool() { return constant_pool; }  
00328   /**
00329    * @return Fields, i.e., variables of the class.
00330    */
00331   public Field[] getFields()         { return fields; }  
00332   /**
00333    * @return File name.
00334    */
00335   public String getFileName()        { return file_name; }  
00336   /**
00337    * @return Names of implemented interfaces.
00338    */
00339   public String[] getInterfaceNames()  { return interface_names; }  
00340   /**
00341    * @return Implemented interfaces.
00342    */
00343   public int[] getInterfaces()     { return interfaces; }  
00344   /**
00345    * @return Major number of compiler version.
00346    */
00347   public int  getMajor()           { return major; }  
00348   /**
00349    * @return Methods of the class.
00350    */
00351   public Method[] getMethods()       { return methods; }  
00352   /**
00353    * @return Minor number of compiler version.
00354    */
00355   public int  getMinor()           { return minor; }  
00356   /**
00357    * @return Package name.
00358    */
00359   public String getPackageName()       { return package_name; }  
00360   /** @return returns either HEAP (generated), FILE, or ZIP
00361    */
00362   public final byte getSource() {
00363     return source;
00364   }  
00365   /**
00366    * @return File name of source.
00367    */
00368   public String getSourceFileName()  { return source_file_name; }  
00369   /**
00370    * @return Superclass name.
00371    */
00372   public String getSuperclassName()  { return superclass_name; }  
00373   /**
00374    * @return Class name index.
00375    */
00376   public int getSuperclassNameIndex() { return superclass_name_index; }  
00377   private static final String indent(Object obj) {
00378     StringTokenizer tok = new StringTokenizer(obj.toString(), "\n");
00379     StringBuffer buf = new StringBuffer();
00380 
00381     while(tok.hasMoreTokens())
00382       buf.append("\t" + tok.nextToken() + "\n");
00383 
00384     return buf.toString();
00385   }  
00386   public final boolean instanceOf(JavaClass super_class) {
00387     return Repository.instanceOf(this, super_class);
00388   }  
00389   public final boolean isClass() {
00390     return (access_flags & Constants.ACC_INTERFACE) == 0;
00391   }  
00392   public final boolean isSuper() {
00393     return (access_flags & Constants.ACC_SUPER) != 0;
00394   }  
00395   /**
00396    * @param attributes.
00397    */
00398   public void setAttributes(Attribute[] attributes) {
00399     this.attributes = attributes;
00400   }  
00401   /**
00402    * @param class_name.
00403    */
00404   public void setClassName(String class_name) {
00405     this.class_name = class_name;
00406   }  
00407   /**
00408    * @param class_name_index.
00409    */
00410   public void setClassNameIndex(int class_name_index) {
00411     this.class_name_index = class_name_index;
00412   }  
00413   /**
00414    * @param constant_pool.
00415    */
00416   public void setConstantPool(ConstantPool constant_pool) {
00417     this.constant_pool = constant_pool;
00418   }  
00419   /**
00420    * @param fields.
00421    */
00422   public void setFields(Field[] fields) {
00423     this.fields = fields;
00424   }  
00425   /**
00426    * @param file_name.
00427    */
00428   public void setFileName(String file_name) {
00429     this.file_name = file_name;
00430   }  
00431   /**
00432    * @param interface_names.
00433    */
00434   public void setInterfaceNames(String[] interface_names) {
00435     this.interface_names = interface_names;
00436   }  
00437   /**
00438    * @param interfaces.
00439    */
00440   public void setInterfaces(int[] interfaces) {
00441     this.interfaces = interfaces;
00442   }  
00443   /**
00444    * @param major.
00445    */
00446   public void setMajor(int major) {
00447     this.major = major;
00448   }  
00449   /**
00450    * @param methods.
00451    */
00452   public void setMethods(Method[] methods) {
00453     this.methods = methods;
00454   }  
00455   /**
00456    * @param minor.
00457    */
00458   public void setMinor(int minor) {
00459     this.minor = minor;
00460   }  
00461   /**
00462    * @param source_file_name.
00463    */
00464   public void setSourceFileName(String source_file_name) {
00465     this.source_file_name = source_file_name;
00466   }  
00467   /**
00468    * @param superclass_name.
00469    */
00470   public void setSuperclassName(String superclass_name) {
00471     this.superclass_name = superclass_name;
00472   }  
00473   /**
00474    * @param superclass_name_index.
00475    */
00476   public void setSuperclassNameIndex(int superclass_name_index) {
00477     this.superclass_name_index = superclass_name_index;
00478   }  
00479   /**
00480    * @return String representing class contents.
00481    */
00482   public String toString() {
00483     String access = Utility.accessToString(access_flags, true);
00484     access = access.equals("")? "" : (access + " ");
00485 
00486     StringBuffer buf = new StringBuffer(access +
00487                     Utility.classOrInterface(access_flags) + 
00488                     " " +
00489                     class_name + " extends " +
00490                     Utility.compactClassName(superclass_name,
00491                                  false) + '\n');
00492     int size = interfaces.length;
00493 
00494     if(size > 0) {
00495       buf.append("implements\t\t");
00496 
00497       for(int i=0; i < size; i++) {
00498     buf.append(interface_names[i]);
00499     if(i < size - 1)
00500       buf.append(", ");
00501       }
00502 
00503       buf.append('\n');
00504     }
00505 
00506     buf.append("filename\t\t" + file_name + '\n');
00507     buf.append("compiled from\t\t" + source_file_name + '\n');
00508     buf.append("compiler version\t" + major + "." + minor + '\n');
00509     buf.append("access flags\t\t" + access_flags + '\n');
00510     buf.append("constant pool\t\t" + constant_pool.getLength() + " entries\n");
00511     buf.append("ACC_SUPER flag\t\t" + isSuper() + "\n");
00512 
00513     if(attributes.length > 0) {
00514       buf.append("\nAttribute(s):\n");
00515       for(int i=0; i < attributes.length; i++)
00516     buf.append(indent(attributes[i]));
00517     }
00518 
00519     if(fields.length > 0) {
00520       buf.append("\n" + fields.length + " fields:\n");
00521       for(int i=0; i < fields.length; i++)
00522     buf.append("\t" + fields[i] + '\n');
00523     }
00524 
00525     if(methods.length > 0) {
00526       buf.append("\n" + methods.length + " methods:\n");
00527       for(int i=0; i < methods.length; i++)
00528     buf.append("\t" + methods[i] + '\n');
00529     }
00530 
00531     return buf.toString();
00532   }  
00533 }

Generated at Thu Feb 7 06:48:16 2002 for Bandera by doxygen1.2.10 written by Dimitri van Heesch, © 1997-2001