jaxp/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/ClassGen.java
changeset 46174 5611d2529b49
parent 44797 8b3b3b911b8a
equal deleted inserted replaced
46173:5546b5710844 46174:5611d2529b49
    16  * distributed under the License is distributed on an "AS IS" BASIS,
    16  * distributed under the License is distributed on an "AS IS" BASIS,
    17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    18  * See the License for the specific language governing permissions and
    18  * See the License for the specific language governing permissions and
    19  * limitations under the License.
    19  * limitations under the License.
    20  */
    20  */
    21 
       
    22 package com.sun.org.apache.bcel.internal.generic;
    21 package com.sun.org.apache.bcel.internal.generic;
    23 
    22 
    24 
       
    25 import com.sun.org.apache.bcel.internal.Constants;
       
    26 import com.sun.org.apache.bcel.internal.classfile.*;
       
    27 import java.util.ArrayList;
    23 import java.util.ArrayList;
    28 import java.util.Iterator;
    24 import java.util.List;
       
    25 
       
    26 import com.sun.org.apache.bcel.internal.Const;
       
    27 import com.sun.org.apache.bcel.internal.classfile.AccessFlags;
       
    28 import com.sun.org.apache.bcel.internal.classfile.AnnotationEntry;
       
    29 import com.sun.org.apache.bcel.internal.classfile.Annotations;
       
    30 import com.sun.org.apache.bcel.internal.classfile.Attribute;
       
    31 import com.sun.org.apache.bcel.internal.classfile.ConstantPool;
       
    32 import com.sun.org.apache.bcel.internal.classfile.Field;
       
    33 import com.sun.org.apache.bcel.internal.classfile.JavaClass;
       
    34 import com.sun.org.apache.bcel.internal.classfile.Method;
       
    35 import com.sun.org.apache.bcel.internal.classfile.RuntimeInvisibleAnnotations;
       
    36 import com.sun.org.apache.bcel.internal.classfile.RuntimeVisibleAnnotations;
       
    37 import com.sun.org.apache.bcel.internal.classfile.SourceFile;
       
    38 import com.sun.org.apache.bcel.internal.util.BCELComparator;
    29 
    39 
    30 /**
    40 /**
    31  * Template class for building up a java class. May be initialized with an
    41  * Template class for building up a java class. May be initialized with an
    32  * existing java class (file).
    42  * existing java class (file).
    33  *
    43  *
    34  * @see JavaClass
    44  * @see JavaClass
    35  * @author  <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
    45  * @version $Id: ClassGen.java 1749603 2016-06-21 20:50:19Z ggregory $
    36  */
    46  */
    37 public class ClassGen extends AccessFlags implements Cloneable {
    47 public class ClassGen extends AccessFlags implements Cloneable {
    38   /* Corresponds to the fields found in a JavaClass object.
    48 
    39    */
    49     /* Corresponds to the fields found in a JavaClass object.
    40   private String   class_name, super_class_name, file_name;
    50      */
    41   private int      class_name_index = -1, superclass_name_index = -1;
    51     private String class_name;
    42   private int      major = Constants.MAJOR_1_1, minor = Constants.MINOR_1_1;
    52     private String super_class_name;
    43 
    53     private final String file_name;
    44   private ConstantPoolGen cp; // Template for building up constant pool
    54     private int class_name_index = -1;
    45 
    55     private int superclass_name_index = -1;
    46   // ArrayLists instead of arrays to gather fields, methods, etc.
    56     private int major = Const.MAJOR;
    47   private ArrayList   field_vec     = new ArrayList();
    57     private int minor = Const.MINOR;
    48   private ArrayList   method_vec    = new ArrayList();
    58     private ConstantPoolGen cp; // Template for building up constant pool
    49   private ArrayList   attribute_vec = new ArrayList();
    59     // ArrayLists instead of arrays to gather fields, methods, etc.
    50   private ArrayList   interface_vec = new ArrayList();
    60     private final List<Field> field_vec = new ArrayList<>();
    51 
    61     private final List<Method> method_vec = new ArrayList<>();
    52   /** Convenience constructor to set up some important values initially.
    62     private final List<Attribute> attribute_vec = new ArrayList<>();
    53    *
    63     private final List<String> interface_vec = new ArrayList<>();
    54    * @param class_name fully qualified class name
    64     private final List<AnnotationEntryGen> annotation_vec = new ArrayList<>();
    55    * @param super_class_name fully qualified superclass name
    65 
    56    * @param file_name source file name
    66     private static BCELComparator _cmp = new BCELComparator() {
    57    * @param access_flags access qualifiers
    67 
    58    * @param interfaces implemented interfaces
    68         @Override
    59    * @param cp constant pool to use
    69         public boolean equals(final Object o1, final Object o2) {
    60    */
    70             final ClassGen THIS = (ClassGen) o1;
    61   public ClassGen(String class_name, String super_class_name, String file_name,
    71             final ClassGen THAT = (ClassGen) o2;
    62                   int access_flags, String[] interfaces, ConstantPoolGen cp) {
    72             return THIS.getClassName().equals(THAT.getClassName());
    63     this.class_name       = class_name;
    73         }
    64     this.super_class_name = super_class_name;
    74 
    65     this.file_name        = file_name;
    75         @Override
    66     this.access_flags     = access_flags;
    76         public int hashCode(final Object o) {
    67     this.cp               = cp;
    77             final ClassGen THIS = (ClassGen) o;
    68 
    78             return THIS.getClassName().hashCode();
    69     // Put everything needed by default into the constant pool and the vectors
    79         }
    70     if(file_name != null)
    80     };
    71       addAttribute(new SourceFile(cp.addUtf8("SourceFile"), 2,
    81 
    72                                   cp.addUtf8(file_name), cp.getConstantPool()));
    82     /**
    73 
    83      * Convenience constructor to set up some important values initially.
    74     class_name_index      = cp.addClass(class_name);
    84      *
    75     superclass_name_index = cp.addClass(super_class_name);
    85      * @param class_name fully qualified class name
    76 
    86      * @param super_class_name fully qualified superclass name
    77     if(interfaces != null)
    87      * @param file_name source file name
    78       for(int i=0; i < interfaces.length; i++)
    88      * @param access_flags access qualifiers
    79         addInterface(interfaces[i]);
    89      * @param interfaces implemented interfaces
    80   }
    90      * @param cp constant pool to use
    81 
    91      */
    82   /** Convenience constructor to set up some important values initially.
    92     public ClassGen(final String class_name, final String super_class_name, final String file_name, final int access_flags,
    83    *
    93             final String[] interfaces, final ConstantPoolGen cp) {
    84    * @param class_name fully qualified class name
    94         super(access_flags);
    85    * @param super_class_name fully qualified superclass name
    95         this.class_name = class_name;
    86    * @param file_name source file name
    96         this.super_class_name = super_class_name;
    87    * @param access_flags access qualifiers
    97         this.file_name = file_name;
    88    * @param interfaces implemented interfaces
    98         this.cp = cp;
    89    */
    99         // Put everything needed by default into the constant pool and the vectors
    90   public ClassGen(String class_name, String super_class_name, String file_name,
   100         if (file_name != null) {
    91                   int access_flags, String[] interfaces) {
   101             addAttribute(new SourceFile(cp.addUtf8("SourceFile"), 2, cp.addUtf8(file_name), cp
    92     this(class_name, super_class_name, file_name, access_flags, interfaces,
   102                     .getConstantPool()));
    93          new ConstantPoolGen());
   103         }
    94   }
   104         class_name_index = cp.addClass(class_name);
    95 
   105         superclass_name_index = cp.addClass(super_class_name);
    96   /**
   106         if (interfaces != null) {
    97    * Initialize with existing class.
   107             for (final String interface1 : interfaces) {
    98    * @param clazz JavaClass object (e.g. read from file)
   108                 addInterface(interface1);
    99    */
   109             }
   100   public ClassGen(JavaClass clazz) {
   110         }
   101     class_name_index      = clazz.getClassNameIndex();
   111     }
   102     superclass_name_index = clazz.getSuperclassNameIndex();
   112 
   103     class_name            = clazz.getClassName();
   113     /**
   104     super_class_name      = clazz.getSuperclassName();
   114      * Convenience constructor to set up some important values initially.
   105     file_name             = clazz.getSourceFileName();
   115      *
   106     access_flags          = clazz.getAccessFlags();
   116      * @param class_name fully qualified class name
   107     cp                    = new ConstantPoolGen(clazz.getConstantPool());
   117      * @param super_class_name fully qualified superclass name
   108     major                 = clazz.getMajor();
   118      * @param file_name source file name
   109     minor                 = clazz.getMinor();
   119      * @param access_flags access qualifiers
   110 
   120      * @param interfaces implemented interfaces
   111     Attribute[] attributes = clazz.getAttributes();
   121      */
   112     Method[]    methods    = clazz.getMethods();
   122     public ClassGen(final String class_name, final String super_class_name, final String file_name, final int access_flags,
   113     Field[]     fields     = clazz.getFields();
   123             final String[] interfaces) {
   114     String[]    interfaces = clazz.getInterfaceNames();
   124         this(class_name, super_class_name, file_name, access_flags, interfaces,
   115 
   125                 new ConstantPoolGen());
   116     for(int i=0; i < interfaces.length; i++)
   126     }
   117       addInterface(interfaces[i]);
   127 
   118 
   128     /**
   119     for(int i=0; i < attributes.length; i++)
   129      * Initialize with existing class.
   120       addAttribute(attributes[i]);
   130      *
   121 
   131      * @param clazz JavaClass object (e.g. read from file)
   122     for(int i=0; i < methods.length; i++)
   132      */
   123       addMethod(methods[i]);
   133     public ClassGen(final JavaClass clazz) {
   124 
   134         super(clazz.getAccessFlags());
   125     for(int i=0; i < fields.length; i++)
   135         class_name_index = clazz.getClassNameIndex();
   126       addField(fields[i]);
   136         superclass_name_index = clazz.getSuperclassNameIndex();
   127   }
   137         class_name = clazz.getClassName();
   128 
   138         super_class_name = clazz.getSuperclassName();
   129   /**
   139         file_name = clazz.getSourceFileName();
   130    * @return the (finally) built up Java class object.
   140         cp = new ConstantPoolGen(clazz.getConstantPool());
   131    */
   141         major = clazz.getMajor();
   132   public JavaClass getJavaClass() {
   142         minor = clazz.getMinor();
   133     int[]        interfaces = getInterfaces();
   143         final Attribute[] attributes = clazz.getAttributes();
   134     Field[]      fields     = getFields();
   144         // J5TODO: Could make unpacking lazy, done on first reference
   135     Method[]     methods    = getMethods();
   145         final AnnotationEntryGen[] annotations = unpackAnnotations(attributes);
   136     Attribute[]  attributes = getAttributes();
   146         final Method[] methods = clazz.getMethods();
   137 
   147         final Field[] fields = clazz.getFields();
   138     // Must be last since the above calls may still add something to it
   148         final String[] interfaces = clazz.getInterfaceNames();
   139     ConstantPool cp         = this.cp.getFinalConstantPool();
   149         for (final String interface1 : interfaces) {
   140 
   150             addInterface(interface1);
   141     return new JavaClass(class_name_index, superclass_name_index,
   151         }
   142                          file_name, major, minor, access_flags,
   152         for (final Attribute attribute : attributes) {
   143                          cp, interfaces, fields, methods, attributes);
   153             if (!(attribute instanceof Annotations)) {
   144   }
   154                 addAttribute(attribute);
   145 
   155             }
   146   /**
   156         }
   147    * Add an interface to this class, i.e., this class has to implement it.
   157         for (final AnnotationEntryGen annotation : annotations) {
   148    * @param name interface to implement (fully qualified class name)
   158             addAnnotationEntry(annotation);
   149    */
   159         }
   150   public void addInterface(String name) {
   160         for (final Method method : methods) {
   151     interface_vec.add(name);
   161             addMethod(method);
   152   }
   162         }
   153 
   163         for (final Field field : fields) {
   154   /**
   164             addField(field);
   155    * Remove an interface from this class.
   165         }
   156    * @param name interface to remove (fully qualified name)
   166     }
   157    */
   167 
   158   public void removeInterface(String name) {
   168     /**
   159     interface_vec.remove(name);
   169      * Look for attributes representing annotations and unpack them.
   160   }
   170      */
   161 
   171     private AnnotationEntryGen[] unpackAnnotations(final Attribute[] attrs) {
   162   /**
   172         final List<AnnotationEntryGen> annotationGenObjs = new ArrayList<>();
   163    * @return major version number of class file
   173         for (final Attribute attr : attrs) {
   164    */
   174             if (attr instanceof RuntimeVisibleAnnotations) {
   165   public int  getMajor()      { return major; }
   175                 final RuntimeVisibleAnnotations rva = (RuntimeVisibleAnnotations) attr;
   166 
   176                 final AnnotationEntry[] annos = rva.getAnnotationEntries();
   167   /** Set major version number of class file, default value is 45 (JDK 1.1)
   177                 for (final AnnotationEntry a : annos) {
   168    * @param major major version number
   178                     annotationGenObjs.add(new AnnotationEntryGen(a,
   169    */
   179                             getConstantPool(), false));
   170   public void setMajor(int major) {
   180                 }
   171     this.major = major;
   181             } else if (attr instanceof RuntimeInvisibleAnnotations) {
   172   }
   182                 final RuntimeInvisibleAnnotations ria = (RuntimeInvisibleAnnotations) attr;
   173 
   183                 final AnnotationEntry[] annos = ria.getAnnotationEntries();
   174   /** Set minor version number of class file, default value is 3 (JDK 1.1)
   184                 for (final AnnotationEntry a : annos) {
   175    * @param minor minor version number
   185                     annotationGenObjs.add(new AnnotationEntryGen(a,
   176    */
   186                             getConstantPool(), false));
   177   public void setMinor(int minor) {
   187                 }
   178     this.minor = minor;
   188             }
   179   }
   189         }
   180 
   190         return annotationGenObjs.toArray(new AnnotationEntryGen[annotationGenObjs.size()]);
   181   /**
   191     }
   182    * @return minor version number of class file
   192 
   183    */
   193     /**
   184   public int  getMinor()      { return minor; }
   194      * @return the (finally) built up Java class object.
   185 
   195      */
   186   /**
   196     public JavaClass getJavaClass() {
   187    * Add an attribute to this class.
   197         final int[] interfaces = getInterfaces();
   188    * @param a attribute to add
   198         final Field[] fields = getFields();
   189    */
   199         final Method[] methods = getMethods();
   190   public void addAttribute(Attribute a)    { attribute_vec.add(a); }
   200         Attribute[] attributes;
   191 
   201         if (annotation_vec.isEmpty()) {
   192   /**
   202             attributes = getAttributes();
   193    * Add a method to this class.
   203         } else {
   194    * @param m method to add
   204             // TODO: Sometime later, trash any attributes called 'RuntimeVisibleAnnotations' or 'RuntimeInvisibleAnnotations'
   195    */
   205             final Attribute[] annAttributes = AnnotationEntryGen.getAnnotationAttributes(cp, getAnnotationEntries());
   196   public void addMethod(Method m)          { method_vec.add(m); }
   206             attributes = new Attribute[attribute_vec.size() + annAttributes.length];
   197 
   207             attribute_vec.toArray(attributes);
   198   /**
   208             System.arraycopy(annAttributes, 0, attributes, attribute_vec.size(), annAttributes.length);
   199    * Convenience method.
   209         }
   200    *
   210         // Must be last since the above calls may still add something to it
   201    * Add an empty constructor to this class that does nothing but calling super().
   211         final ConstantPool _cp = this.cp.getFinalConstantPool();
   202    * @param access rights for constructor
   212         return new JavaClass(class_name_index, superclass_name_index, file_name, major, minor,
   203    */
   213                 super.getAccessFlags(), _cp, interfaces, fields, methods, attributes);
   204   public void addEmptyConstructor(int access_flags) {
   214     }
   205     InstructionList il = new InstructionList();
   215 
   206     il.append(InstructionConstants.THIS); // Push `this'
   216     /**
   207     il.append(new INVOKESPECIAL(cp.addMethodref(super_class_name,
   217      * Add an interface to this class, i.e., this class has to implement it.
   208                                                 "<init>", "()V")));
   218      *
   209     il.append(InstructionConstants.RETURN);
   219      * @param name interface to implement (fully qualified class name)
   210 
   220      */
   211     MethodGen mg = new MethodGen(access_flags, Type.VOID, Type.NO_ARGS, null,
   221     public final void addInterface(final String name) {
   212                        "<init>", class_name, il, cp);
   222         interface_vec.add(name);
   213     mg.setMaxStack(1);
   223     }
   214     addMethod(mg.getMethod());
   224 
   215   }
   225     /**
   216 
   226      * Remove an interface from this class.
   217   /**
   227      *
   218    * Add a field to this class.
   228      * @param name interface to remove (fully qualified name)
   219    * @param f field to add
   229      */
   220    */
   230     public void removeInterface(final String name) {
   221   public void addField(Field f)            { field_vec.add(f); }
   231         interface_vec.remove(name);
   222 
   232     }
   223   public boolean containsField(Field f)    { return field_vec.contains(f); }
   233 
   224 
   234     /**
   225   /** @return field object with given name, or null
   235      * @return major version number of class file
   226    */
   236      */
   227   public Field containsField(String name) {
   237     public int getMajor() {
   228     for(Iterator e=field_vec.iterator(); e.hasNext(); ) {
   238         return major;
   229       Field f = (Field)e.next();
   239     }
   230       if(f.getName().equals(name))
   240 
   231         return f;
   241     /**
   232     }
   242      * Set major version number of class file, default value is 45 (JDK 1.1)
   233 
   243      *
   234     return null;
   244      * @param major major version number
   235   }
   245      */
   236 
   246     public void setMajor(final int major) { // TODO could be package-protected - only called by test code
   237   /** @return method object with given name and signature, or null
   247         this.major = major;
   238    */
   248     }
   239   public Method containsMethod(String name, String signature) {
   249 
   240     for(Iterator e=method_vec.iterator(); e.hasNext();) {
   250     /**
   241       Method m = (Method)e.next();
   251      * Set minor version number of class file, default value is 3 (JDK 1.1)
   242       if(m.getName().equals(name) && m.getSignature().equals(signature))
   252      *
   243         return m;
   253      * @param minor minor version number
   244     }
   254      */
   245 
   255     public void setMinor(final int minor) {  // TODO could be package-protected - only called by test code
   246     return null;
   256         this.minor = minor;
   247   }
   257     }
   248 
   258 
   249   /**
   259     /**
   250    * Remove an attribute from this class.
   260      * @return minor version number of class file
   251    * @param a attribute to remove
   261      */
   252    */
   262     public int getMinor() {
   253   public void removeAttribute(Attribute a) { attribute_vec.remove(a); }
   263         return minor;
   254 
   264     }
   255   /**
   265 
   256    * Remove a method from this class.
   266     /**
   257    * @param m method to remove
   267      * Add an attribute to this class.
   258    */
   268      *
   259   public void removeMethod(Method m)       { method_vec.remove(m); }
   269      * @param a attribute to add
   260 
   270      */
   261   /** Replace given method with new one. If the old one does not exist
   271     public final void addAttribute(final Attribute a) {
   262    * add the new_ method to the class anyway.
   272         attribute_vec.add(a);
   263    */
   273     }
   264   public void replaceMethod(Method old, Method new_) {
   274 
   265     if(new_ == null)
   275     public final void addAnnotationEntry(final AnnotationEntryGen a) {
   266       throw new ClassGenException("Replacement method must not be null");
   276         annotation_vec.add(a);
   267 
   277     }
   268     int i = method_vec.indexOf(old);
   278 
   269 
   279     /**
   270     if(i < 0)
   280      * Add a method to this class.
   271       method_vec.add(new_);
   281      *
   272     else
   282      * @param m method to add
   273       method_vec.set(i, new_);
   283      */
   274   }
   284     public final void addMethod(final Method m) {
   275 
   285         method_vec.add(m);
   276   /** Replace given field with new one. If the old one does not exist
   286     }
   277    * add the new_ field to the class anyway.
   287 
   278    */
   288     /**
   279   public void replaceField(Field old, Field new_) {
   289      * Convenience method.
   280     if(new_ == null)
   290      *
   281       throw new ClassGenException("Replacement method must not be null");
   291      * Add an empty constructor to this class that does nothing but calling
   282 
   292      * super().
   283     int i = field_vec.indexOf(old);
   293      *
   284 
   294      * @param access_flags rights for constructor
   285     if(i < 0)
   295      */
   286       field_vec.add(new_);
   296     public void addEmptyConstructor(final int access_flags) {
   287     else
   297         final InstructionList il = new InstructionList();
   288       field_vec.set(i, new_);
   298         il.append(InstructionConst.THIS); // Push `this'
   289   }
   299         il.append(new INVOKESPECIAL(cp.addMethodref(super_class_name, "<init>", "()V")));
   290 
   300         il.append(InstructionConst.RETURN);
   291   /**
   301         final MethodGen mg = new MethodGen(access_flags, Type.VOID, Type.NO_ARGS, null, "<init>",
   292    * Remove a field to this class.
   302                 class_name, il, cp);
   293    * @param f field to remove
   303         mg.setMaxStack(1);
   294    */
   304         addMethod(mg.getMethod());
   295   public void removeField(Field f)         { field_vec.remove(f); }
   305     }
   296 
   306 
   297   public String getClassName()      { return class_name; }
   307     /**
   298   public String getSuperclassName() { return super_class_name; }
   308      * Add a field to this class.
   299   public String getFileName()       { return file_name; }
   309      *
   300 
   310      * @param f field to add
   301   public void setClassName(String name) {
   311      */
   302     class_name = name.replace('/', '.');
   312     public final void addField(final Field f) {
   303     class_name_index = cp.addClass(name);
   313         field_vec.add(f);
   304   }
   314     }
   305 
   315 
   306   public void setSuperclassName(String name) {
   316     public boolean containsField(final Field f) {
   307     super_class_name = name.replace('/', '.');
   317         return field_vec.contains(f);
   308     superclass_name_index = cp.addClass(name);
   318     }
   309   }
   319 
   310 
   320     /**
   311   public Method[] getMethods() {
   321      * @return field object with given name, or null
   312     Method[] methods = new Method[method_vec.size()];
   322      */
   313     method_vec.toArray(methods);
   323     public Field containsField(final String name) {
   314     return methods;
   324         for (final Field f : field_vec) {
   315   }
   325             if (f.getName().equals(name)) {
   316 
   326                 return f;
   317   public void setMethods(Method[] methods) {
   327             }
   318     method_vec.clear();
   328         }
   319     for(int m=0; m<methods.length; m++)
   329         return null;
   320       addMethod(methods[m]);
   330     }
   321   }
   331 
   322 
   332     /**
   323   public void setMethodAt(Method method, int pos) {
   333      * @return method object with given name and signature, or null
   324     method_vec.set(pos, method);
   334      */
   325   }
   335     public Method containsMethod(final String name, final String signature) {
   326 
   336         for (final Method m : method_vec) {
   327   public Method getMethodAt(int pos) {
   337             if (m.getName().equals(name) && m.getSignature().equals(signature)) {
   328     return (Method)method_vec.get(pos);
   338                 return m;
   329   }
   339             }
   330 
   340         }
   331   public String[] getInterfaceNames() {
   341         return null;
   332     int      size = interface_vec.size();
   342     }
   333     String[] interfaces = new String[size];
   343 
   334 
   344     /**
   335     interface_vec.toArray(interfaces);
   345      * Remove an attribute from this class.
   336     return interfaces;
   346      *
   337   }
   347      * @param a attribute to remove
   338 
   348      */
   339   public int[] getInterfaces() {
   349     public void removeAttribute(final Attribute a) {
   340     int   size = interface_vec.size();
   350         attribute_vec.remove(a);
   341     int[] interfaces = new int[size];
   351     }
   342 
   352 
   343     for(int i=0; i < size; i++)
   353     /**
   344       interfaces[i] = cp.addClass((String)interface_vec.get(i));
   354      * Remove a method from this class.
   345 
   355      *
   346     return interfaces;
   356      * @param m method to remove
   347   }
   357      */
   348 
   358     public void removeMethod(final Method m) {
   349   public Field[] getFields() {
   359         method_vec.remove(m);
   350     Field[] fields = new Field[field_vec.size()];
   360     }
   351     field_vec.toArray(fields);
   361 
   352     return fields;
   362     /**
   353   }
   363      * Replace given method with new one. If the old one does not exist add the
   354 
   364      * new_ method to the class anyway.
   355   public Attribute[] getAttributes() {
   365      */
   356     Attribute[] attributes = new Attribute[attribute_vec.size()];
   366     public void replaceMethod(final Method old, final Method new_) {
   357     attribute_vec.toArray(attributes);
   367         if (new_ == null) {
   358     return attributes;
   368             throw new ClassGenException("Replacement method must not be null");
   359   }
   369         }
   360 
   370         final int i = method_vec.indexOf(old);
   361   public ConstantPoolGen getConstantPool() { return cp; }
   371         if (i < 0) {
   362   public void setConstantPool(ConstantPoolGen constant_pool) {
   372             method_vec.add(new_);
   363     cp = constant_pool;
   373         } else {
   364   }
   374             method_vec.set(i, new_);
   365 
   375         }
   366   public void setClassNameIndex(int class_name_index) {
   376     }
   367     this.class_name_index = class_name_index;
   377 
   368     class_name = cp.getConstantPool().
   378     /**
   369       getConstantString(class_name_index, Constants.CONSTANT_Class).replace('/', '.');
   379      * Replace given field with new one. If the old one does not exist add the
   370   }
   380      * new_ field to the class anyway.
   371 
   381      */
   372   public void setSuperclassNameIndex(int superclass_name_index) {
   382     public void replaceField(final Field old, final Field new_) {
   373     this.superclass_name_index = superclass_name_index;
   383         if (new_ == null) {
   374     super_class_name = cp.getConstantPool().
   384             throw new ClassGenException("Replacement method must not be null");
   375       getConstantString(superclass_name_index, Constants.CONSTANT_Class).replace('/', '.');
   385         }
   376   }
   386         final int i = field_vec.indexOf(old);
   377 
   387         if (i < 0) {
   378   public int getSuperclassNameIndex() { return superclass_name_index; }
   388             field_vec.add(new_);
   379 
   389         } else {
   380   public int getClassNameIndex()   { return class_name_index; }
   390             field_vec.set(i, new_);
   381 
   391         }
   382   private ArrayList observers;
   392     }
   383 
   393 
   384   /** Add observer for this object.
   394     /**
   385    */
   395      * Remove a field to this class.
   386   public void addObserver(ClassObserver o) {
   396      *
   387     if(observers == null)
   397      * @param f field to remove
   388       observers = new ArrayList();
   398      */
   389 
   399     public void removeField(final Field f) {
   390     observers.add(o);
   400         field_vec.remove(f);
   391   }
   401     }
   392 
   402 
   393   /** Remove observer for this object.
   403     public String getClassName() {
   394    */
   404         return class_name;
   395   public void removeObserver(ClassObserver o) {
   405     }
   396     if(observers != null)
   406 
   397       observers.remove(o);
   407     public String getSuperclassName() {
   398   }
   408         return super_class_name;
   399 
   409     }
   400   /** Call notify() method on all observers. This method is not called
   410 
   401    * automatically whenever the state has changed, but has to be
   411     public String getFileName() {
   402    * called by the user after he has finished editing the object.
   412         return file_name;
   403    */
   413     }
   404   public void update() {
   414 
   405     if(observers != null)
   415     public void setClassName(final String name) {
   406       for(Iterator e = observers.iterator(); e.hasNext(); )
   416         class_name = name.replace('/', '.');
   407         ((ClassObserver)e.next()).notify(this);
   417         class_name_index = cp.addClass(name);
   408   }
   418     }
   409 
   419 
   410   public Object clone() {
   420     public void setSuperclassName(final String name) {
   411     try {
   421         super_class_name = name.replace('/', '.');
   412       return super.clone();
   422         superclass_name_index = cp.addClass(name);
   413     } catch(CloneNotSupportedException e) {
   423     }
   414       System.err.println(e);
   424 
   415       return null;
   425     public Method[] getMethods() {
   416     }
   426         return method_vec.toArray(new Method[method_vec.size()]);
   417   }
   427     }
       
   428 
       
   429     public void setMethods(final Method[] methods) {
       
   430         method_vec.clear();
       
   431         for (final Method method : methods) {
       
   432             addMethod(method);
       
   433         }
       
   434     }
       
   435 
       
   436     public void setMethodAt(final Method method, final int pos) {
       
   437         method_vec.set(pos, method);
       
   438     }
       
   439 
       
   440     public Method getMethodAt(final int pos) {
       
   441         return method_vec.get(pos);
       
   442     }
       
   443 
       
   444     public String[] getInterfaceNames() {
       
   445         final int size = interface_vec.size();
       
   446         final String[] interfaces = new String[size];
       
   447         interface_vec.toArray(interfaces);
       
   448         return interfaces;
       
   449     }
       
   450 
       
   451     public int[] getInterfaces() {
       
   452         final int size = interface_vec.size();
       
   453         final int[] interfaces = new int[size];
       
   454         for (int i = 0; i < size; i++) {
       
   455             interfaces[i] = cp.addClass(interface_vec.get(i));
       
   456         }
       
   457         return interfaces;
       
   458     }
       
   459 
       
   460     public Field[] getFields() {
       
   461         return field_vec.toArray(new Field[field_vec.size()]);
       
   462     }
       
   463 
       
   464     public Attribute[] getAttributes() {
       
   465         return attribute_vec.toArray(new Attribute[attribute_vec.size()]);
       
   466     }
       
   467 
       
   468     //  J5TODO: Should we make calling unpackAnnotations() lazy and put it in here?
       
   469     public AnnotationEntryGen[] getAnnotationEntries() {
       
   470         return annotation_vec.toArray(new AnnotationEntryGen[annotation_vec.size()]);
       
   471     }
       
   472 
       
   473     public ConstantPoolGen getConstantPool() {
       
   474         return cp;
       
   475     }
       
   476 
       
   477     public void setConstantPool(final ConstantPoolGen constant_pool) {
       
   478         cp = constant_pool;
       
   479     }
       
   480 
       
   481     public void setClassNameIndex(final int class_name_index) {
       
   482         this.class_name_index = class_name_index;
       
   483         class_name = cp.getConstantPool().getConstantString(class_name_index,
       
   484                 Const.CONSTANT_Class).replace('/', '.');
       
   485     }
       
   486 
       
   487     public void setSuperclassNameIndex(final int superclass_name_index) {
       
   488         this.superclass_name_index = superclass_name_index;
       
   489         super_class_name = cp.getConstantPool().getConstantString(superclass_name_index,
       
   490                 Const.CONSTANT_Class).replace('/', '.');
       
   491     }
       
   492 
       
   493     public int getSuperclassNameIndex() {
       
   494         return superclass_name_index;
       
   495     }
       
   496 
       
   497     public int getClassNameIndex() {
       
   498         return class_name_index;
       
   499     }
       
   500 
       
   501     private List<ClassObserver> observers;
       
   502 
       
   503     /**
       
   504      * Add observer for this object.
       
   505      */
       
   506     public void addObserver(final ClassObserver o) {
       
   507         if (observers == null) {
       
   508             observers = new ArrayList<>();
       
   509         }
       
   510         observers.add(o);
       
   511     }
       
   512 
       
   513     /**
       
   514      * Remove observer for this object.
       
   515      */
       
   516     public void removeObserver(final ClassObserver o) {
       
   517         if (observers != null) {
       
   518             observers.remove(o);
       
   519         }
       
   520     }
       
   521 
       
   522     /**
       
   523      * Call notify() method on all observers. This method is not called
       
   524      * automatically whenever the state has changed, but has to be called by the
       
   525      * user after he has finished editing the object.
       
   526      */
       
   527     public void update() {
       
   528         if (observers != null) {
       
   529             for (final ClassObserver observer : observers) {
       
   530                 observer.notify(this);
       
   531             }
       
   532         }
       
   533     }
       
   534 
       
   535     @Override
       
   536     public Object clone() {
       
   537         try {
       
   538             return super.clone();
       
   539         } catch (final CloneNotSupportedException e) {
       
   540             throw new Error("Clone Not Supported"); // never happens
       
   541         }
       
   542     }
       
   543 
       
   544     /**
       
   545      * @return Comparison strategy object
       
   546      */
       
   547     public static BCELComparator getComparator() {
       
   548         return _cmp;
       
   549     }
       
   550 
       
   551     /**
       
   552      * @param comparator Comparison strategy object
       
   553      */
       
   554     public static void setComparator(final BCELComparator comparator) {
       
   555         _cmp = comparator;
       
   556     }
       
   557 
       
   558     /**
       
   559      * Return value as defined by given BCELComparator strategy. By default two
       
   560      * ClassGen objects are said to be equal when their class names are equal.
       
   561      *
       
   562      * @see java.lang.Object#equals(java.lang.Object)
       
   563      */
       
   564     @Override
       
   565     public boolean equals(final Object obj) {
       
   566         return _cmp.equals(this, obj);
       
   567     }
       
   568 
       
   569     /**
       
   570      * Return value as defined by given BCELComparator strategy. By default
       
   571      * return the hashcode of the class name.
       
   572      *
       
   573      * @see java.lang.Object#hashCode()
       
   574      */
       
   575     @Override
       
   576     public int hashCode() {
       
   577         return _cmp.hashCode(this);
       
   578     }
   418 }
   579 }