FileDocCategorySizeDatePackage
ClassParser.javaAPI DocJava SE 5 API11544Fri Aug 26 14:55:16 BST 2005com.sun.org.apache.bcel.internal.classfile

ClassParser

public final class ClassParser extends Object
Wrapper class that parses a given Java .class file. The method parse returns a JavaClass object on success. When an I/O error or an inconsistency occurs an appropiate exception is propagated back to the caller. The structure and the names comply, except for a few conveniences, exactly with the JVM specification 1.0. See this paper for further details about the structure of a bytecode file.
version
$Id: ClassParser.java,v 1.1.1.1 2001/10/29 19:59:57 jvanzyl Exp $
author
M. Dahm

Fields Summary
private DataInputStream
file
private ZipFile
zip
private String
file_name
private int
class_name_index
private int
superclass_name_index
private int
major
private int
minor
private int
access_flags
private int[]
interfaces
private ConstantPool
constant_pool
private Field[]
fields
private Method[]
methods
private Attribute[]
attributes
private boolean
is_zip
private static final int
BUFSIZE
Constructors Summary
public ClassParser(InputStream file, String file_name)
Parse class from the given stream.

param
file Input stream
param
file_name File name


                   
       
    this.file_name = file_name;

    String clazz = file.getClass().getName(); // Not a very clean solution ...
    is_zip = clazz.startsWith("java.util.zip.") || clazz.startsWith("java.util.jar.");

    if(file instanceof DataInputStream) // Is already a data stream
      this.file = (DataInputStream)file;
    else
      this.file = new DataInputStream(new BufferedInputStream(file, BUFSIZE));
  
public ClassParser(String file_name)
Parse class from given .class file.

param
file_name file name
throw
IOException

    
    is_zip = false;
    this.file_name = file_name;
    file = new DataInputStream(new BufferedInputStream
			       (new FileInputStream(file_name), BUFSIZE));
  
public ClassParser(String zip_file, String file_name)
Parse class from given .class file in a ZIP-archive

param
file_name file name
throw
IOException

    
    is_zip = true;
    zip = new ZipFile(zip_file);
    ZipEntry entry = zip.getEntry(file_name);
  		   
    this.file_name = file_name;

    file = new DataInputStream(new BufferedInputStream(zip.getInputStream(entry),
						       BUFSIZE));
  
Methods Summary
public com.sun.org.apache.bcel.internal.classfile.JavaClassparse()
Parse the given Java class file and return an object that represents the contained data, i.e., constants, methods, fields and commands. A ClassFormatError is raised, if the file is not a valid .class file. (This does not include verification of the byte code as it is performed by the java interpreter).

return
Class object representing the parsed class file
throw
IOException
throw
ClassFormatError

    /****************** Read headers ********************************/
    // Check magic tag of class file
    readID();

    // Get compiler version
    readVersion();

    /****************** Read constant pool and related **************/
    // Read constant pool entries
    readConstantPool();
	
    // Get class information
    readClassInfo();

    // Get interface information, i.e., implemented interfaces
    readInterfaces();

    /****************** Read class fields and methods ***************/ 
    // Read class fields, i.e., the variables of the class
    readFields();

    // Read class methods, i.e., the functions in the class
    readMethods();

    // Read class attributes
    readAttributes();

    // Check for unknown variables
    //Unknown[] u = Unknown.getUnknownAttributes();
    //for(int i=0; i < u.length; i++)
    //  System.err.println("WARNING: " + u[i]);

    // Everything should have been read now
    //      if(file.available() > 0) {
    //        int bytes = file.available();
    //        byte[] buf = new byte[bytes];
    //        file.read(buf);
    
    //        if(!(is_zip && (buf.length == 1))) {
    //  	System.err.println("WARNING: Trailing garbage at end of " + file_name);
    //  	System.err.println(bytes + " extra bytes: " + Utility.toHexString(buf));
    //        }
    //      }

    // Read everything of interest, so close the file
    file.close();
    if(zip != null)
      zip.close();

    // Return the information we have gathered in a new object
    return new JavaClass(class_name_index, superclass_name_index, 
			 file_name, major, minor, access_flags,
			 constant_pool, interfaces, fields,
			 methods, attributes, is_zip? JavaClass.ZIP : JavaClass.FILE);
  
private final voidreadAttributes()
Read information about the attributes of the attributes of the class.

throw
IOException
throw
ClassFormatError

    int attributes_count;

    attributes_count = file.readUnsignedShort();
    attributes       = new Attribute[attributes_count];

    for(int i=0; i < attributes_count; i++)
      attributes[i] = Attribute.readAttribute(file, constant_pool);
  
private final voidreadClassInfo()
Read information about the class and its super class.

throw
IOException
throw
ClassFormatError

    access_flags = file.readUnsignedShort();

    /* Interfaces are implicitely abstract, the flag should be set
     * according to the JVM specification.
     */
    if((access_flags & Constants.ACC_INTERFACE) != 0)
      access_flags |= Constants.ACC_ABSTRACT;

    if(((access_flags & Constants.ACC_ABSTRACT) != 0) && 
       ((access_flags & Constants.ACC_FINAL)    != 0 ))
      throw new ClassFormatError("Class can't be both final and abstract");

    class_name_index      = file.readUnsignedShort();
    superclass_name_index = file.readUnsignedShort();
  
private final voidreadConstantPool()
Read constant pool entries.

throw
IOException
throw
ClassFormatError

    constant_pool = new ConstantPool(file);
  
private final voidreadFields()
Read information about the fields of the class, i.e., its variables.

throw
IOException
throw
ClassFormatError

    int fields_count;

    fields_count = file.readUnsignedShort();
    fields       = new Field[fields_count];

    for(int i=0; i < fields_count; i++)
      fields[i] = new Field(file, constant_pool);
  
private final voidreadID()
Check whether the header of the file is ok. Of course, this has to be the first action on successive file reads.

throw
IOException
throw
ClassFormatError

    int magic = 0xCAFEBABE;

    if(file.readInt() != magic)
      throw new ClassFormatError(file_name + " is not a Java .class file");
  
private final voidreadInterfaces()
Read information about the interfaces implemented by this class.

throw
IOException
throw
ClassFormatError

    int interfaces_count;

    interfaces_count = file.readUnsignedShort();
    interfaces       = new int[interfaces_count];

    for(int i=0; i < interfaces_count; i++)
      interfaces[i] = file.readUnsignedShort();
  
private final voidreadMethods()
Read information about the methods of the class.

throw
IOException
throw
ClassFormatError

    int methods_count;

    methods_count = file.readUnsignedShort();
    methods       = new Method[methods_count];

    for(int i=0; i < methods_count; i++)
      methods[i] = new Method(file, constant_pool);
  
private final voidreadVersion()
Read major and minor version of compiler which created the file.

throw
IOException
throw
ClassFormatError

    minor = file.readUnsignedShort();
    major = file.readUnsignedShort();