ClassParserpublic 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. |
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.
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.
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
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.JavaClass | parse()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).
/****************** 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 void | readAttributes()Read information about the attributes of the attributes of the class.
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 void | readClassInfo()Read information about the class and its super class.
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 void | readConstantPool()Read constant pool entries.
constant_pool = new ConstantPool(file);
| private final void | readFields()Read information about the fields of the class, i.e., its variables.
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 void | readID()Check whether the header of the file is ok.
Of course, this has to be the first action on successive file reads.
int magic = 0xCAFEBABE;
if(file.readInt() != magic)
throw new ClassFormatError(file_name + " is not a Java .class file");
| private final void | readInterfaces()Read information about the interfaces implemented by this class.
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 void | readMethods()Read information about the methods of the class.
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 void | readVersion()Read major and minor version of compiler which created the file.
minor = file.readUnsignedShort();
major = file.readUnsignedShort();
|
|