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