View Javadoc
1   /*
2    * reserved comment block
3    * DO NOT REMOVE OR ALTER!
4    */
5   package com.sun.org.apache.bcel.internal.generic;
6   
7   /* ====================================================================
8    * The Apache Software License, Version 1.1
9    *
10   * Copyright (c) 2001 The Apache Software Foundation.  All rights
11   * reserved.
12   *
13   * Redistribution and use in source and binary forms, with or without
14   * modification, are permitted provided that the following conditions
15   * are met:
16   *
17   * 1. Redistributions of source code must retain the above copyright
18   *    notice, this list of conditions and the following disclaimer.
19   *
20   * 2. Redistributions in binary form must reproduce the above copyright
21   *    notice, this list of conditions and the following disclaimer in
22   *    the documentation and/or other materials provided with the
23   *    distribution.
24   *
25   * 3. The end-user documentation included with the redistribution,
26   *    if any, must include the following acknowledgment:
27   *       "This product includes software developed by the
28   *        Apache Software Foundation (http://www.apache.org/)."
29   *    Alternately, this acknowledgment may appear in the software itself,
30   *    if and wherever such third-party acknowledgments normally appear.
31   *
32   * 4. The names "Apache" and "Apache Software Foundation" and
33   *    "Apache BCEL" must not be used to endorse or promote products
34   *    derived from this software without prior written permission. For
35   *    written permission, please contact apache@apache.org.
36   *
37   * 5. Products derived from this software may not be called "Apache",
38   *    "Apache BCEL", nor may "Apache" appear in their name, without
39   *    prior written permission of the Apache Software Foundation.
40   *
41   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
42   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
43   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
44   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
45   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
46   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
47   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
48   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
49   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
50   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
51   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
52   * SUCH DAMAGE.
53   * ====================================================================
54   *
55   * This software consists of voluntary contributions made by many
56   * individuals on behalf of the Apache Software Foundation.  For more
57   * information on the Apache Software Foundation, please see
58   * <http://www.apache.org/>.
59   */
60  
61  import com.sun.org.apache.bcel.internal.Constants;
62  import com.sun.org.apache.bcel.internal.classfile.*;
63  import java.util.ArrayList;
64  import java.util.Iterator;
65  
66  /**
67   * Template class for building up a java class. May be initialized with an
68   * existing java class (file).
69   *
70   * @see JavaClass
71   * @author  <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
72   */
73  public class ClassGen extends AccessFlags implements Cloneable {
74    /* Corresponds to the fields found in a JavaClass object.
75     */
76    private String   class_name, super_class_name, file_name;
77    private int      class_name_index = -1, superclass_name_index = -1;
78    private int      major = Constants.MAJOR_1_1, minor = Constants.MINOR_1_1;
79  
80    private ConstantPoolGen cp; // Template for building up constant pool
81  
82    // ArrayLists instead of arrays to gather fields, methods, etc.
83    private ArrayList   field_vec     = new ArrayList();
84    private ArrayList   method_vec    = new ArrayList();
85    private ArrayList   attribute_vec = new ArrayList();
86    private ArrayList   interface_vec = new ArrayList();
87  
88    /** Convenience constructor to set up some important values initially.
89     *
90     * @param class_name fully qualified class name
91     * @param super_class_name fully qualified superclass name
92     * @param file_name source file name
93     * @param access_flags access qualifiers
94     * @param interfaces implemented interfaces
95     * @param cp constant pool to use
96     */
97    public ClassGen(String class_name, String super_class_name, String file_name,
98                    int access_flags, String[] interfaces, ConstantPoolGen cp) {
99      this.class_name       = class_name;
100     this.super_class_name = super_class_name;
101     this.file_name        = file_name;
102     this.access_flags     = access_flags;
103     this.cp               = cp;
104 
105     // Put everything needed by default into the constant pool and the vectors
106     if(file_name != null)
107       addAttribute(new SourceFile(cp.addUtf8("SourceFile"), 2,
108                                   cp.addUtf8(file_name), cp.getConstantPool()));
109 
110     class_name_index      = cp.addClass(class_name);
111     superclass_name_index = cp.addClass(super_class_name);
112 
113     if(interfaces != null)
114       for(int i=0; i < interfaces.length; i++)
115         addInterface(interfaces[i]);
116   }
117 
118   /** Convenience constructor to set up some important values initially.
119    *
120    * @param class_name fully qualified class name
121    * @param super_class_name fully qualified superclass name
122    * @param file_name source file name
123    * @param access_flags access qualifiers
124    * @param interfaces implemented interfaces
125    */
126   public ClassGen(String class_name, String super_class_name, String file_name,
127                   int access_flags, String[] interfaces) {
128     this(class_name, super_class_name, file_name, access_flags, interfaces,
129          new ConstantPoolGen());
130   }
131 
132   /**
133    * Initialize with existing class.
134    * @param clazz JavaClass object (e.g. read from file)
135    */
136   public ClassGen(JavaClass clazz) {
137     class_name_index      = clazz.getClassNameIndex();
138     superclass_name_index = clazz.getSuperclassNameIndex();
139     class_name            = clazz.getClassName();
140     super_class_name      = clazz.getSuperclassName();
141     file_name             = clazz.getSourceFileName();
142     access_flags          = clazz.getAccessFlags();
143     cp                    = new ConstantPoolGen(clazz.getConstantPool());
144     major                 = clazz.getMajor();
145     minor                 = clazz.getMinor();
146 
147     Attribute[] attributes = clazz.getAttributes();
148     Method[]    methods    = clazz.getMethods();
149     Field[]     fields     = clazz.getFields();
150     String[]    interfaces = clazz.getInterfaceNames();
151 
152     for(int i=0; i < interfaces.length; i++)
153       addInterface(interfaces[i]);
154 
155     for(int i=0; i < attributes.length; i++)
156       addAttribute(attributes[i]);
157 
158     for(int i=0; i < methods.length; i++)
159       addMethod(methods[i]);
160 
161     for(int i=0; i < fields.length; i++)
162       addField(fields[i]);
163   }
164 
165   /**
166    * @return the (finally) built up Java class object.
167    */
168   public JavaClass getJavaClass() {
169     int[]        interfaces = getInterfaces();
170     Field[]      fields     = getFields();
171     Method[]     methods    = getMethods();
172     Attribute[]  attributes = getAttributes();
173 
174     // Must be last since the above calls may still add something to it
175     ConstantPool cp         = this.cp.getFinalConstantPool();
176 
177     return new JavaClass(class_name_index, superclass_name_index,
178                          file_name, major, minor, access_flags,
179                          cp, interfaces, fields, methods, attributes);
180   }
181 
182   /**
183    * Add an interface to this class, i.e., this class has to implement it.
184    * @param name interface to implement (fully qualified class name)
185    */
186   public void addInterface(String name) {
187     interface_vec.add(name);
188   }
189 
190   /**
191    * Remove an interface from this class.
192    * @param name interface to remove (fully qualified name)
193    */
194   public void removeInterface(String name) {
195     interface_vec.remove(name);
196   }
197 
198   /**
199    * @return major version number of class file
200    */
201   public int  getMajor()      { return major; }
202 
203   /** Set major version number of class file, default value is 45 (JDK 1.1)
204    * @param major major version number
205    */
206   public void setMajor(int major) {
207     this.major = major;
208   }
209 
210   /** Set minor version number of class file, default value is 3 (JDK 1.1)
211    * @param minor minor version number
212    */
213   public void setMinor(int minor) {
214     this.minor = minor;
215   }
216 
217   /**
218    * @return minor version number of class file
219    */
220   public int  getMinor()      { return minor; }
221 
222   /**
223    * Add an attribute to this class.
224    * @param a attribute to add
225    */
226   public void addAttribute(Attribute a)    { attribute_vec.add(a); }
227 
228   /**
229    * Add a method to this class.
230    * @param m method to add
231    */
232   public void addMethod(Method m)          { method_vec.add(m); }
233 
234   /**
235    * Convenience method.
236    *
237    * Add an empty constructor to this class that does nothing but calling super().
238    * @param access rights for constructor
239    */
240   public void addEmptyConstructor(int access_flags) {
241     InstructionList il = new InstructionList();
242     il.append(InstructionConstants.THIS); // Push `this'
243     il.append(new INVOKESPECIAL(cp.addMethodref(super_class_name,
244                                                 "<init>", "()V")));
245     il.append(InstructionConstants.RETURN);
246 
247     MethodGen mg = new MethodGen(access_flags, Type.VOID, Type.NO_ARGS, null,
248                        "<init>", class_name, il, cp);
249     mg.setMaxStack(1);
250     addMethod(mg.getMethod());
251   }
252 
253   /**
254    * Add a field to this class.
255    * @param f field to add
256    */
257   public void addField(Field f)            { field_vec.add(f); }
258 
259   public boolean containsField(Field f)    { return field_vec.contains(f); }
260 
261   /** @return field object with given name, or null
262    */
263   public Field containsField(String name) {
264     for(Iterator e=field_vec.iterator(); e.hasNext(); ) {
265       Field f = (Field)e.next();
266       if(f.getName().equals(name))
267         return f;
268     }
269 
270     return null;
271   }
272 
273   /** @return method object with given name and signature, or null
274    */
275   public Method containsMethod(String name, String signature) {
276     for(Iterator e=method_vec.iterator(); e.hasNext();) {
277       Method m = (Method)e.next();
278       if(m.getName().equals(name) && m.getSignature().equals(signature))
279         return m;
280     }
281 
282     return null;
283   }
284 
285   /**
286    * Remove an attribute from this class.
287    * @param a attribute to remove
288    */
289   public void removeAttribute(Attribute a) { attribute_vec.remove(a); }
290 
291   /**
292    * Remove a method from this class.
293    * @param m method to remove
294    */
295   public void removeMethod(Method m)       { method_vec.remove(m); }
296 
297   /** Replace given method with new one. If the old one does not exist
298    * add the new_ method to the class anyway.
299    */
300   public void replaceMethod(Method old, Method new_) {
301     if(new_ == null)
302       throw new ClassGenException("Replacement method must not be null");
303 
304     int i = method_vec.indexOf(old);
305 
306     if(i < 0)
307       method_vec.add(new_);
308     else
309       method_vec.set(i, new_);
310   }
311 
312   /** Replace given field with new one. If the old one does not exist
313    * add the new_ field to the class anyway.
314    */
315   public void replaceField(Field old, Field new_) {
316     if(new_ == null)
317       throw new ClassGenException("Replacement method must not be null");
318 
319     int i = field_vec.indexOf(old);
320 
321     if(i < 0)
322       field_vec.add(new_);
323     else
324       field_vec.set(i, new_);
325   }
326 
327   /**
328    * Remove a field to this class.
329    * @param f field to remove
330    */
331   public void removeField(Field f)         { field_vec.remove(f); }
332 
333   public String getClassName()      { return class_name; }
334   public String getSuperclassName() { return super_class_name; }
335   public String getFileName()       { return file_name; }
336 
337   public void setClassName(String name) {
338     class_name = name.replace('/', '.');
339     class_name_index = cp.addClass(name);
340   }
341 
342   public void setSuperclassName(String name) {
343     super_class_name = name.replace('/', '.');
344     superclass_name_index = cp.addClass(name);
345   }
346 
347   public Method[] getMethods() {
348     Method[] methods = new Method[method_vec.size()];
349     method_vec.toArray(methods);
350     return methods;
351   }
352 
353   public void setMethods(Method[] methods) {
354     method_vec.clear();
355     for(int m=0; m<methods.length; m++)
356       addMethod(methods[m]);
357   }
358 
359   public void setMethodAt(Method method, int pos) {
360     method_vec.set(pos, method);
361   }
362 
363   public Method getMethodAt(int pos) {
364     return (Method)method_vec.get(pos);
365   }
366 
367   public String[] getInterfaceNames() {
368     int      size = interface_vec.size();
369     String[] interfaces = new String[size];
370 
371     interface_vec.toArray(interfaces);
372     return interfaces;
373   }
374 
375   public int[] getInterfaces() {
376     int   size = interface_vec.size();
377     int[] interfaces = new int[size];
378 
379     for(int i=0; i < size; i++)
380       interfaces[i] = cp.addClass((String)interface_vec.get(i));
381 
382     return interfaces;
383   }
384 
385   public Field[] getFields() {
386     Field[] fields = new Field[field_vec.size()];
387     field_vec.toArray(fields);
388     return fields;
389   }
390 
391   public Attribute[] getAttributes() {
392     Attribute[] attributes = new Attribute[attribute_vec.size()];
393     attribute_vec.toArray(attributes);
394     return attributes;
395   }
396 
397   public ConstantPoolGen getConstantPool() { return cp; }
398   public void setConstantPool(ConstantPoolGen constant_pool) {
399     cp = constant_pool;
400   }
401 
402   public void setClassNameIndex(int class_name_index) {
403     this.class_name_index = class_name_index;
404     class_name = cp.getConstantPool().
405       getConstantString(class_name_index, Constants.CONSTANT_Class).replace('/', '.');
406   }
407 
408   public void setSuperclassNameIndex(int superclass_name_index) {
409     this.superclass_name_index = superclass_name_index;
410     super_class_name = cp.getConstantPool().
411       getConstantString(superclass_name_index, Constants.CONSTANT_Class).replace('/', '.');
412   }
413 
414   public int getSuperclassNameIndex() { return superclass_name_index; }
415 
416   public int getClassNameIndex()   { return class_name_index; }
417 
418   private ArrayList observers;
419 
420   /** Add observer for this object.
421    */
422   public void addObserver(ClassObserver o) {
423     if(observers == null)
424       observers = new ArrayList();
425 
426     observers.add(o);
427   }
428 
429   /** Remove observer for this object.
430    */
431   public void removeObserver(ClassObserver o) {
432     if(observers != null)
433       observers.remove(o);
434   }
435 
436   /** Call notify() method on all observers. This method is not called
437    * automatically whenever the state has changed, but has to be
438    * called by the user after he has finished editing the object.
439    */
440   public void update() {
441     if(observers != null)
442       for(Iterator e = observers.iterator(); e.hasNext(); )
443         ((ClassObserver)e.next()).notify(this);
444   }
445 
446   public Object clone() {
447     try {
448       return super.clone();
449     } catch(CloneNotSupportedException e) {
450       System.err.println(e);
451       return null;
452     }
453   }
454 }