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