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

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