View Javadoc

    1   /*
    2    * Copyright  2000-2004 The Apache Software Foundation
    3    *
    4    *  Licensed under the Apache License, Version 2.0 (the "License");
    5    *  you may not use this file except in compliance with the License.
    6    *  You may obtain a copy of the License at
    7    *
    8    *      http://www.apache.org/licenses/LICENSE-2.0
    9    *
    10   *  Unless required by applicable law or agreed to in writing, software
    11   *  distributed under the License is distributed on an "AS IS" BASIS,
    12   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   *  See the License for the specific language governing permissions and
    14   *  limitations under the License.
    15   *
    16   */
    17  package org.apache.bcel.classfile;
    18
    19  import java.io.ByteArrayOutputStream;
    20  import java.io.DataOutputStream;
    21  import java.io.File;
    22  import java.io.FileOutputStream;
    23  import java.io.IOException;
    24  import java.io.OutputStream;
    25  import java.util.ArrayList;
    26  import java.util.List;
    27  import java.util.Set;
    28  import java.util.StringTokenizer;
    29  import java.util.TreeSet;
    30  import org.apache.bcel.Constants;
    31  import org.apache.bcel.generic.Type;
    32  import org.apache.bcel.util.BCELComparator;
    33  import org.apache.bcel.util.ClassQueue;
    34  import org.apache.bcel.util.SyntheticRepository;
    35
    36  /***
    37   * Represents a Java class, i.e., the data structures, constant pool,
    38   * fields, methods and commands contained in a Java .class file.
    39   * See <a href="ftp://java.sun.com/docs/specs/">JVM specification</a> for details.
    40   * The intent of this class is to represent a parsed or otherwise existing
    41   * class file.  Those interested in programatically generating classes
    42   * should see the <a href="../generic/ClassGen.html">ClassGen</a> class.
    43
    44   * @version $Id: JavaClass.java 386056 2006-03-15 11:31:56Z tcurdt $
    45   * @see org.apache.bcel.generic.ClassGen
    46   * @author  <A HREF="mailto:m.dahm@gmx.de">M. Dahm</A>
    47   */
    48  public class JavaClass extends AccessFlags implements Cloneable, Node, Comparable {
    49
    50      private String file_name;
    51      private</str<a href="../../../../ong> String <strong>package</strong>_name/package-summary.html">ong> String package_name;
    52      private String source_file_name = "<Unknown>";
    53      private int class_name_index;
    54      private int superclass_name_index;
    55      private String class_name;
    56      private String superclass_name;
    57      private int major, minor; // Compiler version
    58      private ConstantPool constant_pool; // Constant pool
    59      private int[] interfaces; // implemented interfaces
    60      private String[] interface_names;
    61      private Field[] fields; // Fields, i.e., variables of class
    62      private Method[] methods; // methods defined in the class
    63      private Attribute[] attributes; // attributes defined in the class
    64      private byte source = HEAP; // Generated in memory
    65      public static final byte HEAP = 1;
    66      public static final byte FILE = 2;
    67      public static final byte ZIP = 3;
    68      static boolean debug = false; // Debugging on/off
    69      static char sep = '/'; // directory separator
    70      private static BCELComparator _cmp = new BCELComparator() {
    71
    72          public boolean equals( Object o1, Object o2 ) {
    73              JavaClass THIS = (JavaClass) o1;
    74              JavaClass THAT = (JavaClass) o2;
    75              return THIS.getClassName().equals(THAT.getClassName());
    76          }
    77
    78
    79          public int hashCode( Object o ) {
    80              JavaClass THIS = (JavaClass) o;
    81              return THIS.getClassName().hashCode();
    82          }
    83      };
    84      /***
    85       * In cases where we go ahead and create something,
    86       * use the default SyntheticRepository, because we
    87       * don't know any better.
    88       */
    89      private transient org.apache.bcel.util.Repository repository = SyntheticRepository
    90              .getInstance();
    91
    92
    93      /***
    94       * Constructor gets all contents as arguments.
    95       *
    96       * @param class_name_index Index into constant pool referencing a
    97       * ConstantClass that represents this class.
    98       * @param superclass_name_index Index into constant pool referencing a
    99       * ConstantClass that represents this class's superclass.
    100      * @param file_name File name
    101      * @param major Major compiler version
    102      * @param minor Minor compiler version
    103      * @param access_flags Access rights defined by bit flags
    104      * @param constant_pool Array of constants
    105      * @param interfaces Implemented interfaces
    106      * @param fields Class fields
    107      * @param methods Class methods
    108      * @param attributes Class attributes
    109      * @param source Read from file or generated in memory?
    110      */
    111     public JavaClass(int class_name_index, int superclass_name_index, String file_name, int major,
    112             int minor, int access_flags, ConstantPool constant_pool, int[] interfaces,
    113             Field[] fields, Method[] methods, Attribute[] attributes, byte source) {
    114         if (interfaces == null) {
    115             interfaces = new int[0];
    116         }
    117         if (attributes == null) {
    118             attributes = new Attribute[0];
    119         }
    120         if (fields == null) {
    121             fields = new Field[0];
    122         }
    123         if (methods == null) {
    124             methods = new Method[0];
    125         }
    126         this.class_name_index = class_name_index;
    127         this.superclass_name_index = superclass_name_index;
    128         this.file_name = file_name;
    129         this.major = major;
    130         this.minor = minor;
    131         this.access_flags = access_flags;
    132         this.constant_pool = constant_pool;
    133         this.interfaces = interfaces;
    134         this.fields = fields;
    135         this.methods = methods;
    136         this.attributes = attributes;
    137         this.source = source;
    138         // Get source file name if available
    139         for (int i = 0; i < attributes.length; i++) {
    140             if (attributes[i] instanceof SourceFile) {
    141                 source_file_name = ((SourceFile) attributes[i]).getSourceFileName();
    142                 break;
    143             }
    144         }
    145         /* According to the specification the following entries must be of type
    146          * `ConstantClass' but we check that anyway via the
    147          * `ConstPool.getConstant' method.
    148          */
    149         class_name = constant_pool.getConstantString(class_name_index, Constants.CONSTANT_Class);
    150         class_name = Utility.compactClassName(class_name, false);
    151         int index = class_name.lastIndexOf('.');
    152         if (index < 0) {
    153             package_name =/package-summary.html">strong>_name = "";
    154         } else {
    155             package_name = class_name/substring(0, index)/package-summary.html">strong>_name = class_name.substring(0, index);
    156         }
    157         if (superclass_name_index > 0) {
    158             // May be zero -> class is java.lang.Object
    159             superclass_name = constant_pool.getConstantString(superclass_name_index,
    160                     Constants.CONSTANT_Class);
    161             superclass_name = Utility.compactClassName(superclass_name, false);
    162         } else {
    163             superclass_name = "java.lang.Object";
    164         }
    165         interface_names = new String[interfaces.length];
    166         for (int i = 0; i < interfaces.length; i++) {
    167             String str = constant_pool.getConstantString(interfaces[i], Constants.CONSTANT_Class);
    168             interface_names[i] = Utility.compactClassName(str, false);
    169         }
    170     }
    171
    172
    173     /***
    174      * Constructor gets all contents as arguments.
    175      *
    176      * @param class_name_index Class name
    177      * @param superclass_name_index Superclass name
    178      * @param file_name File name
    179      * @param major Major compiler version
    180      * @param minor Minor compiler version
    181      * @param access_flags Access rights defined by bit flags
    182      * @param constant_pool Array of constants
    183      * @param interfaces Implemented interfaces
    184      * @param fields Class fields
    185      * @param methods Class methods
    186      * @param attributes Class attributes
    187      */
    188     public JavaClass(int class_name_index, int superclass_name_index, String file_name, int major,
    189             int minor, int access_flags, ConstantPool constant_pool, int[] interfaces,
    190             Field[] fields, Method[] methods, Attribute[] attributes) {
    191         this(class_name_index, superclass_name_index, file_name, major, minor, access_flags,
    192                 constant_pool, interfaces, fields, methods, attributes, HEAP);
    193     }
    194
    195
    196     /***
    197      * Called by objects that are traversing the nodes of the tree implicitely
    198      * defined by the contents of a Java class. I.e., the hierarchy of methods,
    199      * fields, attributes, etc. spawns a tree of objects.
    200      *
    201      * @param v Visitor object
    202      */
    203     public void accept( Visitor v ) {
    204         v.visitJavaClass(this);
    205     }
    206
    207
    208     /* Print debug information depending on `JavaClass.debug'
    209      */
    210     static final void Debug( String str ) {
    211         if (debug) {
    212             System.out.println(str);
    213         }
    214     }
    215
    216
    217     /***
    218      * Dump class to a file.
    219      *
    220      * @param file Output file
    221      * @throws IOException
    222      */
    223     public void dump( File file ) throws IOException {
    224         String parent = file.getParent();
    225         if (parent != null) {
    226             File dir = new File(parent);
    227             dir.mkdirs();
    228         }
    229         DataOutputStream dos = null;
    230         try {
    231             dos = new DataOutputStream(new FileOutputStream(file));
    232             dump(dos);
    233         } finally {
    234             if (dos != null) {
    235                 dos.close();
    236             }
    237         }
    238     }
    239
    240
    241     /***
    242      * Dump class to a file named file_name.
    243      *
    244      * @param _file_name Output file name
    245      * @exception IOException
    246      */
    247     public void dump( String _file_name ) throws IOException {
    248         dump(new File(_file_name));
    249     }
    250
    251
    252     /***
    253      * @return class in binary format
    254      */
    255     public byte[] getBytes() {
    256         ByteArrayOutputStream s = new ByteArrayOutputStream();
    257         DataOutputStream ds = new DataOutputStream(s);
    258         try {
    259             dump(ds);
    260         } catch (IOException e) {
    261             e.printStackTrace();
    262         } finally {
    263             try {
    264                 ds.close();
    265             } catch (IOException e2) {
    266                 e2.printStackTrace();
    267             }
    268         }
    269         return s.toByteArray();
    270     }
    271
    272
    273     /***
    274      * Dump Java class to output stream in binary format.
    275      *
    276      * @param file Output stream
    277      * @exception IOException
    278      */
    279     public void dump( OutputStream file ) throws IOException {
    280         dump(new DataOutputStream(file));
    281     }
    282
    283
    284     /***
    285      * Dump Java class to output stream in binary format.
    286      *
    287      * @param file Output stream
    288      * @exception IOException
    289      */
    290     public void dump( DataOutputStream file ) throws IOException {
    291         file.writeInt(0xcafebabe);
    292         file.writeShort(minor);
    293         file.writeShort(major);
    294         constant_pool.dump(file);
    295         file.writeShort(access_flags);
    296         file.writeShort(class_name_index);
    297         file.writeShort(superclass_name_index);
    298         file.writeShort(interfaces.length);
    299         for (int i = 0; i < interfaces.length; i++) {
    300             file.writeShort(interfaces[i]);
    301         }
    302         file.writeShort(fields.length);
    303         for (int i = 0; i < fields.length; i++) {
    304             fields[i].dump(file);
    305         }
    306         file.writeShort(methods.length);
    307         for (int i = 0; i < methods.length; i++) {
    308             methods[i].dump(file);
    309         }
    310         if (attributes != null) {
    311             file.writeShort(attributes.length);
    312             for (int i = 0; i < attributes.length; i++) {
    313                 attributes[i].dump(file);
    314             }
    315         } else {
    316             file.writeShort(0);
    317         }
    318         file.flush();
    319     }
    320
    321
    322     /***
    323      * @return Attributes of the class.
    324      */
    325     public Attribute[] getAttributes() {
    326         return attributes;
    327     }
    328
    329
    330     /***
    331      * @return Class name.
    332      */
    333     public String getClassName() {
    334         return class_name;
    335     }
    336
    337
    338     /***
    339      * @return Package name.
    340      */
    341     public String getPackageName() {
    342         return</strong> package_name;
    343     }
    344
    345
    346     /***
    347      * @return Class name index.
    348      */
    349     public int getClassNameIndex() {
    350         return class_name_index;
    351     }
    352
    353
    354     /***
    355      * @return Constant pool.
    356      */
    357     public ConstantPool getConstantPool() {
    358         return constant_pool;
    359     }
    360
    361
    362     /***
    363      * @return Fields, i.e., variables of the class. Like the JVM spec
    364      * mandates for the classfile format, these fields are those specific to
    365      * this class, and not those of the superclass or superinterfaces.
    366      */
    367     public Field[] getFields() {
    368         return fields;
    369     }
    370
    371
    372     /***
    373      * @return File name of class, aka SourceFile attribute value
    374      */
    375     public String getFileName() {
    376         return file_name;
    377     }
    378
    379
    380     /***
    381      * @return Names of implemented interfaces.
    382      */
    383     public String[] getInterfaceNames() {
    384         return interface_names;
    385     }
    386
    387
    388     /***
    389      * @return Indices in constant pool of implemented interfaces.
    390      */
    391     public int[] getInterfaceIndices() {
    392         return interfaces;
    393     }
    394
    395
    396     /***
    397      * @return Major number of class file version.
    398      */
    399     public int getMajor() {
    400         return major;
    401     }
    402
    403
    404     /***
    405      * @return Methods of the class.
    406      */
    407     public Method[] getMethods() {
    408         return methods;
    409     }
    410
    411
    412     /***
    413      * @return A org.apache.bcel.classfile.Method corresponding to
    414      * java.lang.reflect.Method if any
    415      */
    416     public Method getMethod( java.lang.reflect.Method m ) {
    417         for (int i = 0; i < methods.length; i++) {
    418             Method method = methods[i];
    419             if (m.getName().equals(method.getName()) && (m.getModifiers() == method.getModifiers())
    420                     && Type.getSignature(m).equals(method.getSignature())) {
    421                 return method;
    422             }
    423         }
    424         return null;
    425     }
    426
    427
    428     /***
    429      * @return Minor number of class file version.
    430      */
    431     public int getMinor() {
    432         return minor;
    433     }
    434
    435
    436     /***
    437      * @return sbsolute path to file where this class was read from
    438      */
    439     public String getSourceFileName() {
    440         return source_file_name;
    441     }
    442
    443
    444     /***
    445      * @return Superclass name.
    446      */
    447     public String getSuperclassName() {
    448         return superclass_name;
    449     }
    450
    451
    452     /***
    453      * @return Class name index.
    454      */
    455     public int getSuperclassNameIndex() {
    456         return superclass_name_index;
    457     }
    458
    459     static {
    460         // Debugging ... on/off
    461         debug = Boolean.getBoolean("JavaClass.debug");
    462         // Get path separator either / or \ usually
    463         String _sep = System.getProperty("file.separator");
    464         if (_sep != null) {
    465             try {
    466                 JavaClass.sep = _sep.charAt(0);
    467             } catch (StringIndexOutOfBoundsException e) {
    468             } // Never reached
    469         }
    470     }
    471
    472
    473     /***
    474      * @param attributes .
    475      */
    476     public void setAttributes( Attribute[] attributes ) {
    477         this.attributes = attributes;
    478     }
    479
    480
    481     /***
    482      * @param class_name .
    483      */
    484     public void setClassName( String class_name ) {
    485         this.class_name = class_name;
    486     }
    487
    488
    489     /***
    490      * @param class_name_index .
    491      */
    492     public void setClassNameIndex( int class_name_index ) {
    493         this.class_name_index = class_name_index;
    494     }
    495
    496
    497     /***
    498      * @param constant_pool .
    499      */
    500     public void setConstantPool( ConstantPool constant_pool ) {
    501         this.constant_pool = constant_pool;
    502     }
    503
    504
    505     /***
    506      * @param fields .
    507      */
    508     public void setFields( Field[] fields ) {
    509         this.fields = fields;
    510     }
    511
    512
    513     /***
    514      * Set File name of class, aka SourceFile attribute value
    515      */
    516     public void setFileName( String file_name ) {
    517         this.file_name = file_name;
    518     }
    519
    520
    521     /***
    522      * @param interface_names .
    523      */
    524     public void setInterfaceNames( String[] interface_names ) {
    525         this.interface_names = interface_names;
    526     }
    527
    528
    529     /***
    530      * @param interfaces .
    531      */
    532     public void setInterfaces( int[] interfaces ) {
    533         this.interfaces = interfaces;
    534     }
    535
    536
    537     /***
    538      * @param major .
    539      */
    540     public void setMajor( int major ) {
    541         this.major = major;
    542     }
    543
    544
    545     /***
    546      * @param methods .
    547      */
    548     public void setMethods( Method[] methods ) {
    549         this.methods = methods;
    550     }
    551
    552
    553     /***
    554      * @param minor .
    555      */
    556     public void setMinor( int minor ) {
    557         this.minor = minor;
    558     }
    559
    560
    561     /***
    562      * Set absolute path to file this class was read from.
    563      */
    564     public void setSourceFileName( String source_file_name ) {
    565         this.source_file_name = source_file_name;
    566     }
    567
    568
    569     /***
    570      * @param superclass_name .
    571      */
    572     public void setSuperclassName( String superclass_name ) {
    573         this.superclass_name = superclass_name;
    574     }
    575
    576
    577     /***
    578      * @param superclass_name_index .
    579      */
    580     public void setSuperclassNameIndex( int superclass_name_index ) {
    581         this.superclass_name_index = superclass_name_index;
    582     }
    583
    584
    585     /***
    586      * @return String representing class contents.
    587      */
    588     public String toString() {
    589         String access = Utility.accessToString(access_flags, true);
    590         access = access.equals("") ? "" : (access + " ");
    591         StringBuffer buf = new StringBuffer(128);
    592         buf.append(access).append(Utility.classOrInterface(access_flags)).append(" ").append(
    593                 class_name).append(" extends ").append(
    594                 Utility.compactClassName(superclass_name, false)).append('\n');
    595         int size = interfaces.length;
    596         if (size > 0) {
    597             buf.append("implements\t\t");
    598             for (int i = 0; i < size; i++) {
    599                 buf.append(interface_names[i]);
    600                 if (i < size - 1) {
    601                     buf.append(", ");
    602                 }
    603             }
    604             buf.append('\n');
    605         }
    606         buf.append("filename\t\t").append(file_name).append('\n');
    607         buf.append("compiled from\t\t").append(source_file_name).append('\n');
    608         buf.append("compiler version\t").append(major).append(".").append(minor).append('\n');
    609         buf.append("access flags\t\t").append(access_flags).append('\n');
    610         buf.append("constant pool\t\t").append(constant_pool.getLength()).append(" entries\n");
    611         buf.append("ACC_SUPER flag\t\t").append(isSuper()).append("\n");
    612         if (attributes.length > 0) {
    613             buf.append("\nAttribute(s):\n");
    614             for (int i = 0; i < attributes.length; i++) {
    615                 buf.append(indent(attributes[i]));
    616             }
    617         }
    618         if (fields.length > 0) {
    619             buf.append("\n").append(fields.length).append(" fields:\n");
    620             for (int i = 0; i < fields.length; i++) {
    621                 buf.append("\t").append(fields[i]).append('\n');
    622             }
    623         }
    624         if (methods.length > 0) {
    625             buf.append("\n").append(methods.length).append(" methods:\n");
    626             for (int i = 0; i < methods.length; i++) {
    627                 buf.append("\t").append(methods[i]).append('\n');
    628             }
    629         }
    630         return buf.toString();
    631     }
    632
    633
    634     private static final String indent( Object obj ) {
    635         StringTokenizer tok = new StringTokenizer(obj.toString(), "\n");
    636         StringBuffer buf = new StringBuffer();
    637         while (tok.hasMoreTokens()) {
    638             buf.append("\t").append(tok.nextToken()).append("\n");
    639         }
    640         return buf.toString();
    641     }
    642
    643
    644     /***
    645      * @return deep copy of this class
    646      */
    647     public JavaClass copy() {
    648         JavaClass c = null;
    649         try {
    650             c = (JavaClass) clone();
    651             c.constant_pool = constant_pool.copy();
    652             c.interfaces = (int[]) interfaces.clone();
    653             c.interface_names = (String[]) interface_names.clone();
    654             c.fields = new Field[fields.length];
    655             for (int i = 0; i < fields.length; i++) {
    656                 c.fields[i] = fields[i].copy(c.constant_pool);
    657             }
    658             c.methods = new Method[methods.length];
    659             for (int i = 0; i < methods.length; i++) {
    660                 c.methods[i] = methods[i].copy(c.constant_pool);
    661             }
    662             c.attributes = new Attribute[attributes.length];
    663             for (int i = 0; i < attributes.length; i++) {
    664                 c.attributes[i] = attributes[i].copy(c.constant_pool);
    665             }
    666         } catch (CloneNotSupportedException e) {
    667         }
    668         return c;
    669     }
    670
    671
    672     public final boolean isSuper() {
    673         return (access_flags & Constants.ACC_SUPER) != 0;
    674     }
    675
    676
    677     public final boolean isClass() {
    678         return (access_flags & Constants.ACC_INTERFACE) == 0;
    679     }
    680
    681
    682     /*** @return returns either HEAP (generated), FILE, or ZIP
    683      */
    684     public final byte getSource() {
    685         return source;
    686     }
    687
    688
    689     /********************** New repository functionality *********************/
    690     /***
    691      * Gets the ClassRepository which holds its definition. By default
    692      * this is the same as SyntheticRepository.getInstance();
    693      */
    694     public org.apache.bcel.util.Repository getRepository() {
    695         return repository;
    696     }
    697
    698
    699     /***
    700      * Sets the ClassRepository which loaded the JavaClass.
    701      * Should be called immediately after parsing is done.
    702      */
    703     public void setRepository( org.apache.bcel.util.Repository repository ) {
    704         this.repository = repository;
    705     }
    706
    707
    708     /*** Equivalent to runtime "instanceof" operator.
    709      *
    710      * @return true if this JavaClass is derived from the super class
    711      * @throws ClassNotFoundException if superclasses or superinterfaces
    712      *   of this object can't be found
    713      */
    714     public final boolean instanceOf( JavaClass super_class ) throws ClassNotFoundException {
    715         if (this.equals(super_class)) {
    716             return true;
    717         }
    718         JavaClass[] super_classes = getSuperClasses();
    719         for (int i = 0; i < super_classes.length; i++) {
    720             if (super_classes[i].equals(super_class)) {
    721                 return true;
    722             }
    723         }
    724         if (super_class.isInterface()) {
    725             return implementationOf(super_class);
    726         }
    727         return false;
    728     }
    729
    730
    731     /***
    732      * @return true, if this class is an implementation of interface inter
    733      * @throws ClassNotFoundException if superclasses or superinterfaces
    734      *   of this class can't be found
    735      */
    736     public boolean implementationOf( JavaClass inter ) throws ClassNotFoundException {
    737         if (!inter.isInterface()) {
    738             throw new IllegalArgumentException(inter.getClassName() + " is no interface");
    739         }
    740         if (this.equals(inter)) {
    741             return true;
    742         }
    743         JavaClass[] super_interfaces = getAllInterfaces();
    744         for (int i = 0; i < super_interfaces.length; i++) {
    745             if (super_interfaces[i].equals(inter)) {
    746                 return true;
    747             }
    748         }
    749         return false;
    750     }
    751
    752
    753     /***
    754      * @return the superclass for this JavaClass object, or null if this
    755      * is java.lang.Object
    756      * @throws ClassNotFoundException if the superclass can't be found
    757      */
    758     public JavaClass getSuperClass() throws ClassNotFoundException {
    759         if ("java.lang.Object".equals(getClassName())) {
    760             return null;
    761         }
    762         return repository.loadClass(getSuperclassName());
    763     }
    764
    765
    766     /***
    767      * @return list of super classes of this class in ascending order, i.e.,
    768      * java.lang.Object is always the last element
    769      * @throws ClassNotFoundException if any of the superclasses can't be found
    770      */
    771     public JavaClass[] getSuperClasses() throws ClassNotFoundException {
    772         JavaClass clazz = this;
    773         List allSuperClasses = new ArrayList();
    774         for (clazz = clazz.getSuperClass(); clazz != null; clazz = clazz.getSuperClass()) {
    775             allSuperClasses.add(clazz);
    776         }
    777         return (JavaClass[]) allSuperClasses.toArray(new JavaClass[allSuperClasses.size()]);
    778     }
    779
    780
    781     /***
    782      * Get interfaces directly implemented by this JavaClass.
    783      */
    784     public JavaClass[] getInterfaces() throws ClassNotFoundException {
    785         String[] _interfaces = getInterfaceNames();
    786         JavaClass[] classes = new JavaClass[_interfaces.length];
    787         for (int i = 0; i < _interfaces.length; i++) {
    788             classes[i] = repository.loadClass(_interfaces[i]);
    789         }
    790         return classes;
    791     }
    792
    793
    794     /***
    795      * Get all interfaces implemented by this JavaClass (transitively).
    796      */
    797     public JavaClass[] getAllInterfaces() throws ClassNotFoundException {
    798         ClassQueue queue = new ClassQueue();
    799         Set allInterfaces = new TreeSet();
    800         queue.enqueue(this);
    801         while (!queue.empty()) {
    802             JavaClass clazz = queue.dequeue();
    803             JavaClass souper = clazz.getSuperClass();
    804             JavaClass[] _interfaces = clazz.getInterfaces();
    805             if (clazz.isInterface()) {
    806                 allInterfaces.add(clazz);
    807             } else {
    808                 if (souper != null) {
    809                     queue.enqueue(souper);
    810                 }
    811             }
    812             for (int i = 0; i < _interfaces.length; i++) {
    813                 queue.enqueue(_interfaces[i]);
    814             }
    815         }
    816         return (JavaClass[]) allInterfaces.toArray(new JavaClass[allInterfaces.size()]);
    817     }
    818
    819
    820     /***
    821      * @return Comparison strategy object
    822      */
    823     public static BCELComparator getComparator() {
    824         return _cmp;
    825     }
    826
    827
    828     /***
    829      * @param comparator Comparison strategy object
    830      */
    831     public static void setComparator( BCELComparator comparator ) {
    832         _cmp = comparator;
    833     }
    834
    835
    836     /***
    837      * Return value as defined by given BCELComparator strategy.
    838      * By default two JavaClass objects are said to be equal when
    839      * their class names are equal.
    840      *
    841      * @see java.lang.Object#equals(java.lang.Object)
    842      */
    843     public boolean equals( Object obj ) {
    844         return _cmp.equals(this, obj);
    845     }
    846
    847
    848     /***
    849      * Return the natural ordering of two JavaClasses.
    850      * This ordering is based on the class name
    851      */
    852     public int compareTo( Object obj ) {
    853         return getClassName().compareTo(((JavaClass) obj).getClassName());
    854     }
    855
    856
    857     /***
    858      * Return value as defined by given BCELComparator strategy.
    859      * By default return the hashcode of the class name.
    860      *
    861      * @see java.lang.Object#hashCode()
    862      */
    863     public int hashCode() {
    864         return _cmp.hashCode(this);
    865     }
    866 }