1 /* 2 * reserved comment block 3 * DO NOT REMOVE OR ALTER! 4 */ 5 /* 6 * Licensed to the Apache Software Foundation (ASF) under one or more 7 * contributor license agreements. See the NOTICE file distributed with 8 * this work for additional information regarding copyright ownership. 9 * The ASF licenses this file to You under the Apache License, Version 2.0 10 * (the "License"); you may not use this file except in compliance with 11 * the License. You may obtain a copy of the License at 12 * 13 * http://www.apache.org/licenses/LICENSE-2.0 14 * 15 * Unless required by applicable law or agreed to in writing, software 16 * distributed under the License is distributed on an "AS IS" BASIS, 17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 * See the License for the specific language governing permissions and 19 * limitations under the License. 20 */ 21 22 package com.sun.org.apache.bcel.internal.generic; 23 24 25 import com.sun.org.apache.bcel.internal.Constants; 26 import com.sun.org.apache.bcel.internal.classfile.*; 27 import java.util.ArrayList; 28 import java.util.Iterator; 29 30 /** 31 * Template class for building up a java class. May be initialized with an 32 * existing java class (file). 33 * 34 * @see JavaClass 35 * @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A> 36 */ 37 public class ClassGen extends AccessFlags implements Cloneable { 38 /* Corresponds to the fields found in a JavaClass object. 39 */ 40 private String class_name, super_class_name, file_name; 41 private int class_name_index = -1, superclass_name_index = -1; 42 private int major = Constants.MAJOR_1_1, minor = Constants.MINOR_1_1; 43 44 private ConstantPoolGen cp; // Template for building up constant pool 45 46 // ArrayLists instead of arrays to gather fields, methods, etc. 47 private ArrayList field_vec = new ArrayList(); 48 private ArrayList method_vec = new ArrayList(); 49 private ArrayList attribute_vec = new ArrayList(); 50 private ArrayList interface_vec = new ArrayList(); 51 52 /** Convenience constructor to set up some important values initially. 53 * 54 * @param class_name fully qualified class name 55 * @param super_class_name fully qualified superclass name 56 * @param file_name source file name 57 * @param access_flags access qualifiers 58 * @param interfaces implemented interfaces 59 * @param cp constant pool to use 60 */ 61 public ClassGen(String class_name, String super_class_name, String file_name, 62 int access_flags, String[] interfaces, ConstantPoolGen cp) { 63 this.class_name = class_name; 64 this.super_class_name = super_class_name; 65 this.file_name = file_name; 66 this.access_flags = access_flags; 67 this.cp = cp; 68 69 // Put everything needed by default into the constant pool and the vectors 70 if(file_name != null) 71 addAttribute(new SourceFile(cp.addUtf8("SourceFile"), 2, 72 cp.addUtf8(file_name), cp.getConstantPool())); 73 74 class_name_index = cp.addClass(class_name); 75 superclass_name_index = cp.addClass(super_class_name); 76 77 if(interfaces != null) 78 for(int i=0; i < interfaces.length; i++) 79 addInterface(interfaces[i]); 80 } 81 82 /** Convenience constructor to set up some important values initially. 83 * 84 * @param class_name fully qualified class name 85 * @param super_class_name fully qualified superclass name 86 * @param file_name source file name 87 * @param access_flags access qualifiers 88 * @param interfaces implemented interfaces 89 */ 90 public ClassGen(String class_name, String super_class_name, String file_name, 91 int access_flags, String[] interfaces) { 92 this(class_name, super_class_name, file_name, access_flags, interfaces, 93 new ConstantPoolGen()); 94 } 95 96 /** 97 * Initialize with existing class. 98 * @param clazz JavaClass object (e.g. read from file) 99 */ 100 public ClassGen(JavaClass clazz) { 101 class_name_index = clazz.getClassNameIndex(); 102 superclass_name_index = clazz.getSuperclassNameIndex(); 103 class_name = clazz.getClassName(); 104 super_class_name = clazz.getSuperclassName(); 105 file_name = clazz.getSourceFileName(); 106 access_flags = clazz.getAccessFlags(); 107 cp = new ConstantPoolGen(clazz.getConstantPool()); 108 major = clazz.getMajor(); 109 minor = clazz.getMinor(); 110 111 Attribute[] attributes = clazz.getAttributes(); 112 Method[] methods = clazz.getMethods(); 113 Field[] fields = clazz.getFields(); 114 String[] interfaces = clazz.getInterfaceNames(); 115 116 for(int i=0; i < interfaces.length; i++) 117 addInterface(interfaces[i]); 118 119 for(int i=0; i < attributes.length; i++) 120 addAttribute(attributes[i]); 121 122 for(int i=0; i < methods.length; i++) 123 addMethod(methods[i]); 124 125 for(int i=0; i < fields.length; i++) 126 addField(fields[i]); 127 } 128 129 /** 130 * @return the (finally) built up Java class object. 131 */ 132 public JavaClass getJavaClass() { 133 int[] interfaces = getInterfaces(); 134 Field[] fields = getFields(); 135 Method[] methods = getMethods(); 136 Attribute[] attributes = getAttributes(); 137 138 // Must be last since the above calls may still add something to it 139 ConstantPool cp = this.cp.getFinalConstantPool(); 140 141 return new JavaClass(class_name_index, superclass_name_index, 142 file_name, major, minor, access_flags, 143 cp, interfaces, fields, methods, attributes); 144 } 145 146 /** 147 * Add an interface to this class, i.e., this class has to implement it. 148 * @param name interface to implement (fully qualified class name) 149 */ 150 public void addInterface(String name) { 151 interface_vec.add(name); 152 } 153 154 /** 155 * Remove an interface from this class. 156 * @param name interface to remove (fully qualified name) 157 */ 158 public void removeInterface(String name) { 159 interface_vec.remove(name); 160 } 161 162 /** 163 * @return major version number of class file 164 */ 165 public int getMajor() { return major; } 166 167 /** Set major version number of class file, default value is 45 (JDK 1.1) 168 * @param major major version number 169 */ 170 public void setMajor(int major) { 171 this.major = major; 172 } 173 174 /** Set minor version number of class file, default value is 3 (JDK 1.1) 175 * @param minor minor version number 176 */ 177 public void setMinor(int minor) { 178 this.minor = minor; 179 } 180 181 /** 182 * @return minor version number of class file 183 */ 184 public int getMinor() { return minor; } 185 186 /** 187 * Add an attribute to this class. 188 * @param a attribute to add 189 */ 190 public void addAttribute(Attribute a) { attribute_vec.add(a); } 191 192 /** 193 * Add a method to this class. 194 * @param m method to add 195 */ 196 public void addMethod(Method m) { method_vec.add(m); } 197 198 /** 199 * Convenience method. 200 * 201 * Add an empty constructor to this class that does nothing but calling super(). 202 * @param access rights for constructor 203 */ 204 public void addEmptyConstructor(int access_flags) { 205 InstructionList il = new InstructionList(); 206 il.append(InstructionConstants.THIS); // Push `this' 207 il.append(new INVOKESPECIAL(cp.addMethodref(super_class_name, 208 "<init>", "()V"))); 209 il.append(InstructionConstants.RETURN); 210 211 MethodGen mg = new MethodGen(access_flags, Type.VOID, Type.NO_ARGS, null, 212 "<init>", class_name, il, cp); 213 mg.setMaxStack(1); 214 addMethod(mg.getMethod()); 215 } 216 217 /** 218 * Add a field to this class. 219 * @param f field to add 220 */ 221 public void addField(Field f) { field_vec.add(f); } 222 223 public boolean containsField(Field f) { return field_vec.contains(f); } 224 225 /** @return field object with given name, or null 226 */ 227 public Field containsField(String name) { 228 for(Iterator e=field_vec.iterator(); e.hasNext(); ) { 229 Field f = (Field)e.next(); 230 if(f.getName().equals(name)) 231 return f; 232 } 233 234 return null; 235 } 236 237 /** @return method object with given name and signature, or null 238 */ 239 public Method containsMethod(String name, String signature) { 240 for(Iterator e=method_vec.iterator(); e.hasNext();) { 241 Method m = (Method)e.next(); 242 if(m.getName().equals(name) && m.getSignature().equals(signature)) 243 return m; 244 } 245 246 return null; 247 } 248 249 /** 250 * Remove an attribute from this class. 251 * @param a attribute to remove 252 */ 253 public void removeAttribute(Attribute a) { attribute_vec.remove(a); } 254 255 /** 256 * Remove a method from this class. 257 * @param m method to remove 258 */ 259 public void removeMethod(Method m) { method_vec.remove(m); } 260 261 /** Replace given method with new one. If the old one does not exist 262 * add the new_ method to the class anyway. 263 */ 264 public void replaceMethod(Method old, Method new_) { 265 if(new_ == null) 266 throw new ClassGenException("Replacement method must not be null"); 267 268 int i = method_vec.indexOf(old); 269 270 if(i < 0) 271 method_vec.add(new_); 272 else 273 method_vec.set(i, new_); 274 } 275 276 /** Replace given field with new one. If the old one does not exist 277 * add the new_ field to the class anyway. 278 */ 279 public void replaceField(Field old, Field new_) { 280 if(new_ == null) 281 throw new ClassGenException("Replacement method must not be null"); 282 283 int i = field_vec.indexOf(old); 284 285 if(i < 0) 286 field_vec.add(new_); 287 else 288 field_vec.set(i, new_); 289 } 290 291 /** 292 * Remove a field to this class. 293 * @param f field to remove 294 */ 295 public void removeField(Field f) { field_vec.remove(f); } 296 297 public String getClassName() { return class_name; } 298 public String getSuperclassName() { return super_class_name; } 299 public String getFileName() { return file_name; } 300 301 public void setClassName(String name) { 302 class_name = name.replace('/', '.'); 303 class_name_index = cp.addClass(name); 304 } 305 306 public void setSuperclassName(String name) { 307 super_class_name = name.replace('/', '.'); 308 superclass_name_index = cp.addClass(name); 309 } 310 311 public Method[] getMethods() { 312 Method[] methods = new Method[method_vec.size()]; 313 method_vec.toArray(methods); 314 return methods; 315 } 316 317 public void setMethods(Method[] methods) { 318 method_vec.clear(); 319 for(int m=0; m<methods.length; m++) 320 addMethod(methods[m]); 321 } 322 323 public void setMethodAt(Method method, int pos) { 324 method_vec.set(pos, method); 325 } 326 327 public Method getMethodAt(int pos) { 328 return (Method)method_vec.get(pos); 329 } 330 331 public String[] getInterfaceNames() { 332 int size = interface_vec.size(); 333 String[] interfaces = new String[size]; 334 335 interface_vec.toArray(interfaces); 336 return interfaces; 337 } 338 339 public int[] getInterfaces() { 340 int size = interface_vec.size(); 341 int[] interfaces = new int[size]; 342 343 for(int i=0; i < size; i++) 344 interfaces[i] = cp.addClass((String)interface_vec.get(i)); 345 346 return interfaces; 347 } 348 349 public Field[] getFields() { 350 Field[] fields = new Field[field_vec.size()]; 351 field_vec.toArray(fields); 352 return fields; 353 } 354 355 public Attribute[] getAttributes() { 356 Attribute[] attributes = new Attribute[attribute_vec.size()]; 357 attribute_vec.toArray(attributes); 358 return attributes; 359 } 360 361 public ConstantPoolGen getConstantPool() { return cp; } 362 public void setConstantPool(ConstantPoolGen constant_pool) { 363 cp = constant_pool; 364 } 365 366 public void setClassNameIndex(int class_name_index) { 367 this.class_name_index = class_name_index; 368 class_name = cp.getConstantPool(). 369 getConstantString(class_name_index, Constants.CONSTANT_Class).replace('/', '.'); 370 } 371 372 public void setSuperclassNameIndex(int superclass_name_index) { 373 this.superclass_name_index = superclass_name_index; 374 super_class_name = cp.getConstantPool(). 375 getConstantString(superclass_name_index, Constants.CONSTANT_Class).replace('/', '.'); 376 } 377 378 public int getSuperclassNameIndex() { return superclass_name_index; } 379 380 public int getClassNameIndex() { return class_name_index; } 381 382 private ArrayList observers; 383 384 /** Add observer for this object. 385 */ 386 public void addObserver(ClassObserver o) { 387 if(observers == null) 388 observers = new ArrayList(); 389 390 observers.add(o); 391 } 392 393 /** Remove observer for this object. 394 */ 395 public void removeObserver(ClassObserver o) { 396 if(observers != null) 397 observers.remove(o); 398 } 399 400 /** Call notify() method on all observers. This method is not called 401 * automatically whenever the state has changed, but has to be 402 * called by the user after he has finished editing the object. 403 */ 404 public void update() { 405 if(observers != null) 406 for(Iterator e = observers.iterator(); e.hasNext(); ) 407 ((ClassObserver)e.next()).notify(this); 408 } 409 410 public Object clone() { 411 try { 412 return super.clone(); 413 } catch(CloneNotSupportedException e) { 414 System.err.println(e); 415 return null; 416 } 417 } 418 }