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 }