< prev index next >
src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/JavaClass.java
Print this page
*** 15,82 ****
* 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 <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.
*/
! private transient com.sun.org.apache.bcel.internal.util.Repository repository =
! SyntheticRepository.getInstance();
/**
* Constructor gets all contents as arguments.
*
* @param class_name_index Index into constant pool referencing a
--- 15,103 ----
* 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 java.io.ByteArrayOutputStream;
+ import java.io.DataOutputStream;
+ import java.io.File;
+ import java.io.FileOutputStream;
+ import java.io.IOException;
+ import java.io.OutputStream;
+ import java.util.ArrayList;
+ import java.util.List;
+ import java.util.Set;
+ import java.util.StringTokenizer;
+ import java.util.TreeSet;
! import com.sun.org.apache.bcel.internal.Const;
import com.sun.org.apache.bcel.internal.generic.Type;
! import com.sun.org.apache.bcel.internal.util.BCELComparator;
! import com.sun.org.apache.bcel.internal.util.ClassQueue;
! import com.sun.org.apache.bcel.internal.util.SyntheticRepository;
! import jdk.xml.internal.SecuritySupport;
/**
! * Represents a Java class, i.e., the data structures, constant pool, fields,
! * methods and commands contained in a Java .class file. See <a
! * href="http://docs.oracle.com/javase/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.
! *
! * @version $Id: JavaClass.java 1750227 2016-06-25 21:47:10Z ggregory $
* @see com.sun.org.apache.bcel.internal.generic.ClassGen
*/
! public class JavaClass extends AccessFlags implements Cloneable, Node, Comparable<JavaClass> {
!
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;
! private int 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 AnnotationEntry[] annotations; // annotations defined on the class
private byte source = HEAP; // Generated in memory
! private boolean isAnonymous = false;
! private boolean isNested = false;
! private boolean computedNestedTypeStatus = false;
public static final byte HEAP = 1;
public static final byte FILE = 2;
public static final byte ZIP = 3;
! private static BCELComparator bcelComparator = new BCELComparator() {
!
! @Override
! public boolean equals(final Object o1, final Object o2) {
! final JavaClass THIS = (JavaClass) o1;
! final JavaClass THAT = (JavaClass) o2;
! return THIS.getClassName().equals(THAT.getClassName());
! }
+ @Override
+ public int hashCode(final Object o) {
+ final JavaClass THIS = (JavaClass) o;
+ return THIS.getClassName().hashCode();
+ }
+ };
/**
! * 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.
*
* @param class_name_index Index into constant pool referencing a
*** 92,169 ****
* @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);
}
}
/**
--- 113,180 ----
* @param fields Class fields
* @param methods Class methods
* @param attributes Class attributes
* @param source Read from file or generated in memory?
*/
! public JavaClass(final int class_name_index, final int superclass_name_index,
! final String file_name, final int major, final int minor, final int access_flags,
! final ConstantPool constant_pool, int[] interfaces, Field[] fields,
! Method[] methods, Attribute[] attributes, final byte source) {
! super(access_flags);
! if (interfaces == null) {
interfaces = new int[0];
! }
! if (attributes == null) {
! 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.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 (final Attribute attribute : attributes) {
! if (attribute instanceof SourceFile) {
! source_file_name = ((SourceFile) attribute).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, Const.CONSTANT_Class);
class_name = Utility.compactClassName(class_name, false);
! final 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,
! Const.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++) {
! final String str = constant_pool.getConstantString(interfaces[i], Const.CONSTANT_Class);
interface_names[i] = Utility.compactClassName(str, false);
}
}
/**
*** 179,788 ****
* @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.
*
* @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.
*
* @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.
*
! * @param file_name Output file name
! * @exception IOException
*/
! public void dump(String file_name) throws IOException
! {
! dump(new File(file_name));
}
/**
* @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.
*
* @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.
*
* @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();
}
/**
* @return Attributes of the class.
*/
! public Attribute[] getAttributes() { return attributes; }
/**
* @return Class name.
*/
! public String getClassName() { return class_name; }
/**
* @return Package name.
*/
! public String getPackageName() { return package_name; }
/**
* @return Class name index.
*/
! public int getClassNameIndex() { return class_name_index; }
/**
* @return Constant pool.
*/
! public ConstantPool getConstantPool() { return constant_pool; }
/**
! * @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; }
/**
* @return File name of class, aka SourceFile attribute value
*/
! public String getFileName() { return file_name; }
/**
* @return Names of implemented interfaces.
*/
! public String[] getInterfaceNames() { return interface_names; }
/**
* @return Indices in constant pool of implemented interfaces.
*/
! public int[] getInterfaceIndices() { return interfaces; }
/**
* @return Major number of class file version.
*/
! public int getMajor() { return major; }
/**
* @return Methods of the class.
*/
! public Method[] getMethods() { return methods; }
/**
! * @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;
}
/**
* @return Minor number of class file version.
*/
! public int getMinor() { return minor; }
/**
* @return sbsolute path to file where this class was read from
*/
! public String getSourceFileName() { return source_file_name; }
/**
* @return Superclass name.
*/
! public String getSuperclassName() { return superclass_name; }
/**
* @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 = Boolean.valueOf(debug);
!
! if(sep != null)
! try {
! JavaClass.sep = sep.charAt(0);
! } catch(StringIndexOutOfBoundsException e) {} // Never reached
}
/**
* @param attributes .
*/
! public void setAttributes(Attribute[] attributes) {
this.attributes = attributes;
}
/**
* @param class_name .
*/
! public void setClassName(String class_name) {
this.class_name = class_name;
}
/**
* @param class_name_index .
*/
! public void setClassNameIndex(int class_name_index) {
this.class_name_index = class_name_index;
}
/**
* @param constant_pool .
*/
! public void setConstantPool(ConstantPool constant_pool) {
this.constant_pool = constant_pool;
}
/**
* @param fields .
*/
! public void setFields(Field[] fields) {
this.fields = fields;
}
/**
* Set File name of class, aka SourceFile attribute value
*/
! public void setFileName(String file_name) {
this.file_name = file_name;
}
/**
* @param interface_names .
*/
! public void setInterfaceNames(String[] interface_names) {
this.interface_names = interface_names;
}
/**
* @param interfaces .
*/
! public void setInterfaces(int[] interfaces) {
this.interfaces = interfaces;
}
/**
* @param major .
*/
! public void setMajor(int major) {
this.major = major;
}
/**
* @param methods .
*/
! public void setMethods(Method[] methods) {
this.methods = methods;
}
/**
* @param minor .
*/
! public void setMinor(int minor) {
this.minor = minor;
}
/**
* Set absolute path to file this class was read from.
*/
! public void setSourceFileName(String source_file_name) {
this.source_file_name = source_file_name;
}
/**
* @param superclass_name .
*/
! public void setSuperclassName(String superclass_name) {
this.superclass_name = superclass_name;
}
/**
* @param superclass_name_index .
*/
! public void setSuperclassNameIndex(int superclass_name_index) {
this.superclass_name_index = superclass_name_index;
}
/**
* @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();
}
/**
* @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;
}
! /** @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();
*/
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.
*/
! public void setRepository(com.sun.org.apache.bcel.internal.util.Repository repository) {
this.repository = repository;
}
! /** 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;
}
/**
! * @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;
}
/**
! * @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;
- }
}
/**
* @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.
*/
! 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).
*/
! 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();
}
}
--- 190,871 ----
* @param interfaces Implemented interfaces
* @param fields Class fields
* @param methods Class methods
* @param attributes Class attributes
*/
! public JavaClass(final int class_name_index, final int superclass_name_index,
! final String file_name, final int major, final int minor, final int access_flags,
! final ConstantPool constant_pool, final int[] interfaces, final Field[] fields,
! final Method[] methods, final 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 implicitly
* 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
*/
! @Override
! public void accept(final Visitor v) {
v.visitJavaClass(this);
}
/**
* Dump class to a file.
*
* @param file Output file
* @throws IOException
*/
! public void dump(final File file) throws IOException {
! final String parent = file.getParent();
! if (parent != null) {
! final File dir = new File(parent);
! if (!dir.mkdirs()) { // either was not created or already existed
! if (!SecuritySupport.isDirectory(dir)) {
! throw new IOException("Could not create the directory " + dir);
! }
! }
! }
! try (DataOutputStream dos = new DataOutputStream(new FileOutputStream(file))) {
! dump(dos);
}
}
/**
* Dump class to a file named file_name.
*
! * @param _file_name Output file name
! * @throws IOException
*/
! public void dump(final String _file_name) throws IOException {
! dump(new File(_file_name));
}
/**
* @return class in binary format
*/
public byte[] getBytes() {
! final ByteArrayOutputStream s = new ByteArrayOutputStream();
! final DataOutputStream ds = new DataOutputStream(s);
try {
dump(ds);
! } catch (final IOException e) {
! System.err.println("Error dumping class: " + e.getMessage());
} finally {
! try {
! ds.close();
! } catch (final IOException e2) {
! System.err.println("Error dumping class: " + e2.getMessage());
! }
}
return s.toByteArray();
}
/**
* Dump Java class to output stream in binary format.
*
* @param file Output stream
! * @throws IOException
*/
! public void dump(final OutputStream file) throws IOException {
dump(new DataOutputStream(file));
}
/**
* Dump Java class to output stream in binary format.
*
* @param file Output stream
! * @throws IOException
*/
! public void dump(final DataOutputStream file) throws IOException {
! file.writeInt(Const.JVM_CLASSFILE_MAGIC);
file.writeShort(minor);
file.writeShort(major);
constant_pool.dump(file);
! file.writeShort(super.getAccessFlags());
file.writeShort(class_name_index);
file.writeShort(superclass_name_index);
file.writeShort(interfaces.length);
! for (final int interface1 : interfaces) {
! file.writeShort(interface1);
! }
file.writeShort(fields.length);
! for (final Field field : fields) {
! field.dump(file);
! }
file.writeShort(methods.length);
! for (final Method method : methods) {
! method.dump(file);
! }
! if (attributes != null) {
file.writeShort(attributes.length);
! for (final Attribute attribute : attributes) {
! attribute.dump(file);
}
! } else {
file.writeShort(0);
! }
! file.flush();
}
/**
* @return Attributes of the class.
*/
! public Attribute[] getAttributes() {
! return attributes;
! }
!
! /**
! * @return Annotations on the class
! * @since 6.0
! */
! public AnnotationEntry[] getAnnotationEntries() {
! if (annotations == null) {
! annotations = AnnotationEntry.createAnnotationEntries(getAttributes());
! }
!
! return annotations;
! }
/**
* @return Class name.
*/
! public String getClassName() {
! return class_name;
! }
/**
* @return Package name.
*/
! public String getPackageName() {
! return package_name;
! }
/**
* @return Class name index.
*/
! public int getClassNameIndex() {
! return class_name_index;
! }
/**
* @return Constant pool.
*/
! public ConstantPool getConstantPool() {
! return constant_pool;
! }
/**
! * @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;
! }
/**
* @return File name of class, aka SourceFile attribute value
*/
! public String getFileName() {
! return file_name;
! }
/**
* @return Names of implemented interfaces.
*/
! public String[] getInterfaceNames() {
! return interface_names;
! }
/**
* @return Indices in constant pool of implemented interfaces.
*/
! public int[] getInterfaceIndices() {
! return interfaces;
! }
/**
* @return Major number of class file version.
*/
! public int getMajor() {
! return major;
! }
/**
* @return Methods of the class.
*/
! public Method[] getMethods() {
! return methods;
! }
/**
! * @return A {@link Method} corresponding to java.lang.reflect.Method if any
*/
! public Method getMethod(final java.lang.reflect.Method m) {
! for (final Method method : methods) {
! if (m.getName().equals(method.getName()) && (m.getModifiers() == method.getModifiers())
! && Type.getSignature(m).equals(method.getSignature())) {
return method;
}
}
return null;
}
/**
* @return Minor number of class file version.
*/
! public int getMinor() {
! return minor;
! }
/**
* @return sbsolute path to file where this class was read from
*/
! public String getSourceFileName() {
! return source_file_name;
! }
/**
+ * returns the super class name of this class. In the case that this class
+ * is java.lang.Object, it will return itself (java.lang.Object). This is
+ * probably incorrect but isn't fixed at this time to not break existing
+ * clients.
+ *
* @return Superclass name.
*/
! public String getSuperclassName() {
! return superclass_name;
! }
/**
* @return Class name index.
*/
! public int getSuperclassNameIndex() {
! return superclass_name_index;
}
/**
* @param attributes .
*/
! public void setAttributes(final Attribute[] attributes) {
this.attributes = attributes;
}
/**
* @param class_name .
*/
! public void setClassName(final String class_name) {
this.class_name = class_name;
}
/**
* @param class_name_index .
*/
! public void setClassNameIndex(final int class_name_index) {
this.class_name_index = class_name_index;
}
/**
* @param constant_pool .
*/
! public void setConstantPool(final ConstantPool constant_pool) {
this.constant_pool = constant_pool;
}
/**
* @param fields .
*/
! public void setFields(final Field[] fields) {
this.fields = fields;
}
/**
* Set File name of class, aka SourceFile attribute value
*/
! public void setFileName(final String file_name) {
this.file_name = file_name;
}
/**
* @param interface_names .
*/
! public void setInterfaceNames(final String[] interface_names) {
this.interface_names = interface_names;
}
/**
* @param interfaces .
*/
! public void setInterfaces(final int[] interfaces) {
this.interfaces = interfaces;
}
/**
* @param major .
*/
! public void setMajor(final int major) {
this.major = major;
}
/**
* @param methods .
*/
! public void setMethods(final Method[] methods) {
this.methods = methods;
}
/**
* @param minor .
*/
! public void setMinor(final int minor) {
this.minor = minor;
}
/**
* Set absolute path to file this class was read from.
*/
! public void setSourceFileName(final String source_file_name) {
this.source_file_name = source_file_name;
}
/**
* @param superclass_name .
*/
! public void setSuperclassName(final String superclass_name) {
this.superclass_name = superclass_name;
}
/**
* @param superclass_name_index .
*/
! public void setSuperclassNameIndex(final int superclass_name_index) {
this.superclass_name_index = superclass_name_index;
}
/**
* @return String representing class contents.
*/
+ @Override
public String toString() {
! String access = Utility.accessToString(super.getAccessFlags(), true);
! access = access.isEmpty() ? "" : (access + " ");
! final StringBuilder buf = new StringBuilder(128);
! buf.append(access).append(Utility.classOrInterface(super.getAccessFlags())).append(" ").append(
! class_name).append(" extends ").append(
! Utility.compactClassName(superclass_name, false)).append('\n');
! final 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").append(file_name).append('\n');
! buf.append("compiled from\t\t").append(source_file_name).append('\n');
! buf.append("compiler version\t").append(major).append(".").append(minor).append('\n');
! buf.append("access flags\t\t").append(super.getAccessFlags()).append('\n');
! buf.append("constant pool\t\t").append(constant_pool.getLength()).append(" entries\n");
! buf.append("ACC_SUPER flag\t\t").append(isSuper()).append("\n");
! if (attributes.length > 0) {
buf.append("\nAttribute(s):\n");
! for (final Attribute attribute : attributes) {
! buf.append(indent(attribute));
}
}
! final AnnotationEntry[] annotations = getAnnotationEntries();
! if (annotations != null && annotations.length > 0) {
! buf.append("\nAnnotation(s):\n");
! for (final AnnotationEntry annotation : annotations) {
! buf.append(indent(annotation));
! }
! }
! if (fields.length > 0) {
! buf.append("\n").append(fields.length).append(" fields:\n");
! for (final Field field : fields) {
! buf.append("\t").append(field).append('\n');
! }
! }
! if (methods.length > 0) {
! buf.append("\n").append(methods.length).append(" methods:\n");
! for (final Method method : methods) {
! buf.append("\t").append(method).append('\n');
! }
}
return buf.toString();
}
! private static String indent(final Object obj) {
! final StringTokenizer tok = new StringTokenizer(obj.toString(), "\n");
! final StringBuilder buf = new StringBuilder();
! while (tok.hasMoreTokens()) {
! buf.append("\t").append(tok.nextToken()).append("\n");
! }
return buf.toString();
}
/**
* @return deep copy of this class
*/
public JavaClass copy() {
JavaClass c = null;
try {
! c = (JavaClass) clone();
c.constant_pool = constant_pool.copy();
! c.interfaces = interfaces.clone();
! c.interface_names = 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);
! }
! } catch (final CloneNotSupportedException e) {
! // TODO should this throw?
! }
return c;
}
public final boolean isSuper() {
! return (super.getAccessFlags() & Const.ACC_SUPER) != 0;
}
public final boolean isClass() {
! return (super.getAccessFlags() & Const.ACC_INTERFACE) == 0;
! }
!
! /**
! * @since 6.0
! */
! public final boolean isAnonymous() {
! computeNestedTypeStatus();
! return this.isAnonymous;
}
! /**
! * @since 6.0
! */
! public final boolean isNested() {
! computeNestedTypeStatus();
! return this.isNested;
! }
!
! private void computeNestedTypeStatus() {
! if (computedNestedTypeStatus) {
! return;
! }
! for (final Attribute attribute : this.attributes) {
! if (attribute instanceof InnerClasses) {
! final InnerClass[] innerClasses = ((InnerClasses) attribute).getInnerClasses();
! for (final InnerClass innerClasse : innerClasses) {
! boolean innerClassAttributeRefersToMe = false;
! String inner_class_name = constant_pool.getConstantString(innerClasse.getInnerClassIndex(),
! Const.CONSTANT_Class);
! inner_class_name = Utility.compactClassName(inner_class_name);
! if (inner_class_name.equals(getClassName())) {
! innerClassAttributeRefersToMe = true;
! }
! if (innerClassAttributeRefersToMe) {
! this.isNested = true;
! if (innerClasse.getInnerNameIndex() == 0) {
! this.isAnonymous = true;
! }
! }
! }
! }
! }
! this.computedNestedTypeStatus = true;
! }
!
! /**
! * @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();
*/
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.
*/
! public void setRepository(final com.sun.org.apache.bcel.internal.util.Repository repository) {
this.repository = repository;
}
! /**
! * Equivalent to runtime "instanceof" operator.
*
! * @return true if this JavaClass is derived from the super class
! * @throws ClassNotFoundException if superclasses or superinterfaces of this
! * object can't be found
*/
! public final boolean instanceOf(final JavaClass super_class) throws ClassNotFoundException {
! if (this.equals(super_class)) {
return true;
! }
! final JavaClass[] super_classes = getSuperClasses();
! for (final JavaClass super_classe : super_classes) {
! if (super_classe.equals(super_class)) {
return true;
}
}
! if (super_class.isInterface()) {
return implementationOf(super_class);
}
return false;
}
/**
! * @return true, if this class is an implementation of interface inter
! * @throws ClassNotFoundException if superclasses or superinterfaces of this
! * class can't be found
*/
! public boolean implementationOf(final JavaClass inter) throws ClassNotFoundException {
! if (!inter.isInterface()) {
throw new IllegalArgumentException(inter.getClassName() + " is no interface");
}
! if (this.equals(inter)) {
return true;
}
! final JavaClass[] super_interfaces = getAllInterfaces();
! for (final JavaClass super_interface : super_interfaces) {
! if (super_interface.equals(inter)) {
return true;
}
}
return false;
}
/**
! * @return the superclass for this JavaClass object, or null if this is
! * java.lang.Object
! * @throws ClassNotFoundException if the superclass can't be found
*/
! public JavaClass getSuperClass() throws ClassNotFoundException {
! if ("java.lang.Object".equals(getClassName())) {
return null;
}
return repository.loadClass(getSuperclassName());
}
/**
* @return list of super classes of this class in ascending order, i.e.,
* java.lang.Object is always the last element
+ * @throws ClassNotFoundException if any of the superclasses can't be found
*/
! public JavaClass[] getSuperClasses() throws ClassNotFoundException {
JavaClass clazz = this;
! final List<JavaClass> allSuperClasses = new ArrayList<>();
! for (clazz = clazz.getSuperClass(); clazz != null; clazz = clazz.getSuperClass()) {
! allSuperClasses.add(clazz);
}
! return allSuperClasses.toArray(new JavaClass[allSuperClasses.size()]);
}
/**
* Get interfaces directly implemented by this JavaClass.
*/
! public JavaClass[] getInterfaces() throws ClassNotFoundException {
! final String[] _interfaces = getInterfaceNames();
! final JavaClass[] classes = new JavaClass[_interfaces.length];
! for (int i = 0; i < _interfaces.length; i++) {
! classes[i] = repository.loadClass(_interfaces[i]);
}
return classes;
}
/**
* Get all interfaces implemented by this JavaClass (transitively).
*/
! public JavaClass[] getAllInterfaces() throws ClassNotFoundException {
! final ClassQueue queue = new ClassQueue();
! final Set<JavaClass> allInterfaces = new TreeSet<>();
queue.enqueue(this);
! while (!queue.empty()) {
! final JavaClass clazz = queue.dequeue();
! final JavaClass souper = clazz.getSuperClass();
! final JavaClass[] _interfaces = clazz.getInterfaces();
! if (clazz.isInterface()) {
! allInterfaces.add(clazz);
} else {
! if (souper != null) {
queue.enqueue(souper);
}
}
+ for (final JavaClass _interface : _interfaces) {
+ queue.enqueue(_interface);
+ }
+ }
+ return allInterfaces.toArray(new JavaClass[allInterfaces.size()]);
+ }
! /**
! * @return Comparison strategy object
! */
! public static BCELComparator getComparator() {
! return bcelComparator;
}
+
+ /**
+ * @param comparator Comparison strategy object
+ */
+ public static void setComparator(final BCELComparator comparator) {
+ bcelComparator = comparator;
}
! /**
! * Return value as defined by given BCELComparator strategy. By default two
! * JavaClass objects are said to be equal when their class names are equal.
! *
! * @see java.lang.Object#equals(java.lang.Object)
! */
! @Override
! public boolean equals(final Object obj) {
! return bcelComparator.equals(this, obj);
! }
!
! /**
! * Return the natural ordering of two JavaClasses. This ordering is based on
! * the class name
! *
! * @since 6.0
! */
! @Override
! public int compareTo(final JavaClass obj) {
! return getClassName().compareTo(obj.getClassName());
! }
!
! /**
! * Return value as defined by given BCELComparator strategy. By default
! * return the hashcode of the class name.
! *
! * @see java.lang.Object#hashCode()
! */
! @Override
! public int hashCode() {
! return bcelComparator.hashCode(this);
}
}
< prev index next >