Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/techtrader/modules/tools/bytecode/BCClass.java


1   package com.techtrader.modules.tools.bytecode;
2   
3   
4   import java.io.IOException;
5   import java.io.File;
6   import java.io.InputStream;
7   import java.io.OutputStream;
8   import java.io.DataInput;
9   import java.io.DataOutput;
10  import java.io.DataInputStream;
11  import java.io.DataOutputStream;
12  import java.io.FileInputStream;
13  import java.io.FileOutputStream;
14  import java.io.ByteArrayOutputStream;
15  import java.io.ByteArrayInputStream;
16  import java.util.List;
17  import java.util.LinkedList;
18  import java.util.Iterator;
19  
20  import com.techtrader.modules.tools.bytecode.lowlevel.ConstantPool;
21  import com.techtrader.modules.tools.bytecode.visitor.BCVisitor;
22  
23  
24  /**
25   *  Start here to understand this package.
26   *  A BCClass is a representation of a bytecode class.  It contains
27   *  methods to manipulate the class object itself as well as methods to
28   *  manage the fields and methods of the class.  As with most entities in the
29   *  bytecode framework, there are methods to manipulate the low-level state
30   *  of the class (constant pool indexes, etc), but these methods can safely
31   *  be ignored in favor of the available high-level methods.
32   *  
33   *  @author    Abe White
34   */
35  public class BCClass
36    extends BCEntity
37    implements Constants
38  {
39    private int   _magic        = VALID_MAGIC;
40    private int   _minorVersion     = 3;
41    private int   _majorVersion     = 45;
42    private int   _access       = ACCESS_PUBLIC | ACCESS_SUPER;
43    private int    _classIndex      = 0;
44    private int    _superclassIndex   = 0;
45  
46    private ConstantPool  _pool        = new ConstantPool (this);
47    private List      _interfaceIndexes  = new LinkedList ();
48    private List      _methods      = new LinkedList ();
49    private List      _fields        = new LinkedList ();
50  
51  
52    /**
53     *  Default constructor.  Creates a new empty class.
54     */
55    public BCClass ()
56    {
57    }
58  
59  
60    /**
61     *  Create a BCClass that is an exact copy of the given one.
62     */
63    public BCClass (BCClass orig)
64    {
65      copy (orig);
66    }
67  
68  
69    /**  
70      *  Create a BCClass for the given Class type.
71     */
72    public BCClass (Class type)
73      throws IOException
74    {
75      read (type);
76    }
77  
78  
79    /**
80     *  Create a new BCClass with the given name. 
81     */
82    public BCClass (String name)
83    {
84      setName (name);
85      setSuperclassName (Object.class.getName ());
86    }
87  
88  
89    /**
90     *  Create a BCClass from the given .class file.
91     */
92    public BCClass (File classFile)
93      throws IOException
94    {
95      read (classFile);
96    }
97  
98  
99    /**
100    *  Create a BCClass from the given stream representing a .class file.
101    */
102   public BCClass (InputStream in)
103     throws IOException
104   {
105     read (in);
106   }
107 
108 
109   /**
110    *  Read the class definition from the given file.
111    *  This method resets all information in this instance.
112    */
113   public void read (File classFile)
114     throws IOException
115   {
116     InputStream in = new FileInputStream (classFile);
117     try { read (in); } finally { in.close (); }
118   }
119 
120 
121   /**
122    *  Read the class definition from the given stream.
123    *  This method resets all information in this instance.
124    */
125   public void read (InputStream instream)
126     throws IOException
127   {
128     DataInput in = new DataInputStream (instream);
129 
130     // header information
131     setMagic (in.readInt ());
132     setMinorVersion (in.readUnsignedShort ());
133     setMajorVersion (in.readUnsignedShort ());
134 
135     // constant pool
136     _pool.readData (in);
137 
138     // access flags
139     setAccessFlags (in.readUnsignedShort ());
140 
141     // class, super class, interfaces
142     setIndex (in.readUnsignedShort ());
143     setSuperclassIndex (in.readUnsignedShort ());
144 
145     _interfaceIndexes.clear ();
146     int interfaceCount = in.readUnsignedShort ();
147     int interfaceIndex;
148     for (int i = 0; i < interfaceCount; i++)
149       _interfaceIndexes.add (new Integer (in.readUnsignedShort ()));
150 
151     // fields
152     _fields.clear ();
153     int fieldCount = in.readUnsignedShort ();
154     BCField field;
155     for (int i = 0; i < fieldCount; i++)
156     {
157       field = addField ();
158       field.readData (in);
159     }  
160 
161     // methods
162     _methods.clear ();
163     int methodCount = in.readUnsignedShort ();
164     BCMethod method;
165     for (int i = 0; i < methodCount; i++)
166     {
167       method = addMethod ();
168       method.readData (in);
169     }  
170 
171     readAttributes (in);
172   }
173 
174 
175   /**
176    *  Read the definition of the given class.
177    *  This method resets all information in this instance.
178    */
179   public void read (Class type)
180     throws IOException
181   {
182     // find out the length of the package name
183     int dotIndex = type.getName ().lastIndexOf ('.') + 1;
184 
185     // strip the package off of the class name
186     String className = type.getName ().substring (dotIndex);
187 
188     // attempt to get the class file for the class as a stream
189     InputStream in = type.getResourceAsStream (className + ".class");
190     try { read (in); } finally { in.close (); }
191   }
192 
193 
194   /**  
195     *  For existing classes, write the new bytecode to the same .class file
196    *  the class was laoded from.
197    */
198   public void write ()
199     throws IOException
200   {
201     String name = getName ();
202     int dotIndex = name.lastIndexOf ('.') + 1;
203     name = name.substring (dotIndex);
204 
205     Class type = null;
206     try
207     {
208       type = getType ();
209     }
210     catch (ClassNotFoundException cnfe)
211     {
212       throw new IOException (cnfe.getMessage ());
213     }
214 
215     // attempt to get the class file for the class as a stream
216     OutputStream out = new FileOutputStream (type.getResource 
217       (name + ".class").getFile ());
218     try { write (out); } finally { out.close (); }
219   }
220 
221 
222   /**
223    *  Write the class to the specified file.
224    */
225   public void write (File classFile)
226     throws IOException
227   {
228     OutputStream out = new FileOutputStream (classFile);
229     try { write (out); } finally { out.close (); }
230   }
231 
232 
233   /**
234    *  Write the class to the specified stream.
235    */
236   public void write (OutputStream outstream)
237     throws IOException
238   {
239     DataOutput out = new DataOutputStream (outstream);
240 
241     // header information
242     out.writeInt (getMagic ());
243     out.writeShort (getMinorVersion ());
244     out.writeShort (getMajorVersion ());
245 
246     // constant pool
247     _pool.writeData (out);
248 
249     // access flags
250     out.writeShort (getAccessFlags ());
251 
252     // class, super class, interfaces
253     out.writeShort (getIndex ());
254     out.writeShort (getSuperclassIndex ());
255     out.writeShort (_interfaceIndexes.size ());
256     for (Iterator i = _interfaceIndexes.iterator (); i.hasNext ();)
257       out.writeShort (((Number) i.next ()).intValue ());
258 
259     // fields
260     out.writeShort (_fields.size ());
261     for (Iterator i = _fields.iterator (); i.hasNext ();)
262       ((BCField) i.next ()).writeData (out);
263 
264     // methods
265     out.writeShort (_methods.size ());
266     for (Iterator i = _methods.iterator (); i.hasNext ();)
267       ((BCMethod) i.next ()).writeData (out);
268 
269     // attributes
270     writeAttributes (out);
271   }
272 
273 
274   /**
275    *  Get the contents of this class as a byte array, possibly for use
276    *  in a custom ClassLoader.
277    */
278   public byte[] toByteArray ()
279     throws IOException
280   {
281     ByteArrayOutputStream out = new ByteArrayOutputStream ();
282     try
283     {
284       write (out);
285       out.flush ();
286 
287       return out.toByteArray ();
288     }
289     finally  
290     {
291       out.close ();
292     }
293   }
294 
295 
296   /**
297    *  Copy all of the data from the given original BCClass to this one,
298    *  recursing into fields, methods, code, the constant pool, etc.
299    */
300   public void copy (BCClass orig)
301   {
302     try
303     {
304       ByteArrayInputStream in = new ByteArrayInputStream 
305         (orig.toByteArray ());
306       read (in);
307       in.close ();
308     }
309     catch (IOException ioe)
310     {
311       throw new RuntimeException (ioe.getMessage ());
312     }
313   }
314 
315 
316   /**
317    *  Get the magic number for this .class; if this is a valid class, this
318    *  should be equal to the VALID_MAGIC constant.
319    */
320   public int getMagic ()
321   {
322     return _magic;
323   }
324 
325 
326   /**
327    *  Set the magic number for this .class; if this is a valid class, this
328    *  should be equal to the VALID_MAGIC constant (the default value).
329    */
330   public void setMagic (int magic)
331   {
332     _magic = magic;
333   }
334 
335 
336   /**
337    *  Get the major version of the bytecode spec used for this class;
338    *  JVMs are only required to operate with versions that they understand;
339    *  leaving the default value (45) is safe.
340    */
341   public int getMajorVersion ()
342   {
343     return _majorVersion;
344   }
345 
346 
347   /**
348    *  Set the major version of the bytecode spec used for this class;
349    *  JVMs are only required to operate with versions that they understand;
350    *  leaving the default value (45) is safe.
351    */
352   public void setMajorVersion (int majorVersion)
353   {
354     _majorVersion = majorVersion;  
355   }
356 
357 
358   /**
359    *  Get the minor version of the bytecode spec used for this class;
360    *  JVMs are only required to operate with versions that they understand;
361    *  leaving the default value (3) is safe.
362    */
363   public int getMinorVersion ()
364   {
365     return _minorVersion;
366   }
367 
368 
369   /**
370    *  Set the minor version of the bytecode spec used for this class;
371    *  JVMs are only required to operate with versions that they understand;
372    *  leaving the default value (3) is safe.
373    */
374   public void setMinorVersion (int minorVersion)
375   {
376     _minorVersion = minorVersion;  
377   }
378 
379 
380   /**
381    *  Return the access flags for this class as a bit array of 
382     *  ACCESS_XXX constants.  This can be used to transfer access flags
383    *  between classes without getting/setting each possible access flag.
384    */
385   public int getAccessFlags ()
386   {
387     return _access;
388   }
389 
390 
391   /**
392    *  Set the access flags for this class as a bit array of 
393     *  ACCESS_XXX constants.  This can be used to transfer access flags
394    *  between classes without getting/setting each possible access flag.
395    */
396   public void setAccessFlags (int access)
397   {
398     _access = access;  
399   }
400 
401 
402   /**
403    *  Manipulate the class access flags.
404    */
405   public boolean isPublic ()
406   {
407     return BCHelper.hasFlag (_access, ACCESS_PUBLIC);
408   }
409 
410 
411   /**
412    *  Manipulate the class access flags.
413    */
414   public void makePublic ()
415   {
416     _access = BCHelper.setFlag (_access, ACCESS_PUBLIC, true);
417   }
418 
419 
420   /**
421    *  Manipulate the class access flags.
422    */
423   public boolean isPackage ()
424   {
425     return !isPublic ();
426   }
427 
428 
429   /**
430    *  Manipulate the class access flags.
431    */
432   public void makePackage ()
433   {
434     _access = BCHelper.setFlag (_access, ACCESS_PUBLIC, false);
435   }
436 
437 
438   /**
439    *  Manipulate the class access flags.
440    */
441   public boolean isFinal ()
442   {
443     return BCHelper.hasFlag (_access, ACCESS_FINAL);
444   }
445 
446 
447   /**
448    *  Manipulate the class access flags.
449    */
450   public void setFinal (boolean on)
451   {
452     _access = BCHelper.setFlag (_access, ACCESS_FINAL, on);
453   }
454 
455 
456   /**
457    *  Manipulate the class access flags.
458    */
459   public boolean isInterface ()
460   {
461     return BCHelper.hasFlag (_access, ACCESS_INTERFACE);
462   }
463 
464 
465   /**
466    *  Manipulate the class access flags.
467    */
468   public void setInterface (boolean on)
469   {
470     _access = BCHelper.setFlag (_access, ACCESS_INTERFACE, on);
471     if (on)
472       setAbstract (true);
473   }
474 
475 
476   /**
477    *  Manipulate the class access flags.
478    */
479   public boolean isAbstract ()
480   {
481     return BCHelper.hasFlag (_access, ACCESS_ABSTRACT);
482   }
483 
484 
485   /**
486    *  Manipulate the class access flags.
487    */
488   public void setAbstract (boolean on)
489   {
490     _access = BCHelper.setFlag (_access, ACCESS_INTERFACE, on);
491   }
492 
493 
494   /**
495    *  Get the index in the constant pool of the ClassEntry for this class.
496    */
497   public int getIndex ()
498   {
499     return _classIndex;
500   }
501 
502 
503   /**
504    *  Set the constant pool index of the ClassEntry for this class.
505    */
506   public void setIndex (int index)
507   {
508     _classIndex = index;
509   }
510 
511   
512   /**
513    *  Get the name of this class, including package name.
514    */
515   public String getName ()
516   {
517     return BCHelper.getExternalForm 
518       (_pool.getClassName (_classIndex), true);
519   }
520 
521 
522   /**
523    *  Set the name of this class.
524    */
525   public void setName (String name)
526   {
527     _classIndex = _pool.setClassName (_classIndex, 
528       BCHelper.getInternalForm (name, false));
529   }
530 
531 
532   /**
533    *  Get the Class object for this class.
534    */
535   public Class getType ()
536     throws ClassNotFoundException
537   {
538     return BCHelper.classForName (_pool.getClassName (_classIndex));
539   }
540 
541 
542   /**
543    *  Get the index in the constant pool of the ClassEntry for the
544    *  superclass.
545    */
546   public int getSuperclassIndex ()
547   {
548     return _superclassIndex;
549   }
550 
551 
552   /**
553    *  Set the constant pool index of the ClassEntry for the superclass.
554    */
555   public void setSuperclassIndex (int index)
556   {
557     _superclassIndex = index;
558   }
559 
560 
561   /**
562    *  Get the name of the superclass for this class, including package name.
563    */
564   public String getSuperclassName ()
565   {
566     return BCHelper.getExternalForm 
567       (_pool.getClassName (_superclassIndex), true);
568   }
569 
570 
571   /**
572    *  Set the name of the superclass to this class.
573    */
574   public void setSuperclassName (String name)
575   {
576     _superclassIndex = _pool.setClassName (_superclassIndex, 
577       BCHelper.getInternalForm (name, false));
578   }
579 
580 
581   /**
582    *  Get the Class object for the superclass of this class.
583    */
584   public Class getSuperclassType ()
585     throws ClassNotFoundException
586   {
587     return BCHelper.classForName (_pool.getClassName (_superclassIndex));
588   }
589 
590 
591   /**
592    *  Set the Class object for the superclass of this class.
593    */
594   public void setSuperclassType (Class type)
595   {
596     if (type == null)
597       setSuperclassName (Object.class.getName ());
598     else
599       setSuperclassName (type.getName ());
600   }
601 
602 
603   /**
604    *  Get the list of indexes into the constant pool of the ClassEntrys 
605    *  describing all the interfaces this class implements/extends.
606    *  
607    *  @return    the implmented interfaces, or empty array if none
608    */
609   public int[] getInterfaceIndexes ()
610   {
611     int[] indexes = new int[_interfaceIndexes.size ()];
612 
613     Iterator intItr = _interfaceIndexes.iterator ();
614     for (int i = 0, max = _interfaceIndexes.size (); i < max; i++)
615       indexes[i] = ((Integer) intItr.next ()).intValue ();
616 
617     return indexes;
618   }
619 
620 
621   /**
622    *  Set the list of indexes into the constant pool of the ClassEntrys 
623    *  describing all the interfaces this class implements/extends; set to 
624    *  null if none.
625    */
626   public void setInterfaceIndexes (int[] interfaceIndexes)
627   {
628     _interfaceIndexes.clear ();
629 
630     if (interfaceIndexes != null)
631       for (int i = 0; i < interfaceIndexes.length; i++)
632         _interfaceIndexes.add (new Integer (interfaceIndexes[i]));
633   }
634 
635 
636   /**
637    *  Get the names of the interfaces for this class, including package names.
638    */
639   public String[] getInterfaceNames ()
640   {
641     String[] names = new String[_interfaceIndexes.size ()];
642 
643     Iterator interfaces = _interfaceIndexes.iterator ();
644     for (int i = 0; i < names.length; i++)
645       names[i] = BCHelper.getExternalForm (_pool.getClassName
646         (((Integer) interfaces.next ()).intValue ()), true);
647 
648     return names;
649   }
650 
651 
652   /**
653    *  Get the Class objects for the interfaces of this class.
654    */
655   public Class[] getInterfaceTypes ()
656     throws ClassNotFoundException
657   {
658     Class[] types = new Class[_interfaceIndexes.size ()];
659 
660     Iterator interfaces = _interfaceIndexes.iterator ();
661     for (int i = 0; i < types.length; i++)
662       types[i] = BCHelper.classForName (_pool.getClassName 
663         (((Integer) interfaces.next ()).intValue ()));
664 
665     return types;
666   }
667 
668 
669   /**
670    *  Set the interfaces implemented by this class.
671    */
672   public void setInterfaceNames (String[] interfaces)
673   {
674     _interfaceIndexes.clear ();
675     if (interfaces != null)
676       for (int i = 0; i < interfaces.length; i++)
677         addInterfaceName (interfaces[i]);
678   }
679 
680 
681   /**
682    *  Set the interfaces implemented by this class.
683    */
684   public void setInterfaceTypes (Class[] interfaces)
685   {
686     String[] names = null;
687     if (interfaces != null)
688     {
689       names = new String[interfaces.length];
690       for (int i = 0; i < interfaces.length; i++)
691         names[i] = interfaces[i].getName ();
692     }
693 
694     setInterfaceNames (names);
695   }
696 
697 
698   /**
699    *  Clear this class of all interface declarations.
700    */
701   public void clearInterfaces ()
702   {
703     _interfaceIndexes.clear ();
704   }
705 
706 
707   /**
708    *  Remove an interface implmented by this class.
709    */
710   public boolean removeInterfaceName (String name)
711   {
712     if (name == null)
713       return false;
714     
715     String internalForm = BCHelper.getInternalForm (name, false);
716     for (Iterator i = _interfaceIndexes.iterator (); i.hasNext ();)
717     {
718       if (_pool.getClassName (((Integer) i.next ()).intValue ()).
719         equals (internalForm))
720       {
721         i.remove ();
722         return true;
723       }
724     }
725     return false;
726   }
727 
728 
729   /**
730    *  Remove an interface implemented by this class.
731    */
732   public boolean removeInterfaceType (Class type)
733   {
734     return removeInterfaceName (type.getName ());
735   }
736 
737 
738   /**  
739     *  Add an interface to those implemented by this class.
740    */
741   public void addInterfaceName (String name)
742   {
743     int index = _pool.setClassName (0,
744       BCHelper.getInternalForm (name, false));
745 
746     _interfaceIndexes.add (new Integer (index));
747   }
748 
749 
750   /**  
751     *  Add a Class to those implemented by this interface.
752    */
753   public void addInterfaceType (Class type)
754   {
755     addInterfaceName (type.getName ());
756   }
757 
758 
759   /**
760    *  Return true if the class declares that it implements the given 
761    *  interface.
762    */
763   public boolean implementsInterface (String name)
764   {
765     String[] interfaces = getInterfaceNames ();
766     for (int i = 0; i < interfaces.length; i++)
767       if (interfaces[i].equals (name))
768         return true;
769 
770     return false;
771   }
772 
773 
774   /**
775    *  Return true if the class declares that it implements the given 
776    *  interface.
777    */
778   public boolean implementsInterface (Class type)
779   {
780     return implementsInterface (type.getName ());
781   }
782   
783 
784   /**
785    *  Get all the fields of this class.
786    */
787   public BCField[] getFields ()
788   {
789     return (BCField[]) _fields.toArray (new BCField[_fields.size ()]);
790   }
791 
792   
793   /**
794    *  Get the field with the given name.
795    */
796   public BCField getField (String name)
797   {
798     BCField next;
799     for (Iterator i = _fields.iterator (); i.hasNext ();)
800     {
801       next = (BCField) i.next ();
802       if (next.getName ().equals (name))
803         return next;
804     }
805 
806     return null;
807   }
808 
809 
810   /**
811    *  Import the given field from another class, or, if the field belongs
812    *  to this class, add a duplicate of it (in this case, it is an error
813    *  not to change the field name).
814    */
815   public BCField importField (BCField field)
816   {
817     BCField newField = addField (field.getName (), field.getTypeName ());
818     newField.setAccessFlags (field.getAccessFlags ());
819     newField.importAttributes (field);
820 
821     return newField;
822   }
823 
824 
825   /**
826    *  Import all fields from another class.
827    */
828   public void importFields (BCClass other)
829   {
830     BCField[] fields = other.getFields ();
831     for (int i = 0; i < fields.length; i++)
832       importField (fields[i]);
833   }
834 
835 
836   /**
837    *  Add a field to this class.
838    */
839   public BCField addField ()
840   {
841     BCField field = new BCField (this);
842     _fields.add (field);
843 
844     return field;
845   }
846 
847 
848   /**
849    *  Add a field to this class.
850    */
851   public BCField addField (String name, String type)
852   {
853     BCField field = addField ();
854     field.setName (name);
855     field.setTypeName (type);
856 
857     return field;
858   }
859 
860 
861   /**
862    *  Add a field to this class.
863    */
864   public BCField addField (String name, Class type)
865   {
866     return addField (name, type.getName ());
867   }
868 
869 
870   /**
871    *  Clear all fields from this class.
872    */
873   public void clearFields ()
874   {
875     _fields.clear ();
876   }
877 
878 
879   /**
880    *  Removes the field with the given name from this class.
881    */
882   public boolean removeField (String name)
883   {
884     return removeField (getField (name));
885   }
886 
887 
888   /**  
889     *  Removes a field from this class.  After this method, the field
890    *  will be invalid, and the result of any operations on it is undefined.
891    */
892   public boolean removeField (BCField field)
893   {
894     if (field == null || !_fields.remove (field))
895       return false;
896 
897     field.invalidate ();
898     return true;
899   }
900 
901 
902   /**
903    *  Get all the methods of this class.
904    */
905   public BCMethod[] getMethods ()
906   {
907     return (BCMethod[]) _methods.toArray (new BCMethod[_methods.size ()]);
908   }
909 
910   
911   /**
912    *  Get the method with the given name.  If multiple methods in this class
913    *  have this name, which is returned is not defined.
914    */
915   public BCMethod getMethod (String name)
916   {
917     BCMethod next;
918     for (Iterator i = _methods.iterator (); i.hasNext ();)
919     {
920       next = (BCMethod) i.next ();
921       if (next.getName ().equals (name))
922         return next;
923     }
924 
925     return null;
926   }
927 
928 
929   /**
930    *  Get all methods with the given name.
931    *
932    *  @return    the matching methods, or empty array if none
933    */
934   public BCMethod[] getMethods (String name)
935   {
936     List matches = new LinkedList ();
937     BCMethod next;
938     for (Iterator i = _methods.iterator (); i.hasNext ();)
939     {
940       next = (BCMethod) i.next ();
941       if (next.getName ().equals (name))
942         matches.add (next);
943     }
944 
945     return (BCMethod[]) matches.toArray (new BCMethod[matches.size ()]);
946   }
947 
948 
949   /**
950    *  Get the method with the given name and param types.
951    */
952   public BCMethod getMethod (String name, String[] params)
953   {
954     if (params == null)
955       params = new String[0];
956 
957     String[] curParams;
958     boolean match;
959     BCMethod next;
960     for (Iterator i = _methods.iterator (); i.hasNext ();)
961     {
962       next = (BCMethod) i.next ();
963       if (next.getName ().equals (name))
964       {
965         curParams = next.getParamTypeNames ();
966         if (curParams.length != params.length)
967           continue;
968 
969         match = true;
970         for (int j = 0; j < params.length; j++)
971         {
972           if (!curParams[j].equals (BCHelper.getExternalForm 
973             (params[j], true)))
974           {
975             match = false;
976             break;
977           }
978         }
979 
980         if (match)
981           return next;
982       }
983     }
984 
985     return null;
986   }
987 
988 
989   /**
990    *  Get the method with the given name and param types.
991    */
992   public BCMethod getMethod (String name, Class[] params)
993   {
994     String[] paramTypeNames;
995     if (params == null)
996       paramTypeNames = new String[0];
997     else
998     {
999       paramTypeNames = new String[params.length];
1000      for (int i = 0; i < params.length; i++)
1001        paramTypeNames[i] = params[i].getName ();
1002    }
1003
1004    return getMethod (name, paramTypeNames);
1005  }
1006
1007
1008  /**
1009   *  Import the given method from another class, or, if the method belongs
1010   *  to this class, add a duplicate of it (in this case, it is an error
1011   *  not to change the method name or parameter types).
1012   */
1013  public BCMethod importMethod (BCMethod method)
1014  {
1015    BCMethod newMethod = addMethod (method.getName (), 
1016      method.getReturnTypeName (), method.getParamTypeNames ());
1017    newMethod.setAccessFlags (method.getAccessFlags ());
1018    newMethod.importAttributes (method);
1019
1020    return newMethod;
1021  }
1022
1023
1024  /**
1025   *  Import all methods from the given class; note that this includes
1026   *  constructors, static initializers, etc.
1027   */
1028  public void importMethods (BCClass other)
1029  {
1030    BCMethod[] methods = other.getMethods ();
1031    for (int i = 0; i < methods.length; i++)
1032      importMethod (methods[i]);
1033  }
1034
1035
1036  /**
1037   *  Add a method to this class.
1038   */
1039  public BCMethod addMethod ()
1040  {
1041    BCMethod method = new BCMethod (this);
1042    _methods.add (method);
1043
1044    return method;
1045  }
1046
1047  
1048  /**
1049   *  Add a method to this class.
1050   */
1051  public BCMethod addMethod (String name, String returnType, 
1052    String[] paramTypes)
1053  {
1054    BCMethod method = addMethod ();
1055    method.setName (name);
1056    method.setDescriptor (returnType, paramTypes);
1057
1058    return method;
1059  }
1060
1061
1062  /**
1063   *  Add a method to this class.
1064   */
1065  public BCMethod addMethod (String name, Class returnType, 
1066    Class[] paramTypes)
1067  {
1068    BCMethod method = addMethod ();
1069    method.setName (name);
1070    method.setDescriptor (returnType, paramTypes);
1071
1072    return method;
1073  }
1074
1075
1076  /**
1077   *  Remove all methods from this class; note that this includes 
1078   *  constructors, static initializers, etc.
1079   */
1080  public void clearMethods ()
1081  {
1082    _methods.clear ();
1083  }
1084
1085
1086  /**  
1087    *  Removes a method from this class.  After this method, the method
1088   *  will be invalid, and the result of any operations on it is undefined.
1089   */
1090  public boolean removeMethod (BCMethod method)
1091  {
1092    if (method == null || !_methods.remove (method))
1093      return false;
1094
1095    method.invalidate ();
1096    return true;
1097  }
1098
1099
1100  /**
1101   *  Removes the method with the given name from the class.  If multiple
1102   *  methods have the name, they will all be removed.
1103   */
1104  public boolean removeMethod (String name)
1105  {
1106    BCMethod[] matches = getMethods (name);
1107    for (int i = 0; i < matches.length; i++)
1108      removeMethod (matches[i]);
1109
1110    return (matches.length > 0);
1111  }
1112
1113
1114  /**
1115   *  Removes the method with the given signature.
1116   */
1117  public boolean removeMethod (String name, String[] params)
1118  {
1119    return removeMethod (getMethod (name, params));
1120  }
1121
1122
1123  /**
1124   *  Removes the method with the given signature.
1125   */
1126  public boolean removeMethod (String name, Class[] params)
1127  {
1128    return removeMethod (getMethod (name, params));
1129  }
1130
1131
1132  /**
1133   *  Return the constant pool for this class.
1134   */
1135  public ConstantPool getPool ()
1136  {
1137    return _pool;
1138  }
1139
1140
1141  /**
1142   *  Add a default constructor to this class.  This method can only be
1143   *  called if the superclass has been set.
1144   */
1145  public BCMethod addDefaultConstructor ()
1146  {
1147    BCMethod method = addMethod ("<init>", void.class, null);
1148    Code code = method.addCode ();
1149    code.setMaxStack (1);
1150    code.setMaxLocals (1);
1151  
1152    code.aload_0 ();
1153    code.invokespecial ().setMethod 
1154      ("<init>", void.class, null, getSuperclassName ());
1155    code.vreturn ();
1156
1157    return method;
1158  }
1159
1160
1161  public void acceptVisit (BCVisitor visit)
1162  {
1163    visit.enterBCClass (this);
1164
1165    _pool.acceptVisit (visit);
1166    for (Iterator i = _fields.iterator (); i.hasNext ();)
1167      ((BCField) i.next ()).acceptVisit (visit);
1168    for (Iterator i = _methods.iterator (); i.hasNext ();)
1169      ((BCMethod) i.next ()).acceptVisit (visit);
1170    visitAttributes (visit);
1171
1172    visit.exitBCClass (this);
1173  }
1174}