< 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 >