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 } | 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 package com.sun.org.apache.bcel.internal.generic; 22 23 import java.util.ArrayList; 24 import java.util.List; 25 26 import com.sun.org.apache.bcel.internal.Const; 27 import com.sun.org.apache.bcel.internal.classfile.AccessFlags; 28 import com.sun.org.apache.bcel.internal.classfile.AnnotationEntry; 29 import com.sun.org.apache.bcel.internal.classfile.Annotations; 30 import com.sun.org.apache.bcel.internal.classfile.Attribute; 31 import com.sun.org.apache.bcel.internal.classfile.ConstantPool; 32 import com.sun.org.apache.bcel.internal.classfile.Field; 33 import com.sun.org.apache.bcel.internal.classfile.JavaClass; 34 import com.sun.org.apache.bcel.internal.classfile.Method; 35 import com.sun.org.apache.bcel.internal.classfile.RuntimeInvisibleAnnotations; 36 import com.sun.org.apache.bcel.internal.classfile.RuntimeVisibleAnnotations; 37 import com.sun.org.apache.bcel.internal.classfile.SourceFile; 38 import com.sun.org.apache.bcel.internal.util.BCELComparator; 39 40 /** 41 * Template class for building up a java class. May be initialized with an 42 * existing java class (file). 43 * 44 * @see JavaClass 45 * @version $Id: ClassGen.java 1749603 2016-06-21 20:50:19Z ggregory $ 46 */ 47 public class ClassGen extends AccessFlags implements Cloneable { 48 49 /* Corresponds to the fields found in a JavaClass object. 50 */ 51 private String class_name; 52 private String super_class_name; 53 private final String file_name; 54 private int class_name_index = -1; 55 private int superclass_name_index = -1; 56 private int major = Const.MAJOR; 57 private int minor = Const.MINOR; 58 private ConstantPoolGen cp; // Template for building up constant pool 59 // ArrayLists instead of arrays to gather fields, methods, etc. 60 private final List<Field> field_vec = new ArrayList<>(); 61 private final List<Method> method_vec = new ArrayList<>(); 62 private final List<Attribute> attribute_vec = new ArrayList<>(); 63 private final List<String> interface_vec = new ArrayList<>(); 64 private final List<AnnotationEntryGen> annotation_vec = new ArrayList<>(); 65 66 private static BCELComparator _cmp = new BCELComparator() { 67 68 @Override 69 public boolean equals(final Object o1, final Object o2) { 70 final ClassGen THIS = (ClassGen) o1; 71 final ClassGen THAT = (ClassGen) o2; 72 return THIS.getClassName().equals(THAT.getClassName()); 73 } 74 75 @Override 76 public int hashCode(final Object o) { 77 final ClassGen THIS = (ClassGen) o; 78 return THIS.getClassName().hashCode(); 79 } 80 }; 81 82 /** 83 * Convenience constructor to set up some important values initially. 84 * 85 * @param class_name fully qualified class name 86 * @param super_class_name fully qualified superclass name 87 * @param file_name source file name 88 * @param access_flags access qualifiers 89 * @param interfaces implemented interfaces 90 * @param cp constant pool to use 91 */ 92 public ClassGen(final String class_name, final String super_class_name, final String file_name, final int access_flags, 93 final String[] interfaces, final ConstantPoolGen cp) { 94 super(access_flags); 95 this.class_name = class_name; 96 this.super_class_name = super_class_name; 97 this.file_name = file_name; 98 this.cp = cp; 99 // Put everything needed by default into the constant pool and the vectors 100 if (file_name != null) { 101 addAttribute(new SourceFile(cp.addUtf8("SourceFile"), 2, cp.addUtf8(file_name), cp 102 .getConstantPool())); 103 } 104 class_name_index = cp.addClass(class_name); 105 superclass_name_index = cp.addClass(super_class_name); 106 if (interfaces != null) { 107 for (final String interface1 : interfaces) { 108 addInterface(interface1); 109 } 110 } 111 } 112 113 /** 114 * Convenience constructor to set up some important values initially. 115 * 116 * @param class_name fully qualified class name 117 * @param super_class_name fully qualified superclass name 118 * @param file_name source file name 119 * @param access_flags access qualifiers 120 * @param interfaces implemented interfaces 121 */ 122 public ClassGen(final String class_name, final String super_class_name, final String file_name, final int access_flags, 123 final String[] interfaces) { 124 this(class_name, super_class_name, file_name, access_flags, interfaces, 125 new ConstantPoolGen()); 126 } 127 128 /** 129 * Initialize with existing class. 130 * 131 * @param clazz JavaClass object (e.g. read from file) 132 */ 133 public ClassGen(final JavaClass clazz) { 134 super(clazz.getAccessFlags()); 135 class_name_index = clazz.getClassNameIndex(); 136 superclass_name_index = clazz.getSuperclassNameIndex(); 137 class_name = clazz.getClassName(); 138 super_class_name = clazz.getSuperclassName(); 139 file_name = clazz.getSourceFileName(); 140 cp = new ConstantPoolGen(clazz.getConstantPool()); 141 major = clazz.getMajor(); 142 minor = clazz.getMinor(); 143 final Attribute[] attributes = clazz.getAttributes(); 144 // J5TODO: Could make unpacking lazy, done on first reference 145 final AnnotationEntryGen[] annotations = unpackAnnotations(attributes); 146 final Method[] methods = clazz.getMethods(); 147 final Field[] fields = clazz.getFields(); 148 final String[] interfaces = clazz.getInterfaceNames(); 149 for (final String interface1 : interfaces) { 150 addInterface(interface1); 151 } 152 for (final Attribute attribute : attributes) { 153 if (!(attribute instanceof Annotations)) { 154 addAttribute(attribute); 155 } 156 } 157 for (final AnnotationEntryGen annotation : annotations) { 158 addAnnotationEntry(annotation); 159 } 160 for (final Method method : methods) { 161 addMethod(method); 162 } 163 for (final Field field : fields) { 164 addField(field); 165 } 166 } 167 168 /** 169 * Look for attributes representing annotations and unpack them. 170 */ 171 private AnnotationEntryGen[] unpackAnnotations(final Attribute[] attrs) { 172 final List<AnnotationEntryGen> annotationGenObjs = new ArrayList<>(); 173 for (final Attribute attr : attrs) { 174 if (attr instanceof RuntimeVisibleAnnotations) { 175 final RuntimeVisibleAnnotations rva = (RuntimeVisibleAnnotations) attr; 176 final AnnotationEntry[] annos = rva.getAnnotationEntries(); 177 for (final AnnotationEntry a : annos) { 178 annotationGenObjs.add(new AnnotationEntryGen(a, 179 getConstantPool(), false)); 180 } 181 } else if (attr instanceof RuntimeInvisibleAnnotations) { 182 final RuntimeInvisibleAnnotations ria = (RuntimeInvisibleAnnotations) attr; 183 final AnnotationEntry[] annos = ria.getAnnotationEntries(); 184 for (final AnnotationEntry a : annos) { 185 annotationGenObjs.add(new AnnotationEntryGen(a, 186 getConstantPool(), false)); 187 } 188 } 189 } 190 return annotationGenObjs.toArray(new AnnotationEntryGen[annotationGenObjs.size()]); 191 } 192 193 /** 194 * @return the (finally) built up Java class object. 195 */ 196 public JavaClass getJavaClass() { 197 final int[] interfaces = getInterfaces(); 198 final Field[] fields = getFields(); 199 final Method[] methods = getMethods(); 200 Attribute[] attributes; 201 if (annotation_vec.isEmpty()) { 202 attributes = getAttributes(); 203 } else { 204 // TODO: Sometime later, trash any attributes called 'RuntimeVisibleAnnotations' or 'RuntimeInvisibleAnnotations' 205 final Attribute[] annAttributes = AnnotationEntryGen.getAnnotationAttributes(cp, getAnnotationEntries()); 206 attributes = new Attribute[attribute_vec.size() + annAttributes.length]; 207 attribute_vec.toArray(attributes); 208 System.arraycopy(annAttributes, 0, attributes, attribute_vec.size(), annAttributes.length); 209 } 210 // Must be last since the above calls may still add something to it 211 final ConstantPool _cp = this.cp.getFinalConstantPool(); 212 return new JavaClass(class_name_index, superclass_name_index, file_name, major, minor, 213 super.getAccessFlags(), _cp, interfaces, fields, methods, attributes); 214 } 215 216 /** 217 * Add an interface to this class, i.e., this class has to implement it. 218 * 219 * @param name interface to implement (fully qualified class name) 220 */ 221 public final void addInterface(final String name) { 222 interface_vec.add(name); 223 } 224 225 /** 226 * Remove an interface from this class. 227 * 228 * @param name interface to remove (fully qualified name) 229 */ 230 public void removeInterface(final String name) { 231 interface_vec.remove(name); 232 } 233 234 /** 235 * @return major version number of class file 236 */ 237 public int getMajor() { 238 return major; 239 } 240 241 /** 242 * Set major version number of class file, default value is 45 (JDK 1.1) 243 * 244 * @param major major version number 245 */ 246 public void setMajor(final int major) { // TODO could be package-protected - only called by test code 247 this.major = major; 248 } 249 250 /** 251 * Set minor version number of class file, default value is 3 (JDK 1.1) 252 * 253 * @param minor minor version number 254 */ 255 public void setMinor(final int minor) { // TODO could be package-protected - only called by test code 256 this.minor = minor; 257 } 258 259 /** 260 * @return minor version number of class file 261 */ 262 public int getMinor() { 263 return minor; 264 } 265 266 /** 267 * Add an attribute to this class. 268 * 269 * @param a attribute to add 270 */ 271 public final void addAttribute(final Attribute a) { 272 attribute_vec.add(a); 273 } 274 275 public final void addAnnotationEntry(final AnnotationEntryGen a) { 276 annotation_vec.add(a); 277 } 278 279 /** 280 * Add a method to this class. 281 * 282 * @param m method to add 283 */ 284 public final void addMethod(final Method m) { 285 method_vec.add(m); 286 } 287 288 /** 289 * Convenience method. 290 * 291 * Add an empty constructor to this class that does nothing but calling 292 * super(). 293 * 294 * @param access_flags rights for constructor 295 */ 296 public void addEmptyConstructor(final int access_flags) { 297 final InstructionList il = new InstructionList(); 298 il.append(InstructionConst.THIS); // Push `this' 299 il.append(new INVOKESPECIAL(cp.addMethodref(super_class_name, "<init>", "()V"))); 300 il.append(InstructionConst.RETURN); 301 final MethodGen mg = new MethodGen(access_flags, Type.VOID, Type.NO_ARGS, null, "<init>", 302 class_name, il, cp); 303 mg.setMaxStack(1); 304 addMethod(mg.getMethod()); 305 } 306 307 /** 308 * Add a field to this class. 309 * 310 * @param f field to add 311 */ 312 public final void addField(final Field f) { 313 field_vec.add(f); 314 } 315 316 public boolean containsField(final Field f) { 317 return field_vec.contains(f); 318 } 319 320 /** 321 * @return field object with given name, or null 322 */ 323 public Field containsField(final String name) { 324 for (final Field f : field_vec) { 325 if (f.getName().equals(name)) { 326 return f; 327 } 328 } 329 return null; 330 } 331 332 /** 333 * @return method object with given name and signature, or null 334 */ 335 public Method containsMethod(final String name, final String signature) { 336 for (final Method m : method_vec) { 337 if (m.getName().equals(name) && m.getSignature().equals(signature)) { 338 return m; 339 } 340 } 341 return null; 342 } 343 344 /** 345 * Remove an attribute from this class. 346 * 347 * @param a attribute to remove 348 */ 349 public void removeAttribute(final Attribute a) { 350 attribute_vec.remove(a); 351 } 352 353 /** 354 * Remove a method from this class. 355 * 356 * @param m method to remove 357 */ 358 public void removeMethod(final Method m) { 359 method_vec.remove(m); 360 } 361 362 /** 363 * Replace given method with new one. If the old one does not exist add the 364 * new_ method to the class anyway. 365 */ 366 public void replaceMethod(final Method old, final Method new_) { 367 if (new_ == null) { 368 throw new ClassGenException("Replacement method must not be null"); 369 } 370 final int i = method_vec.indexOf(old); 371 if (i < 0) { 372 method_vec.add(new_); 373 } else { 374 method_vec.set(i, new_); 375 } 376 } 377 378 /** 379 * Replace given field with new one. If the old one does not exist add the 380 * new_ field to the class anyway. 381 */ 382 public void replaceField(final Field old, final Field new_) { 383 if (new_ == null) { 384 throw new ClassGenException("Replacement method must not be null"); 385 } 386 final int i = field_vec.indexOf(old); 387 if (i < 0) { 388 field_vec.add(new_); 389 } else { 390 field_vec.set(i, new_); 391 } 392 } 393 394 /** 395 * Remove a field to this class. 396 * 397 * @param f field to remove 398 */ 399 public void removeField(final Field f) { 400 field_vec.remove(f); 401 } 402 403 public String getClassName() { 404 return class_name; 405 } 406 407 public String getSuperclassName() { 408 return super_class_name; 409 } 410 411 public String getFileName() { 412 return file_name; 413 } 414 415 public void setClassName(final String name) { 416 class_name = name.replace('/', '.'); 417 class_name_index = cp.addClass(name); 418 } 419 420 public void setSuperclassName(final String name) { 421 super_class_name = name.replace('/', '.'); 422 superclass_name_index = cp.addClass(name); 423 } 424 425 public Method[] getMethods() { 426 return method_vec.toArray(new Method[method_vec.size()]); 427 } 428 429 public void setMethods(final Method[] methods) { 430 method_vec.clear(); 431 for (final Method method : methods) { 432 addMethod(method); 433 } 434 } 435 436 public void setMethodAt(final Method method, final int pos) { 437 method_vec.set(pos, method); 438 } 439 440 public Method getMethodAt(final int pos) { 441 return method_vec.get(pos); 442 } 443 444 public String[] getInterfaceNames() { 445 final int size = interface_vec.size(); 446 final String[] interfaces = new String[size]; 447 interface_vec.toArray(interfaces); 448 return interfaces; 449 } 450 451 public int[] getInterfaces() { 452 final int size = interface_vec.size(); 453 final int[] interfaces = new int[size]; 454 for (int i = 0; i < size; i++) { 455 interfaces[i] = cp.addClass(interface_vec.get(i)); 456 } 457 return interfaces; 458 } 459 460 public Field[] getFields() { 461 return field_vec.toArray(new Field[field_vec.size()]); 462 } 463 464 public Attribute[] getAttributes() { 465 return attribute_vec.toArray(new Attribute[attribute_vec.size()]); 466 } 467 468 // J5TODO: Should we make calling unpackAnnotations() lazy and put it in here? 469 public AnnotationEntryGen[] getAnnotationEntries() { 470 return annotation_vec.toArray(new AnnotationEntryGen[annotation_vec.size()]); 471 } 472 473 public ConstantPoolGen getConstantPool() { 474 return cp; 475 } 476 477 public void setConstantPool(final ConstantPoolGen constant_pool) { 478 cp = constant_pool; 479 } 480 481 public void setClassNameIndex(final int class_name_index) { 482 this.class_name_index = class_name_index; 483 class_name = cp.getConstantPool().getConstantString(class_name_index, 484 Const.CONSTANT_Class).replace('/', '.'); 485 } 486 487 public void setSuperclassNameIndex(final int superclass_name_index) { 488 this.superclass_name_index = superclass_name_index; 489 super_class_name = cp.getConstantPool().getConstantString(superclass_name_index, 490 Const.CONSTANT_Class).replace('/', '.'); 491 } 492 493 public int getSuperclassNameIndex() { 494 return superclass_name_index; 495 } 496 497 public int getClassNameIndex() { 498 return class_name_index; 499 } 500 501 private List<ClassObserver> observers; 502 503 /** 504 * Add observer for this object. 505 */ 506 public void addObserver(final ClassObserver o) { 507 if (observers == null) { 508 observers = new ArrayList<>(); 509 } 510 observers.add(o); 511 } 512 513 /** 514 * Remove observer for this object. 515 */ 516 public void removeObserver(final ClassObserver o) { 517 if (observers != null) { 518 observers.remove(o); 519 } 520 } 521 522 /** 523 * Call notify() method on all observers. This method is not called 524 * automatically whenever the state has changed, but has to be called by the 525 * user after he has finished editing the object. 526 */ 527 public void update() { 528 if (observers != null) { 529 for (final ClassObserver observer : observers) { 530 observer.notify(this); 531 } 532 } 533 } 534 535 @Override 536 public Object clone() { 537 try { 538 return super.clone(); 539 } catch (final CloneNotSupportedException e) { 540 throw new Error("Clone Not Supported"); // never happens 541 } 542 } 543 544 /** 545 * @return Comparison strategy object 546 */ 547 public static BCELComparator getComparator() { 548 return _cmp; 549 } 550 551 /** 552 * @param comparator Comparison strategy object 553 */ 554 public static void setComparator(final BCELComparator comparator) { 555 _cmp = comparator; 556 } 557 558 /** 559 * Return value as defined by given BCELComparator strategy. By default two 560 * ClassGen objects are said to be equal when their class names are equal. 561 * 562 * @see java.lang.Object#equals(java.lang.Object) 563 */ 564 @Override 565 public boolean equals(final Object obj) { 566 return _cmp.equals(this, obj); 567 } 568 569 /** 570 * Return value as defined by given BCELComparator strategy. By default 571 * return the hashcode of the class name. 572 * 573 * @see java.lang.Object#hashCode() 574 */ 575 @Override 576 public int hashCode() { 577 return _cmp.hashCode(this); 578 } 579 } |