blob: 005a50b28346cda094268eda47ac599acc9d7f7b [file] [log] [blame]
/*
* reserved comment block
* DO NOT REMOVE OR ALTER!
*/
package com.sun.org.apache.bcel.internal.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
* <http://www.apache.org/>.
*/
import com.sun.org.apache.bcel.internal.Constants;
import com.sun.org.apache.bcel.internal.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
* @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
*/
public class ClassGen extends AccessFlags implements Cloneable {
/* 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,
"<init>", "()V")));
il.append(InstructionConstants.RETURN);
MethodGen mg = new MethodGen(access_flags, Type.VOID, Type.NO_ARGS, null,
"<init>", 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 = (Field)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 = (Method)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<methods.length; m++)
addMethod(methods[m]);
}
public void setMethodAt(Method method, int pos) {
method_vec.set(pos, method);
}
public Method getMethodAt(int pos) {
return (Method)method_vec.get(pos);
}
public String[] getInterfaceNames() {
int size = interface_vec.size();
String[] interfaces = new String[size];
interface_vec.toArray(interfaces);
return interfaces;
}
public int[] getInterfaces() {
int size = interface_vec.size();
int[] interfaces = new int[size];
for(int i=0; i < size; i++)
interfaces[i] = cp.addClass((String)interface_vec.get(i));
return interfaces;
}
public Field[] getFields() {
Field[] fields = new Field[field_vec.size()];
field_vec.toArray(fields);
return fields;
}
public Attribute[] getAttributes() {
Attribute[] attributes = new Attribute[attribute_vec.size()];
attribute_vec.toArray(attributes);
return attributes;
}
public ConstantPoolGen getConstantPool() { return cp; }
public void setConstantPool(ConstantPoolGen constant_pool) {
cp = constant_pool;
}
public void setClassNameIndex(int class_name_index) {
this.class_name_index = class_name_index;
class_name = cp.getConstantPool().
getConstantString(class_name_index, Constants.CONSTANT_Class).replace('/', '.');
}
public void setSuperclassNameIndex(int superclass_name_index) {
this.superclass_name_index = superclass_name_index;
super_class_name = cp.getConstantPool().
getConstantString(superclass_name_index, Constants.CONSTANT_Class).replace('/', '.');
}
public int getSuperclassNameIndex() { return superclass_name_index; }
public int getClassNameIndex() { return class_name_index; }
private ArrayList 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(); )
((ClassObserver)e.next()).notify(this);
}
public Object clone() {
try {
return super.clone();
} catch(CloneNotSupportedException e) {
System.err.println(e);
return null;
}
}
}