--- old/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/JavaClass.java 2017-08-08 16:04:34.323452153 -0700
+++ new/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/JavaClass.java 2017-08-08 16:04:34.171444542 -0700
@@ -17,772 +17,855 @@
* 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;
+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 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
+ * 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.
-
+ *
+ * @version $Id: JavaClass.java 1750227 2016-06-25 21:47:10Z ggregory $
* @see com.sun.org.apache.bcel.internal.generic.ClassGen
- * @author M. Dahm
*/
-public class JavaClass extends AccessFlags implements Cloneable, Node {
- private String file_name;
- private String package_name;
- private String source_file_name = "";
- 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
- * 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.
- *
- * @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.
- *
- * @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]);
- }
+public class JavaClass extends AccessFlags implements Cloneable, Node, Comparable {
+
+ private String file_name;
+ private String package_name;
+ private String source_file_name = "";
+ 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
+ * 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(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);
+ }
+ }
+
+ /**
+ * 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(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);
}
- return vec.toArray();
- }
+ /**
+ * 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 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 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);
+ }
}