package org.apache.bcel.generic; /* ==================================================================== * The Apache Software License, Version 1.1 * * Copyright (c) 2001 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, * if any, must include the following acknowledgment: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Apache" and "Apache Software Foundation" and * "Apache BCEL" must not be used to endorse or promote products * derived from this software without prior written permission. For * written permission, please contact apache@apache.org. * * 5. Products derived from this software may not be called "Apache", * "Apache BCEL", nor may "Apache" appear in their name, without * prior written permission of the Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * . */ import org.apache.bcel.Constants; import org.apache.bcel.classfile.*; import java.util.ArrayList; import java.util.Iterator; /** * Template class for building up a java class. May be initialized with an * existing java class (file). * * @see JavaClass * @version $Id: ClassGen.java,v 1.3 2002/03/04 13:36:57 mdahm Exp $ * @author M. Dahm */ public class ClassGen extends AccessFlags implements Cloneable { /** * */ private static final long serialVersionUID = 1030389262306646953L; /* Corresponds to the fields found in a JavaClass object. */ private String class_name, super_class_name, file_name; private int class_name_index = -1, superclass_name_index = -1; private int major = Constants.MAJOR_1_1, minor = Constants.MINOR_1_1; private ConstantPoolGen cp; // Template for building up constant pool // ArrayLists instead of arrays to gather fields, methods, etc. private ArrayList field_vec = new ArrayList(); private ArrayList method_vec = new ArrayList(); private ArrayList attribute_vec = new ArrayList(); private ArrayList interface_vec = new ArrayList(); /** Convenience constructor to set up some important values initially. * * @param class_name fully qualified class name * @param super_class_name fully qualified superclass name * @param file_name source file name * @param access_flags access qualifiers * @param interfaces implemented interfaces * @param cp constant pool to use */ public ClassGen(String class_name, String super_class_name, String file_name, int access_flags, String[] interfaces, ConstantPoolGen cp) { this.class_name = class_name; this.super_class_name = super_class_name; this.file_name = file_name; this.access_flags = access_flags; this.cp = cp; // Put everything needed by default into the constant pool and the vectors if(file_name != null) addAttribute(new SourceFile(cp.addUtf8("SourceFile"), 2, cp.addUtf8(file_name), cp.getConstantPool())); class_name_index = cp.addClass(class_name); superclass_name_index = cp.addClass(super_class_name); if(interfaces != null) for(int i=0; i < interfaces.length; i++) addInterface(interfaces[i]); } /** Convenience constructor to set up some important values initially. * * @param class_name fully qualified class name * @param super_class_name fully qualified superclass name * @param file_name source file name * @param access_flags access qualifiers * @param interfaces implemented interfaces */ public ClassGen(String class_name, String super_class_name, String file_name, int access_flags, String[] interfaces) { this(class_name, super_class_name, file_name, access_flags, interfaces, new ConstantPoolGen()); } /** * Initialize with existing class. * @param clazz JavaClass object (e.g. read from file) */ public ClassGen(JavaClass clazz) { class_name_index = clazz.getClassNameIndex(); superclass_name_index = clazz.getSuperclassNameIndex(); class_name = clazz.getClassName(); super_class_name = clazz.getSuperclassName(); file_name = clazz.getSourceFileName(); access_flags = clazz.getAccessFlags(); cp = new ConstantPoolGen(clazz.getConstantPool()); major = clazz.getMajor(); minor = clazz.getMinor(); Attribute[] attributes = clazz.getAttributes(); Method[] methods = clazz.getMethods(); Field[] fields = clazz.getFields(); String[] interfaces = clazz.getInterfaceNames(); for(int i=0; i < interfaces.length; i++) addInterface(interfaces[i]); for(int i=0; i < attributes.length; i++) addAttribute(attributes[i]); for(int i=0; i < methods.length; i++) addMethod(methods[i]); for(int i=0; i < fields.length; i++) addField(fields[i]); } /** * @return the (finally) built up Java class object. */ public JavaClass getJavaClass() { int[] interfaces = getInterfaces(); Field[] fields = getFields(); Method[] methods = getMethods(); Attribute[] attributes = getAttributes(); // Must be last since the above calls may still add something to it ConstantPool cp = this.cp.getFinalConstantPool(); return new JavaClass(class_name_index, superclass_name_index, file_name, major, minor, access_flags, cp, interfaces, fields, methods, attributes); } /** * Add an interface to this class, i.e., this class has to implement it. * @param name interface to implement (fully qualified class name) */ public void addInterface(String name) { interface_vec.add(name); } /** * Remove an interface from this class. * @param name interface to remove (fully qualified name) */ public void removeInterface(String name) { interface_vec.remove(name); } /** * @return major version number of class file */ public int getMajor() { return major; } /** Set major version number of class file, default value is 45 (JDK 1.1) * @param major major version number */ public void setMajor(int major) { this.major = major; } /** Set minor version number of class file, default value is 3 (JDK 1.1) * @param minor minor version number */ public void setMinor(int minor) { this.minor = minor; } /** * @return minor version number of class file */ public int getMinor() { return minor; } /** * Add an attribute to this class. * @param a attribute to add */ public void addAttribute(Attribute a) { attribute_vec.add(a); } /** * Add a method to this class. * @param m method to add */ public void addMethod(Method m) { method_vec.add(m); } /** * Convenience method. * * Add an empty constructor to this class that does nothing but calling super(). * @param access rights for constructor */ public void addEmptyConstructor(int access_flags) { InstructionList il = new InstructionList(); il.append(InstructionConstants.THIS); // Push `this' il.append(new INVOKESPECIAL(cp.addMethodref(super_class_name, "", "()V"))); il.append(InstructionConstants.RETURN); MethodGen mg = new MethodGen(access_flags, Type.VOID, Type.NO_ARGS, null, "", class_name, il, cp); mg.setMaxStack(1); addMethod(mg.getMethod()); } /** * Add a field to this class. * @param f field to add */ public void addField(Field f) { field_vec.add(f); } public boolean containsField(Field f) { return field_vec.contains(f); } /** @return field object with given name, or null */ public Field containsField(String name) { for(Iterator e=field_vec.iterator(); e.hasNext(); ) { Field f = e.next(); if(f.getName().equals(name)) return f; } return null; } /** @return method object with given name and signature, or null */ public Method containsMethod(String name, String signature) { for(Iterator e=method_vec.iterator(); e.hasNext();) { Method m = e.next(); if(m.getName().equals(name) && m.getSignature().equals(signature)) return m; } return null; } /** * Remove an attribute from this class. * @param a attribute to remove */ public void removeAttribute(Attribute a) { attribute_vec.remove(a); } /** * Remove a method from this class. * @param m method to remove */ public void removeMethod(Method m) { method_vec.remove(m); } /** Replace given method with new one. If the old one does not exist * add the new_ method to the class anyway. */ public void replaceMethod(Method old, Method new_) { if(new_ == null) throw new ClassGenException("Replacement method must not be null"); int i = method_vec.indexOf(old); if(i < 0) method_vec.add(new_); else method_vec.set(i, new_); } /** Replace given field with new one. If the old one does not exist * add the new_ field to the class anyway. */ public void replaceField(Field old, Field new_) { if(new_ == null) throw new ClassGenException("Replacement method must not be null"); int i = field_vec.indexOf(old); if(i < 0) field_vec.add(new_); else field_vec.set(i, new_); } /** * Remove a field to this class. * @param f field to remove */ public void removeField(Field f) { field_vec.remove(f); } public String getClassName() { return class_name; } public String getSuperclassName() { return super_class_name; } public String getFileName() { return file_name; } public void setClassName(String name) { class_name = name.replace('/', '.'); class_name_index = cp.addClass(name); } public void setSuperclassName(String name) { super_class_name = name.replace('/', '.'); superclass_name_index = cp.addClass(name); } public Method[] getMethods() { Method[] methods = new Method[method_vec.size()]; method_vec.toArray(methods); return methods; } public void setMethods(Method[] methods) { method_vec.clear(); for(int m=0; m observers; /** Add observer for this object. */ public void addObserver(ClassObserver o) { if(observers == null) observers = new ArrayList(); observers.add(o); } /** Remove observer for this object. */ public void removeObserver(ClassObserver o) { if(observers != null) observers.remove(o); } /** Call notify() method on all observers. This method is not called * automatically whenever the state has changed, but has to be * called by the user after he has finished editing the object. */ public void update() { if(observers != null) for(Iterator e = observers.iterator(); e.hasNext(); ) e.next().notify(this); } public Object clone() { try { return super.clone(); } catch(CloneNotSupportedException e) { System.err.println(e); return null; } } }