JavaClass.java
- /*
- * 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 org.apache.bcel.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.Arrays;
- import java.util.List;
- import java.util.Objects;
- import java.util.Set;
- import java.util.StringTokenizer;
- import java.util.TreeSet;
- import org.apache.bcel.Const;
- import org.apache.bcel.generic.Type;
- import org.apache.bcel.util.BCELComparator;
- import org.apache.bcel.util.ClassQueue;
- import org.apache.bcel.util.SyntheticRepository;
- import org.apache.commons.lang3.ArrayUtils;
- /**
- * Represents a Java class, i.e., the data structures, constant pool, fields, methods and commands contained in a Java
- * .class file. See <a href="https://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 programmatically generating
- * classes should see the <a href="../generic/ClassGen.html">ClassGen</a> class.
- *
- * @see org.apache.bcel.generic.ClassGen
- */
- public class JavaClass extends AccessFlags implements Cloneable, Node, Comparable<JavaClass> {
- /**
- * The standard class file extension.
- *
- * @since 6.7.0
- */
- public static final String EXTENSION = ".class";
- /**
- * Empty array.
- *
- * @since 6.6.0
- */
- public static final JavaClass[] EMPTY_ARRAY = {};
- public static final byte HEAP = 1;
- public static final byte FILE = 2;
- public static final byte ZIP = 3;
- private static final boolean debug = Boolean.getBoolean("JavaClass.debug"); // Debugging on/off
- private static BCELComparator<JavaClass> bcelComparator = new BCELComparator<JavaClass>() {
- @Override
- public boolean equals(final JavaClass a, final JavaClass b) {
- return a == b || a != null && b != null && Objects.equals(a.getClassName(), b.getClassName());
- }
- @Override
- public int hashCode(final JavaClass o) {
- return o != null ? Objects.hashCode(o.getClassName()) : 0;
- }
- };
- /*
- * Print debug information depending on 'JavaClass.debug'
- */
- static void Debug(final String str) {
- if (debug) {
- System.out.println(str);
- }
- }
- /**
- * @return Comparison strategy object.
- */
- public static BCELComparator<JavaClass> getComparator() {
- return bcelComparator;
- }
- private static String indent(final Object obj) {
- final StringTokenizer tokenizer = new StringTokenizer(obj.toString(), "\n");
- final StringBuilder buf = new StringBuilder();
- while (tokenizer.hasMoreTokens()) {
- buf.append("\t").append(tokenizer.nextToken()).append("\n");
- }
- return buf.toString();
- }
- /**
- * @param comparator Comparison strategy object.
- */
- public static void setComparator(final BCELComparator<JavaClass> comparator) {
- bcelComparator = comparator;
- }
- private String fileName;
- private final String packageName;
- private String sourceFileName = "<Unknown>";
- private int classNameIndex;
- private int superclassNameIndex;
- private String className;
- private String superclassName;
- private int major;
- private int minor; // Compiler version
- private ConstantPool constantPool; // Constant pool
- private int[] interfaces; // implemented interfaces
- private String[] interfaceNames;
- 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;
- private boolean isNested;
- private boolean isRecord;
- private boolean computedNestedTypeStatus;
- private boolean computedRecord;
- /**
- * In cases where we go ahead and create something, use the default SyntheticRepository, because we don't know any
- * better.
- */
- private transient org.apache.bcel.util.Repository repository = SyntheticRepository.getInstance();
- /**
- * Constructor gets all contents as arguments.
- *
- * @param classNameIndex Class name
- * @param superclassNameIndex Superclass name
- * @param fileName File name
- * @param major Major compiler version
- * @param minor Minor compiler version
- * @param accessFlags Access rights defined by bit flags
- * @param constantPool Array of constants
- * @param interfaces Implemented interfaces
- * @param fields Class fields
- * @param methods Class methods
- * @param attributes Class attributes
- */
- public JavaClass(final int classNameIndex, final int superclassNameIndex, final String fileName, final int major, final int minor, final int accessFlags,
- final ConstantPool constantPool, final int[] interfaces, final Field[] fields, final Method[] methods, final Attribute[] attributes) {
- this(classNameIndex, superclassNameIndex, fileName, major, minor, accessFlags, constantPool, interfaces, fields, methods, attributes, HEAP);
- }
- /**
- * Constructor gets all contents as arguments.
- *
- * @param classNameIndex Index into constant pool referencing a ConstantClass that represents this class.
- * @param superclassNameIndex Index into constant pool referencing a ConstantClass that represents this class's
- * superclass.
- * @param fileName File name
- * @param major Major compiler version
- * @param minor Minor compiler version
- * @param accessFlags Access rights defined by bit flags
- * @param constantPool 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 classNameIndex, final int superclassNameIndex, final String fileName, final int major, final int minor, final int accessFlags,
- final ConstantPool constantPool, int[] interfaces, Field[] fields, Method[] methods, Attribute[] attributes, final byte source) {
- super(accessFlags);
- interfaces = ArrayUtils.nullToEmpty(interfaces);
- if (attributes == null) {
- attributes = Attribute.EMPTY_ARRAY;
- }
- if (fields == null) {
- fields = Field.EMPTY_ARRAY;
- }
- if (methods == null) {
- methods = Method.EMPTY_ARRAY;
- }
- this.classNameIndex = classNameIndex;
- this.superclassNameIndex = superclassNameIndex;
- this.fileName = fileName;
- this.major = major;
- this.minor = minor;
- this.constantPool = constantPool;
- 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) {
- sourceFileName = ((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.
- */
- className = constantPool.getConstantString(classNameIndex, Const.CONSTANT_Class);
- className = Utility.compactClassName(className, false);
- final int index = className.lastIndexOf('.');
- if (index < 0) {
- packageName = "";
- } else {
- packageName = className.substring(0, index);
- }
- if (superclassNameIndex > 0) {
- // May be zero -> class is java.lang.Object
- superclassName = constantPool.getConstantString(superclassNameIndex, Const.CONSTANT_Class);
- superclassName = Utility.compactClassName(superclassName, false);
- } else {
- superclassName = "java.lang.Object";
- }
- interfaceNames = new String[interfaces.length];
- for (int i = 0; i < interfaces.length; i++) {
- final String str = constantPool.getConstantString(interfaces[i], Const.CONSTANT_Class);
- interfaceNames[i] = Utility.compactClassName(str, false);
- }
- }
- /**
- * 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 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());
- }
- private void computeIsRecord() {
- if (computedRecord) {
- return;
- }
- for (final Attribute attribute : this.attributes) {
- if (attribute instanceof Record) {
- isRecord = true;
- break;
- }
- }
- this.computedRecord = true;
- }
- private void computeNestedTypeStatus() {
- if (computedNestedTypeStatus) {
- return;
- }
- for (final Attribute attribute : this.attributes) {
- if (attribute instanceof InnerClasses) {
- ((InnerClasses) attribute).forEach(innerClass -> {
- boolean innerClassAttributeRefersToMe = false;
- String innerClassName = constantPool.getConstantString(innerClass.getInnerClassIndex(), Const.CONSTANT_Class);
- innerClassName = Utility.compactClassName(innerClassName, false);
- if (innerClassName.equals(getClassName())) {
- innerClassAttributeRefersToMe = true;
- }
- if (innerClassAttributeRefersToMe) {
- this.isNested = true;
- if (innerClass.getInnerNameIndex() == 0) {
- this.isAnonymous = true;
- }
- }
- });
- }
- }
- this.computedNestedTypeStatus = true;
- }
- /**
- * @return deep copy of this class
- */
- public JavaClass copy() {
- try {
- final JavaClass c = (JavaClass) clone();
- c.constantPool = constantPool.copy();
- c.interfaces = interfaces.clone();
- c.interfaceNames = interfaceNames.clone();
- c.fields = new Field[fields.length];
- Arrays.setAll(c.fields, i -> fields[i].copy(c.constantPool));
- c.methods = new Method[methods.length];
- Arrays.setAll(c.methods, i -> methods[i].copy(c.constantPool));
- c.attributes = new Attribute[attributes.length];
- Arrays.setAll(c.attributes, i -> attributes[i].copy(c.constantPool));
- return c;
- } catch (final CloneNotSupportedException e) {
- return null;
- }
- }
- /**
- * Dump Java class to output stream in binary format.
- *
- * @param file Output stream
- * @throws IOException if an I/O error occurs.
- */
- public void dump(final DataOutputStream file) throws IOException {
- file.writeInt(Const.JVM_CLASSFILE_MAGIC);
- file.writeShort(minor);
- file.writeShort(major);
- constantPool.dump(file);
- file.writeShort(super.getAccessFlags());
- file.writeShort(classNameIndex);
- file.writeShort(superclassNameIndex);
- 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();
- }
- /**
- * Dump class to a file.
- *
- * @param file Output file
- * @throws IOException if an I/O error occurs.
- */
- 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() && !dir.isDirectory()) {
- throw new IOException("Could not create the directory " + dir);
- }
- }
- try (DataOutputStream dos = new DataOutputStream(new FileOutputStream(file))) {
- dump(dos);
- }
- }
- /**
- * Dump Java class to output stream in binary format.
- *
- * @param file Output stream
- * @throws IOException if an I/O error occurs.
- */
- public void dump(final OutputStream file) throws IOException {
- dump(new DataOutputStream(file));
- }
- /**
- * Dump class to a file named fileName.
- *
- * @param fileName Output file name
- * @throws IOException if an I/O error occurs.
- */
- public void dump(final String fileName) throws IOException {
- dump(new File(fileName));
- }
- /**
- * 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 Object#equals(Object)
- */
- @Override
- public boolean equals(final Object obj) {
- return obj instanceof JavaClass && bcelComparator.equals(this, (JavaClass) obj);
- }
- /**
- * Finds a visible field by name and type in this class and its super classes.
- * @param fieldName the field name to find
- * @param fieldType the field type to find
- * @return field matching given name and type, null if field is not found or not accessible from this class.
- * @throws ClassNotFoundException
- * @since 6.8.0
- */
- public Field findField(final String fieldName, final Type fieldType) throws ClassNotFoundException {
- for (final Field field : fields) {
- if (field.getName().equals(fieldName)) {
- final Type fType = Type.getType(field.getSignature());
- /*
- * TODO: Check if assignment compatibility is sufficient. What does Sun do?
- */
- if (fType.equals(fieldType)) {
- return field;
- }
- }
- }
- final JavaClass superclass = getSuperClass();
- if (superclass != null && !"java.lang.Object".equals(superclass.getClassName())) {
- final Field f = superclass.findField(fieldName, fieldType);
- if (f != null && (f.isPublic() || f.isProtected() || !f.isPrivate() && packageName.equals(superclass.getPackageName()))) {
- return f;
- }
- }
- final JavaClass[] implementedInterfaces = getInterfaces();
- if (implementedInterfaces != null) {
- for (final JavaClass implementedInterface : implementedInterfaces) {
- final Field f = implementedInterface.findField(fieldName, fieldType);
- if (f != null) {
- return f;
- }
- }
- }
- return null;
- }
- /**
- * Gets all interfaces implemented by this JavaClass (transitively).
- *
- * @throws ClassNotFoundException if any of the class's superclasses or interfaces can't be found.
- */
- 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 iface : interfaces) {
- queue.enqueue(iface);
- }
- }
- return allInterfaces.toArray(EMPTY_ARRAY);
- }
- /**
- * @return Annotations on the class
- * @since 6.0
- */
- public AnnotationEntry[] getAnnotationEntries() {
- if (annotations == null) {
- annotations = AnnotationEntry.createAnnotationEntries(getAttributes());
- }
- return annotations;
- }
- /**
- * Gets attribute for given tag.
- * @return Attribute for given tag, null if not found.
- * Refer to {@link org.apache.bcel.Const#ATTR_UNKNOWN} constants named ATTR_* for possible values.
- * @since 6.10.0
- */
- @SuppressWarnings("unchecked")
- public final <T extends Attribute> T getAttribute(final byte tag) {
- for (final Attribute attribute : getAttributes()) {
- if (attribute.getTag() == tag) {
- return (T) attribute;
- }
- }
- return null;
- }
- /**
- * @return Attributes of the class.
- */
- public Attribute[] getAttributes() {
- return attributes;
- }
- /**
- * @return class in binary format
- */
- public byte[] getBytes() {
- final ByteArrayOutputStream baos = new ByteArrayOutputStream();
- try (DataOutputStream dos = new DataOutputStream(baos)) {
- dump(dos);
- } catch (final IOException e) {
- e.printStackTrace();
- }
- return baos.toByteArray();
- }
- /**
- * @return Class name.
- */
- public String getClassName() {
- return className;
- }
- /**
- * @return Class name index.
- */
- public int getClassNameIndex() {
- return classNameIndex;
- }
- /**
- * @return Constant pool.
- */
- public ConstantPool getConstantPool() {
- return constantPool;
- }
- /**
- * @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 fileName;
- }
- /**
- * @return Indices in constant pool of implemented interfaces.
- */
- public int[] getInterfaceIndices() {
- return interfaces;
- }
- /**
- * @return Names of implemented interfaces.
- */
- public String[] getInterfaceNames() {
- return interfaceNames;
- }
- /**
- * Gets interfaces directly implemented by this JavaClass.
- *
- * @throws ClassNotFoundException if any of the class's interfaces can't be found.
- */
- 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;
- }
- /**
- * @return Major number of class file version.
- */
- public int getMajor() {
- return major;
- }
- /**
- * @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 Methods of the class.
- */
- public Method[] getMethods() {
- return methods;
- }
- /**
- * @return Minor number of class file version.
- */
- public int getMinor() {
- return minor;
- }
- /**
- * @return Package name.
- */
- public String getPackageName() {
- return packageName;
- }
- /**
- * Gets the ClassRepository which holds its definition. By default this is the same as
- * SyntheticRepository.getInstance();
- */
- public org.apache.bcel.util.Repository getRepository() {
- return repository;
- }
- /**
- * @return returns either HEAP (generated), FILE, or ZIP
- */
- public final byte getSource() {
- return source;
- }
- /**
- * @return file name where this class was read from
- */
- public String getSourceFileName() {
- return sourceFileName;
- }
- /**
- * Gets the source file path including the package path.
- *
- * @return path to original source file of parsed class, relative to original source directory.
- * @since 6.7.0
- */
- public String getSourceFilePath() {
- final StringBuilder outFileName = new StringBuilder();
- if (!packageName.isEmpty()) {
- outFileName.append(Utility.packageToPath(packageName));
- outFileName.append('/');
- }
- outFileName.append(sourceFileName);
- return outFileName.toString();
- }
- /**
- * @return the superclass for this JavaClass object, or null if this is {@link 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(EMPTY_ARRAY);
- }
- /**
- * returns the super class name of this class. In the case that this class is {@link Object}, it will return itself
- * ({@link Object}). This is probably incorrect but isn't fixed at this time to not break existing clients.
- *
- * @return Superclass name.
- */
- public String getSuperclassName() {
- return superclassName;
- }
- /**
- * @return Class name index.
- */
- public int getSuperclassNameIndex() {
- return superclassNameIndex;
- }
- /**
- * Return value as defined by given BCELComparator strategy. By default return the hash code of the class name.
- *
- * @see Object#hashCode()
- */
- @Override
- public int hashCode() {
- return bcelComparator.hashCode(this);
- }
- /**
- * @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 (equals(inter)) {
- return true;
- }
- final JavaClass[] superInterfaces = getAllInterfaces();
- for (final JavaClass superInterface : superInterfaces) {
- if (superInterface.equals(inter)) {
- return true;
- }
- }
- return false;
- }
- /**
- * 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 superclass) throws ClassNotFoundException {
- if (equals(superclass)) {
- return true;
- }
- for (final JavaClass clazz : getSuperClasses()) {
- if (clazz.equals(superclass)) {
- return true;
- }
- }
- if (superclass.isInterface()) {
- return implementationOf(superclass);
- }
- return false;
- }
- /**
- * @since 6.0
- */
- public final boolean isAnonymous() {
- computeNestedTypeStatus();
- return this.isAnonymous;
- }
- public final boolean isClass() {
- return (super.getAccessFlags() & Const.ACC_INTERFACE) == 0;
- }
- /**
- * @since 6.0
- */
- public final boolean isNested() {
- computeNestedTypeStatus();
- return this.isNested;
- }
- /**
- * Tests whether this class was declared as a record
- *
- * @return true if a record attribute is present, false otherwise.
- * @since 6.9.0
- */
- public boolean isRecord() {
- computeIsRecord();
- return this.isRecord;
- }
- public final boolean isSuper() {
- return (super.getAccessFlags() & Const.ACC_SUPER) != 0;
- }
- /**
- * @param attributes .
- */
- public void setAttributes(final Attribute[] attributes) {
- this.attributes = attributes != null ? attributes : Attribute.EMPTY_ARRAY;
- }
- /**
- * @param className .
- */
- public void setClassName(final String className) {
- this.className = className;
- }
- /**
- * @param classNameIndex .
- */
- public void setClassNameIndex(final int classNameIndex) {
- this.classNameIndex = classNameIndex;
- }
- /**
- * @param constantPool .
- */
- public void setConstantPool(final ConstantPool constantPool) {
- this.constantPool = constantPool;
- }
- /**
- * @param fields .
- */
- public void setFields(final Field[] fields) {
- this.fields = fields != null ? fields : Field.EMPTY_ARRAY;
- }
- /**
- * Sets File name of class, aka SourceFile attribute value
- */
- public void setFileName(final String fileName) {
- this.fileName = fileName;
- }
- /**
- * @param interfaceNames .
- */
- public void setInterfaceNames(final String[] interfaceNames) {
- this.interfaceNames = ArrayUtils.nullToEmpty(interfaceNames);
- }
- /**
- * @param interfaces .
- */
- public void setInterfaces(final int[] interfaces) {
- this.interfaces = ArrayUtils.nullToEmpty(interfaces);
- }
- /**
- * @param major .
- */
- public void setMajor(final int major) {
- this.major = major;
- }
- /**
- * @param methods .
- */
- public void setMethods(final Method[] methods) {
- this.methods = methods != null ? methods : Method.EMPTY_ARRAY;
- }
- /**
- * @param minor .
- */
- public void setMinor(final int minor) {
- this.minor = minor;
- }
- /**
- * Sets the ClassRepository which loaded the JavaClass. Should be called immediately after parsing is done.
- */
- public void setRepository(final org.apache.bcel.util.Repository repository) { // TODO make protected?
- this.repository = repository;
- }
- /**
- * Sets absolute path to file this class was read from.
- */
- public void setSourceFileName(final String sourceFileName) {
- this.sourceFileName = sourceFileName;
- }
- /**
- * @param superclassName .
- */
- public void setSuperclassName(final String superclassName) {
- this.superclassName = superclassName;
- }
- /**
- * @param superclassNameIndex .
- */
- public void setSuperclassNameIndex(final int superclassNameIndex) {
- this.superclassNameIndex = superclassNameIndex;
- }
- /**
- * @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(className).append(" extends ")
- .append(Utility.compactClassName(superclassName, 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(interfaceNames[i]);
- if (i < size - 1) {
- buf.append(", ");
- }
- }
- buf.append('\n');
- }
- buf.append("file name\t\t").append(fileName).append('\n');
- buf.append("compiled from\t\t").append(sourceFileName).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(constantPool.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();
- }
- }