/*
 * reserved comment block
 * DO NOT REMOVE OR ALTER!
 */
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.sun.org.apache.bcel.internal.classfile;


import  com.sun.org.apache.bcel.internal.Constants;
import  com.sun.org.apache.bcel.internal.util.SyntheticRepository;
import  com.sun.org.apache.bcel.internal.util.ClassVector;
import  com.sun.org.apache.bcel.internal.util.ClassQueue;
import  com.sun.org.apache.bcel.internal.generic.Type;
import com.sun.org.apache.xalan.internal.utils.SecuritySupport;

import  java.io.*;
import  java.util.StringTokenizer;

Represents a Java class, i.e., the data structures, constant pool, fields, methods and commands contained in a Java .class file. See JVM specification for details. The intent of this class is to represent a parsed or otherwise existing class file. Those interested in programatically generating classes should see the ClassGen class.
Author: M. Dahm
See Also:
  • ClassGen
/** * Represents a Java class, i.e., the data structures, constant pool, * fields, methods and commands contained in a Java .class file. * See <a href="ftp://java.sun.com/docs/specs/">JVM * specification</a> for details. * The intent of this class is to represent a parsed or otherwise existing * class file. Those interested in programatically generating classes * should see the <a href="../generic/ClassGen.html">ClassGen</a> class. * @see com.sun.org.apache.bcel.internal.generic.ClassGen * @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A> */
public class JavaClass extends AccessFlags implements Cloneable, Node { private String file_name; private String package_name; private String source_file_name = "<Unknown>"; private int class_name_index; private int superclass_name_index; private String class_name; private String superclass_name; private int major, minor; // Compiler version private ConstantPool constant_pool; // Constant pool private int[] interfaces; // implemented interfaces private String[] interface_names; private Field[] fields; // Fields, i.e., variables of class private Method[] methods; // methods defined in the class private Attribute[] attributes; // attributes defined in the class private byte source = HEAP; // Generated in memory public static final byte HEAP = 1; public static final byte FILE = 2; public static final byte ZIP = 3; static boolean debug = false; // Debugging on/off static char sep = '/'; // directory separator
In cases where we go ahead and create something, use the default SyntheticRepository, because we don't know any better.
/** * In cases where we go ahead and create something, * use the default SyntheticRepository, because we * don't know any better. */
private transient com.sun.org.apache.bcel.internal.util.Repository repository = SyntheticRepository.getInstance();
Constructor gets all contents as arguments.
Params:
  • class_name_index – Index into constant pool referencing a ConstantClass that represents this class.
  • superclass_name_index – Index into constant pool referencing a ConstantClass that represents this class's superclass.
  • file_name – File name
  • major – Major compiler version
  • minor – Minor compiler version
  • access_flags – Access rights defined by bit flags
  • constant_pool – Array of constants
  • interfaces – Implemented interfaces
  • fields – Class fields
  • methods – Class methods
  • attributes – Class attributes
  • source – Read from file or generated in memory?
/** * Constructor gets all contents as arguments. * * @param class_name_index Index into constant pool referencing a * ConstantClass that represents this class. * @param superclass_name_index Index into constant pool referencing a * ConstantClass that represents this class's superclass. * @param file_name File name * @param major Major compiler version * @param minor Minor compiler version * @param access_flags Access rights defined by bit flags * @param constant_pool Array of constants * @param interfaces Implemented interfaces * @param fields Class fields * @param methods Class methods * @param attributes Class attributes * @param source Read from file or generated in memory? */
public JavaClass(int class_name_index, int superclass_name_index, String file_name, int major, int minor, int access_flags, ConstantPool constant_pool, int[] interfaces, Field[] fields, Method[] methods, Attribute[] attributes, byte source) { if(interfaces == null) // Allowed for backward compatibility interfaces = new int[0]; if(attributes == null) this.attributes = new Attribute[0]; if(fields == null) fields = new Field[0]; if(methods == null) methods = new Method[0]; this.class_name_index = class_name_index; this.superclass_name_index = superclass_name_index; this.file_name = file_name; this.major = major; this.minor = minor; this.access_flags = access_flags; this.constant_pool = constant_pool; this.interfaces = interfaces; this.fields = fields; this.methods = methods; this.attributes = attributes; this.source = source; // Get source file name if available for(int i=0; i < attributes.length; i++) { if(attributes[i] instanceof SourceFile) { source_file_name = ((SourceFile)attributes[i]).getSourceFileName(); break; } } /* According to the specification the following entries must be of type * `ConstantClass' but we check that anyway via the * `ConstPool.getConstant' method. */ class_name = constant_pool.getConstantString(class_name_index, Constants.CONSTANT_Class); class_name = Utility.compactClassName(class_name, false); int index = class_name.lastIndexOf('.'); if(index < 0) package_name = ""; else package_name = class_name.substring(0, index); if(superclass_name_index > 0) { // May be zero -> class is java.lang.Object superclass_name = constant_pool.getConstantString(superclass_name_index, Constants.CONSTANT_Class); superclass_name = Utility.compactClassName(superclass_name, false); } else superclass_name = "java.lang.Object"; interface_names = new String[interfaces.length]; for(int i=0; i < interfaces.length; i++) { String str = constant_pool.getConstantString(interfaces[i], Constants.CONSTANT_Class); interface_names[i] = Utility.compactClassName(str, false); } }
Constructor gets all contents as arguments.
Params:
  • class_name_index – Class name
  • superclass_name_index – Superclass name
  • file_name – File name
  • major – Major compiler version
  • minor – Minor compiler version
  • access_flags – Access rights defined by bit flags
  • constant_pool – Array of constants
  • interfaces – Implemented interfaces
  • fields – Class fields
  • methods – Class methods
  • attributes – Class attributes
/** * Constructor gets all contents as arguments. * * @param class_name_index Class name * @param superclass_name_index Superclass name * @param file_name File name * @param major Major compiler version * @param minor Minor compiler version * @param access_flags Access rights defined by bit flags * @param constant_pool Array of constants * @param interfaces Implemented interfaces * @param fields Class fields * @param methods Class methods * @param attributes Class attributes */
public JavaClass(int class_name_index, int superclass_name_index, String file_name, int major, int minor, int access_flags, ConstantPool constant_pool, int[] interfaces, Field[] fields, Method[] methods, Attribute[] attributes) { this(class_name_index, superclass_name_index, file_name, major, minor, access_flags, constant_pool, interfaces, fields, methods, attributes, HEAP); }
Called by objects that are traversing the nodes of the tree implicitely defined by the contents of a Java class. I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects.
Params:
  • v – Visitor object
/** * Called by objects that are traversing the nodes of the tree implicitely * defined by the contents of a Java class. I.e., the hierarchy of methods, * fields, attributes, etc. spawns a tree of objects. * * @param v Visitor object */
public void accept(Visitor v) { v.visitJavaClass(this); } /* Print debug information depending on `JavaClass.debug' */ static final void Debug(String str) { if(debug) System.out.println(str); }
Dump class to a file.
Params:
  • file – Output file
Throws:
/** * Dump class to a file. * * @param file Output file * @throws IOException */
public void dump(File file) throws IOException { String parent = file.getParent(); if(parent != null) { File dir = new File(parent); if(dir != null) dir.mkdirs(); } dump(new DataOutputStream(new FileOutputStream(file))); }
Dump class to a file named file_name.
Params:
  • file_name – Output file name
Throws:
/** * Dump class to a file named file_name. * * @param file_name Output file name * @exception IOException */
public void dump(String file_name) throws IOException { dump(new File(file_name)); }
Returns:class in binary format
/** * @return class in binary format */
public byte[] getBytes() { ByteArrayOutputStream s = new ByteArrayOutputStream(); DataOutputStream ds = new DataOutputStream(s); try { dump(ds); } catch(IOException e) { e.printStackTrace(); } finally { try { ds.close(); } catch(IOException e2) { e2.printStackTrace(); } } return s.toByteArray(); }
Dump Java class to output stream in binary format.
Params:
  • file – Output stream
Throws:
/** * Dump Java class to output stream in binary format. * * @param file Output stream * @exception IOException */
public void dump(OutputStream file) throws IOException { dump(new DataOutputStream(file)); }
Dump Java class to output stream in binary format.
Params:
  • file – Output stream
Throws:
/** * Dump Java class to output stream in binary format. * * @param file Output stream * @exception IOException */
public void dump(DataOutputStream file) throws IOException { file.writeInt(0xcafebabe); file.writeShort(minor); file.writeShort(major); constant_pool.dump(file); file.writeShort(access_flags); file.writeShort(class_name_index); file.writeShort(superclass_name_index); file.writeShort(interfaces.length); for(int i=0; i < interfaces.length; i++) file.writeShort(interfaces[i]); file.writeShort(fields.length); for(int i=0; i < fields.length; i++) fields[i].dump(file); file.writeShort(methods.length); for(int i=0; i < methods.length; i++) methods[i].dump(file); if(attributes != null) { file.writeShort(attributes.length); for(int i=0; i < attributes.length; i++) attributes[i].dump(file); } else file.writeShort(0); file.close(); }
Returns:Attributes of the class.
/** * @return Attributes of the class. */
public Attribute[] getAttributes() { return attributes; }
Returns:Class name.
/** * @return Class name. */
public String getClassName() { return class_name; }
Returns:Package name.
/** * @return Package name. */
public String getPackageName() { return package_name; }
Returns:Class name index.
/** * @return Class name index. */
public int getClassNameIndex() { return class_name_index; }
Returns:Constant pool.
/** * @return Constant pool. */
public ConstantPool getConstantPool() { return constant_pool; }
Returns:Fields, i.e., variables of the class. Like the JVM spec mandates for the classfile format, these fields are those specific to this class, and not those of the superclass or superinterfaces.
/** * @return Fields, i.e., variables of the class. Like the JVM spec * mandates for the classfile format, these fields are those specific to * this class, and not those of the superclass or superinterfaces. */
public Field[] getFields() { return fields; }
Returns:File name of class, aka SourceFile attribute value
/** * @return File name of class, aka SourceFile attribute value */
public String getFileName() { return file_name; }
Returns:Names of implemented interfaces.
/** * @return Names of implemented interfaces. */
public String[] getInterfaceNames() { return interface_names; }
Returns:Indices in constant pool of implemented interfaces.
/** * @return Indices in constant pool of implemented interfaces. */
public int[] getInterfaceIndices() { return interfaces; }
Returns:Major number of class file version.
/** * @return Major number of class file version. */
public int getMajor() { return major; }
Returns:Methods of the class.
/** * @return Methods of the class. */
public Method[] getMethods() { return methods; }
Returns:A com.sun.org.apache.bcel.internal.classfile.Method corresponding to java.lang.reflect.Method if any
/** * @return A com.sun.org.apache.bcel.internal.classfile.Method corresponding to * java.lang.reflect.Method if any */
public Method getMethod(java.lang.reflect.Method m) { for(int i = 0; i < methods.length; i++) { Method method = methods[i]; if(m.getName().equals(method.getName()) && (m.getModifiers() == method.getModifiers()) && Type.getSignature(m).equals(method.getSignature())) { return method; } } return null; }
Returns:Minor number of class file version.
/** * @return Minor number of class file version. */
public int getMinor() { return minor; }
Returns:sbsolute path to file where this class was read from
/** * @return sbsolute path to file where this class was read from */
public String getSourceFileName() { return source_file_name; }
Returns:Superclass name.
/** * @return Superclass name. */
public String getSuperclassName() { return superclass_name; }
Returns:Class name index.
/** * @return Class name index. */
public int getSuperclassNameIndex() { return superclass_name_index; } static { // Debugging ... on/off String debug = null, sep = null; try { debug = SecuritySupport.getSystemProperty("JavaClass.debug"); // Get path separator either / or \ usually sep = SecuritySupport.getSystemProperty("file.separator"); } catch (SecurityException e) { // falls through } if(debug != null) JavaClass.debug = new Boolean(debug).booleanValue(); if(sep != null) try { JavaClass.sep = sep.charAt(0); } catch(StringIndexOutOfBoundsException e) {} // Never reached }
Params:
  • attributes – .
/** * @param attributes . */
public void setAttributes(Attribute[] attributes) { this.attributes = attributes; }
Params:
  • class_name – .
/** * @param class_name . */
public void setClassName(String class_name) { this.class_name = class_name; }
Params:
  • class_name_index – .
/** * @param class_name_index . */
public void setClassNameIndex(int class_name_index) { this.class_name_index = class_name_index; }
Params:
  • constant_pool – .
/** * @param constant_pool . */
public void setConstantPool(ConstantPool constant_pool) { this.constant_pool = constant_pool; }
Params:
  • fields – .
/** * @param fields . */
public void setFields(Field[] fields) { this.fields = fields; }
Set File name of class, aka SourceFile attribute value
/** * Set File name of class, aka SourceFile attribute value */
public void setFileName(String file_name) { this.file_name = file_name; }
Params:
  • interface_names – .
/** * @param interface_names . */
public void setInterfaceNames(String[] interface_names) { this.interface_names = interface_names; }
Params:
  • interfaces – .
/** * @param interfaces . */
public void setInterfaces(int[] interfaces) { this.interfaces = interfaces; }
Params:
  • major – .
/** * @param major . */
public void setMajor(int major) { this.major = major; }
Params:
  • methods – .
/** * @param methods . */
public void setMethods(Method[] methods) { this.methods = methods; }
Params:
  • minor – .
/** * @param minor . */
public void setMinor(int minor) { this.minor = minor; }
Set absolute path to file this class was read from.
/** * Set absolute path to file this class was read from. */
public void setSourceFileName(String source_file_name) { this.source_file_name = source_file_name; }
Params:
  • superclass_name – .
/** * @param superclass_name . */
public void setSuperclassName(String superclass_name) { this.superclass_name = superclass_name; }
Params:
  • superclass_name_index – .
/** * @param superclass_name_index . */
public void setSuperclassNameIndex(int superclass_name_index) { this.superclass_name_index = superclass_name_index; }
Returns:String representing class contents.
/** * @return String representing class contents. */
public String toString() { String access = Utility.accessToString(access_flags, true); access = access.equals("")? "" : (access + " "); StringBuffer buf = new StringBuffer(access + Utility.classOrInterface(access_flags) + " " + class_name + " extends " + Utility.compactClassName(superclass_name, false) + '\n'); int size = interfaces.length; if(size > 0) { buf.append("implements\t\t"); for(int i=0; i < size; i++) { buf.append(interface_names[i]); if(i < size - 1) buf.append(", "); } buf.append('\n'); } buf.append("filename\t\t" + file_name + '\n'); buf.append("compiled from\t\t" + source_file_name + '\n'); buf.append("compiler version\t" + major + "." + minor + '\n'); buf.append("access flags\t\t" + access_flags + '\n'); buf.append("constant pool\t\t" + constant_pool.getLength() + " entries\n"); buf.append("ACC_SUPER flag\t\t" + isSuper() + "\n"); if(attributes.length > 0) { buf.append("\nAttribute(s):\n"); for(int i=0; i < attributes.length; i++) buf.append(indent(attributes[i])); } if(fields.length > 0) { buf.append("\n" + fields.length + " fields:\n"); for(int i=0; i < fields.length; i++) buf.append("\t" + fields[i] + '\n'); } if(methods.length > 0) { buf.append("\n" + methods.length + " methods:\n"); for(int i=0; i < methods.length; i++) buf.append("\t" + methods[i] + '\n'); } return buf.toString(); } private static final String indent(Object obj) { StringTokenizer tok = new StringTokenizer(obj.toString(), "\n"); StringBuffer buf = new StringBuffer(); while(tok.hasMoreTokens()) buf.append("\t" + tok.nextToken() + "\n"); return buf.toString(); }
Returns:deep copy of this class
/** * @return deep copy of this class */
public JavaClass copy() { JavaClass c = null; try { c = (JavaClass)clone(); } catch(CloneNotSupportedException e) {} c.constant_pool = constant_pool.copy(); c.interfaces = (int[])interfaces.clone(); c.interface_names = (String[])interface_names.clone(); c.fields = new Field[fields.length]; for(int i=0; i < fields.length; i++) c.fields[i] = fields[i].copy(c.constant_pool); c.methods = new Method[methods.length]; for(int i=0; i < methods.length; i++) c.methods[i] = methods[i].copy(c.constant_pool); c.attributes = new Attribute[attributes.length]; for(int i=0; i < attributes.length; i++) c.attributes[i] = attributes[i].copy(c.constant_pool); return c; } public final boolean isSuper() { return (access_flags & Constants.ACC_SUPER) != 0; } public final boolean isClass() { return (access_flags & Constants.ACC_INTERFACE) == 0; }
Returns:returns either HEAP (generated), FILE, or ZIP
/** @return returns either HEAP (generated), FILE, or ZIP */
public final byte getSource() { return source; } /********************* New repository functionality *********************/
Gets the ClassRepository which holds its definition. By default this is the same as SyntheticRepository.getInstance();
/** * Gets the ClassRepository which holds its definition. By default * this is the same as SyntheticRepository.getInstance(); */
public com.sun.org.apache.bcel.internal.util.Repository getRepository() { return repository; }
Sets the ClassRepository which loaded the JavaClass. Should be called immediately after parsing is done.
/** * Sets the ClassRepository which loaded the JavaClass. * Should be called immediately after parsing is done. */
public void setRepository(com.sun.org.apache.bcel.internal.util.Repository repository) { this.repository = repository; }
Equivalent to runtime "instanceof" operator.
Returns:true if this JavaClass is derived from teh super class
/** Equivalent to runtime "instanceof" operator. * * @return true if this JavaClass is derived from teh super class */
public final boolean instanceOf(JavaClass super_class) { if(this.equals(super_class)) return true; JavaClass[] super_classes = getSuperClasses(); for(int i=0; i < super_classes.length; i++) { if(super_classes[i].equals(super_class)) { return true; } } if(super_class.isInterface()) { return implementationOf(super_class); } return false; }
Returns:true, if clazz is an implementation of interface inter
/** * @return true, if clazz is an implementation of interface inter */
public boolean implementationOf(JavaClass inter) { if(!inter.isInterface()) { throw new IllegalArgumentException(inter.getClassName() + " is no interface"); } if(this.equals(inter)) { return true; } JavaClass[] super_interfaces = getAllInterfaces(); for(int i=0; i < super_interfaces.length; i++) { if(super_interfaces[i].equals(inter)) { return true; } } return false; }
Returns:the superclass for this JavaClass object, or null if this is java.lang.Object
/** * @return the superclass for this JavaClass object, or null if this * is java.lang.Object */
public JavaClass getSuperClass() { if("java.lang.Object".equals(getClassName())) { return null; } try { return repository.loadClass(getSuperclassName()); } catch(ClassNotFoundException e) { System.err.println(e); return null; } }
Returns:list of super classes of this class in ascending order, i.e., java.lang.Object is always the last element
/** * @return list of super classes of this class in ascending order, i.e., * java.lang.Object is always the last element */
public JavaClass[] getSuperClasses() { JavaClass clazz = this; ClassVector vec = new ClassVector(); for(clazz = clazz.getSuperClass(); clazz != null; clazz = clazz.getSuperClass()) { vec.addElement(clazz); } return vec.toArray(); }
Get interfaces directly implemented by this JavaClass.
/** * Get interfaces directly implemented by this JavaClass. */
public JavaClass[] getInterfaces() { String[] interfaces = getInterfaceNames(); JavaClass[] classes = new JavaClass[interfaces.length]; try { for(int i = 0; i < interfaces.length; i++) { classes[i] = repository.loadClass(interfaces[i]); } } catch(ClassNotFoundException e) { System.err.println(e); return null; } return classes; }
Get all interfaces implemented by this JavaClass (transitively).
/** * Get all interfaces implemented by this JavaClass (transitively). */
public JavaClass[] getAllInterfaces() { ClassQueue queue = new ClassQueue(); ClassVector vec = new ClassVector(); queue.enqueue(this); while(!queue.empty()) { JavaClass clazz = queue.dequeue(); JavaClass souper = clazz.getSuperClass(); JavaClass[] interfaces = clazz.getInterfaces(); if(clazz.isInterface()) { vec.addElement(clazz); } else { if(souper != null) { queue.enqueue(souper); } } for(int i = 0; i < interfaces.length; i++) { queue.enqueue(interfaces[i]); } } return vec.toArray(); } }