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