1 package serp.bytecode;
2
3 import java.io.*;
4 import java.net.*;
5 import java.util.*;
6
7 import serp.bytecode.lowlevel.*;
8 import serp.bytecode.visitor.*;
9 import serp.util.*;
10
11 /***
12 * The BCClass represents a class object in the bytecode framework, in many
13 * ways mirroring the {@link Class} class of Java reflection. The represented
14 * class might be a primitive, array, existing object type, or some new user-
15 * defined type. As with most entities in the bytecode framework, the BCClass
16 * contains methods to manipulate the low-level state of the class (constant
17 * pool indexes, etc), but these can and should be ignored in
18 * favor of the available high-level methods.
19 *
20 * <p>A BCClass instance is loaded from a {@link Project} and remains
21 * attached to that project for its lifetime. If a BCClass is removed from
22 * its project, the result of any further operations on the class are
23 * undefined.</p>
24 *
25 * <p>Note that if a BCClass represents a primitive or array type, all of the
26 * available mutator methods and any methods that access the constant pool
27 * will throw {@link UnsupportedOperationException}s.</p>
28 *
29 * @author Abe White
30 */
31 public class BCClass extends Annotated implements VisitAcceptor {
32 private Project _project = null;
33 private State _state = null;
34 private ClassLoader _loader = null;
35
36 /***
37 * Hide constructor. For use by the owning project only.
38 */
39 BCClass(Project project) {
40 _project = project;
41 }
42
43 /***
44 * Set the class state. For use by the owning project only.
45 */
46 void setState(State state) {
47 _state = state;
48 }
49
50 /***
51 * Invalidate this class.
52 */
53 void invalidate() {
54 _project = null;
55 _state = State.INVALID;
56 }
57
58
59
60
61
62 /***
63 * Initialize from the class definition in the given file. For use by
64 * the owning project only.
65 */
66 void read(File classFile, ClassLoader loader) throws IOException {
67 InputStream in = new FileInputStream(classFile);
68 try {
69 read(in, loader);
70 } finally {
71 in.close();
72 }
73 }
74
75 /***
76 * Initialize from the class definition in the given stream. For use by
77 * the owning project only.
78 */
79 void read(InputStream instream, ClassLoader loader)
80 throws IOException {
81 DataInput in = new DataInputStream(instream);
82
83
84 _state.setMagic(in.readInt());
85 _state.setMinorVersion(in.readUnsignedShort());
86 _state.setMajorVersion(in.readUnsignedShort());
87
88
89 _state.getPool().read(in);
90
91
92 _state.setAccessFlags(in.readUnsignedShort());
93
94
95 _state.setIndex(in.readUnsignedShort());
96 _state.setSuperclassIndex(in.readUnsignedShort());
97
98 List interfaces = _state.getInterfacesHolder();
99 interfaces.clear();
100 int interfaceCount = in.readUnsignedShort();
101 for (int i = 0; i < interfaceCount; i++)
102 interfaces.add(Numbers.valueOf(in.readUnsignedShort()));
103
104
105 List fields = _state.getFieldsHolder();
106 fields.clear();
107 int fieldCount = in.readUnsignedShort();
108 BCField field;
109 for (int i = 0; i < fieldCount; i++) {
110 field = new BCField(this);
111 fields.add(field);
112 field.read(in);
113 }
114
115
116 List methods = _state.getMethodsHolder();
117 methods.clear();
118 int methodCount = in.readUnsignedShort();
119 BCMethod method;
120 for (int i = 0; i < methodCount; i++) {
121 method = new BCMethod(this);
122 methods.add(method);
123 method.read(in);
124 }
125
126 readAttributes(in);
127 _loader = loader;
128 }
129
130 /***
131 * Initialize from the bytecode of the definition of the given class.
132 * For use by the owning project only.
133 */
134 void read(Class type) throws IOException {
135
136 int dotIndex = type.getName().lastIndexOf('.') + 1;
137
138
139 String className = type.getName().substring(dotIndex);
140
141
142 InputStream in = type.getResourceAsStream(className + ".class");
143 try {
144 read(in, type.getClassLoader());
145 } finally {
146 in.close();
147 }
148 }
149
150 /***
151 * Initialize from the given parsed bytecode.
152 * For use by the owning project only.
153 */
154 void read(BCClass orig) {
155 try {
156 ByteArrayInputStream in = new ByteArrayInputStream
157 (orig.toByteArray());
158 read(in, orig.getClassLoader());
159 in.close();
160 } catch (IOException ioe) {
161 throw new RuntimeException(ioe.toString());
162 }
163 }
164
165 /***
166 * Write the class bytecode to the .class file in the proper directory of
167 * the CLASSPATH. The file must exist already, so this method only works
168 * on existing classes.
169 */
170 public void write() throws IOException {
171 String name = getName();
172 int dotIndex = name.lastIndexOf('.') + 1;
173 name = name.substring(dotIndex);
174 Class type = getType();
175
176
177
178
179 OutputStream out = new FileOutputStream(URLDecoder.decode
180 (type.getResource(name + ".class").getFile()));
181 try {
182 write(out);
183 } finally {
184 out.close();
185 }
186 }
187
188 /***
189 * Write the class bytecode to the specified file.
190 */
191 public void write(File classFile) throws IOException {
192 OutputStream out = new FileOutputStream(classFile);
193 try {
194 write(out);
195 } finally {
196 out.close();
197 }
198 }
199
200 /***
201 * Write the class bytecode to the specified stream.
202 */
203 public void write(OutputStream outstream) throws IOException {
204 DataOutput out = new DataOutputStream(outstream);
205
206
207 out.writeInt(_state.getMagic());
208 out.writeShort(_state.getMinorVersion());
209 out.writeShort(_state.getMajorVersion());
210
211
212 _state.getPool().write(out);
213
214
215 out.writeShort(_state.getAccessFlags());
216
217
218 out.writeShort(_state.getIndex());
219 out.writeShort(_state.getSuperclassIndex());
220
221
222 List interfaces = _state.getInterfacesHolder();
223 out.writeShort(interfaces.size());
224 for (Iterator itr = interfaces.iterator(); itr.hasNext();)
225 out.writeShort(((Number) itr.next()).intValue());
226
227
228 List fields = _state.getFieldsHolder();
229 out.writeShort(fields.size());
230 for (Iterator itr = fields.iterator(); itr.hasNext();)
231 ((BCField) itr.next()).write(out);
232
233
234 List methods = _state.getMethodsHolder();
235 out.writeShort(methods.size());
236 for (Iterator itr = methods.iterator(); itr.hasNext();)
237 ((BCMethod) itr.next()).write(out);
238
239
240 writeAttributes(out);
241 }
242
243 /***
244 * Return the bytecode of this class as a byte array, possibly for use
245 * in a custom {@link ClassLoader}.
246 */
247 public byte[] toByteArray() {
248 ByteArrayOutputStream out = new ByteArrayOutputStream();
249 try {
250 write(out);
251 out.flush();
252 return out.toByteArray();
253 } catch (IOException ioe) {
254 throw new RuntimeException(ioe.toString());
255 } finally {
256 try { out.close(); } catch (IOException ioe) {}
257 }
258 }
259
260
261
262
263
264 /***
265 * Return the magic number for this class; if this is a valid type, this
266 * should be equal to {@link Constants#VALID_MAGIC} (the default value).
267 */
268 public int getMagic() {
269 return _state.getMagic();
270 }
271
272 /***
273 * Set the magic number for this class; if this is a valid type, this
274 * should be equal to {@link Constants#VALID_MAGIC} (the default value).
275 */
276 public void setMagic(int magic) {
277 _state.setMagic(magic);
278 }
279
280 /***
281 * Return the major version of the bytecode spec used for this class.
282 * JVMs are only required to operate with versions that they understand;
283 * leaving the default value of {@link Constants#MAJOR_VERSION} is safe.
284 */
285 public int getMajorVersion() {
286 return _state.getMajorVersion();
287 }
288
289 /***
290 * Set the major version of the bytecode spec used for this class.
291 * JVMs are only required to operate with versions that they understand;
292 * leaving the default value of {@link Constants#MAJOR_VERSION} is safe.
293 */
294 public void setMajorVersion(int majorVersion) {
295 _state.setMajorVersion(majorVersion);
296 }
297
298 /***
299 * Get the minor version of the bytecode spec used for this class.
300 * JVMs are only required to operate with versions that they understand;
301 * leaving the default value of {@link Constants#MINOR_VERSION} is safe.
302 */
303 public int getMinorVersion() {
304 return _state.getMinorVersion();
305 }
306
307 /***
308 * Set the minor version of the bytecode spec used for this class.
309 * JVMs are only required to operate with versions that they understand;
310 * leaving the default value of {@link Constants#MINOR_VERSION} is safe.
311 */
312 public void setMinorVersion(int minorVersion) {
313 _state.setMinorVersion(minorVersion);
314 }
315
316 /***
317 * Return the access flags for this class as a bit array of
318 * ACCESS_XXX constants from {@link Constants}. This can be used to
319 * transfer access flags between classes without getting/setting each
320 * possible flag.
321 */
322 public int getAccessFlags() {
323 return _state.getAccessFlags();
324 }
325
326 /***
327 * Set the access flags for this class as a bit array of
328 * ACCESS_XXX constants from {@link Constants}. This can be used to
329 * transfer access flags between classes without getting/setting each
330 * possible flag.
331 */
332 public void setAccessFlags(int access) {
333 _state.setAccessFlags(access);
334 }
335
336 /***
337 * Manipulate the class access flags.
338 */
339 public boolean isPublic() {
340 return (getAccessFlags() & Constants.ACCESS_PUBLIC) > 0;
341 }
342
343 /***
344 * Manipulate the class access flags.
345 */
346 public void makePublic() {
347 setAccessFlags(getAccessFlags() | Constants.ACCESS_PUBLIC);
348 }
349
350 /***
351 * Manipulate the class access flags.
352 */
353 public boolean isPackage() {
354 return !isPublic();
355 }
356
357 /***
358 * Manipulate the class access flags.
359 */
360 public void makePackage() {
361 setAccessFlags(getAccessFlags() & ~Constants.ACCESS_PUBLIC);
362 }
363
364 /***
365 * Manipulate the class access flags.
366 */
367 public boolean isFinal() {
368 return (getAccessFlags() & Constants.ACCESS_FINAL) > 0;
369 }
370
371 /***
372 * Manipulate the class access flags.
373 */
374 public void setFinal(boolean on) {
375 if (on)
376 setAccessFlags(getAccessFlags() | Constants.ACCESS_FINAL);
377 else
378 setAccessFlags(getAccessFlags() & ~Constants.ACCESS_FINAL);
379 }
380
381 /***
382 * Manipulate the class access flags.
383 */
384 public boolean isInterface() {
385 return (getAccessFlags() & Constants.ACCESS_INTERFACE) > 0;
386 }
387
388 /***
389 * Manipulate the class access flags.
390 */
391 public void setInterface(boolean on) {
392 if (on) {
393 setAccessFlags(getAccessFlags() | Constants.ACCESS_INTERFACE);
394 setAbstract(true);
395 } else
396 setAccessFlags(getAccessFlags() & ~Constants.ACCESS_INTERFACE);
397 }
398
399 /***
400 * Manipulate the class access flags.
401 */
402 public boolean isAbstract() {
403 return (getAccessFlags() & Constants.ACCESS_ABSTRACT) > 0;
404 }
405
406 /***
407 * Manipulate the class access flags.
408 */
409 public void setAbstract(boolean on) {
410 if (on)
411 setAccessFlags(getAccessFlags() | Constants.ACCESS_ABSTRACT);
412 else
413 setAccessFlags(getAccessFlags() & ~Constants.ACCESS_ABSTRACT);
414 }
415
416 /***
417 * Manipulate the class access flags.
418 */
419 public boolean isSynthetic() {
420 return (getAccessFlags() & Constants.ACCESS_SYNTHETIC) > 0;
421 }
422
423 /***
424 * Manipulate the class access flags.
425 */
426 public void setSynthetic(boolean on) {
427 if (on)
428 setAccessFlags(getAccessFlags() | Constants.ACCESS_SYNTHETIC);
429 else
430 setAccessFlags(getAccessFlags() & ~Constants.ACCESS_SYNTHETIC);
431 }
432
433 /***
434 * Manipulate the class access flags.
435 */
436 public boolean isAnnotation() {
437 return (getAccessFlags() & Constants.ACCESS_ANNOTATION) > 0;
438 }
439
440 /***
441 * Manipulate the class access flags. Setting to true also makes this
442 * an interface.
443 */
444 public void setAnnotation(boolean on) {
445 if (on) {
446 setAccessFlags(getAccessFlags() | Constants.ACCESS_ANNOTATION);
447 setAccessFlags(getAccessFlags() | Constants.ACCESS_INTERFACE);
448 } else
449 setAccessFlags(getAccessFlags() & ~Constants.ACCESS_ANNOTATION);
450 }
451
452 /***
453 * Manipulate the class access flags.
454 */
455 public boolean isEnum() {
456 return (getAccessFlags() & Constants.ACCESS_ENUM) > 0;
457 }
458
459 /***
460 * Manipulate the class access flags.
461 */
462 public void setEnum(boolean on) {
463 if (on)
464 setAccessFlags(getAccessFlags() | Constants.ACCESS_ENUM);
465 else
466 setAccessFlags(getAccessFlags() & ~Constants.ACCESS_ENUM);
467 }
468
469 /***
470 * Return true if this class is a primitive type.
471 */
472 public boolean isPrimitive() {
473 return _state.isPrimitive();
474 }
475
476 /***
477 * Return true if this class is an array type.
478 */
479 public boolean isArray() {
480 return _state.isArray();
481 }
482
483
484
485
486
487 /***
488 * Return the {@link ConstantPool} index of the
489 * {@link ClassEntry} for this class. Returns 0 if the class does not
490 * have a constant pool (such as a primitive or array).
491 */
492 public int getIndex() {
493 return _state.getIndex();
494 }
495
496 /***
497 * Set the {@link ConstantPool} index of the {@link ClassEntry} for this
498 * class. Unlike most other low-level methods, the index
499 * will be checked against the pool immediately;
500 * classes must have a valid name at all times.
501 */
502 public void setIndex(int index) {
503 String oldName = getName();
504 String newName = ((ClassEntry) getPool().getEntry(index)).
505 getNameEntry().getValue();
506 beforeRename(oldName, newName);
507 _state.setIndex(index);
508 }
509
510 /***
511 * Return the name of this class, including package name. The name will
512 * be in a form suitable for a {@link Class#forName} call.
513 */
514 public String getName() {
515 return _state.getName();
516 }
517
518 /***
519 * Return the name of the class only, without package.
520 */
521 public String getClassName() {
522 String name = _project.getNameCache().getExternalForm(getName(), true);
523 return name.substring(name.lastIndexOf('.') + 1);
524 }
525
526 /***
527 * Return the package name only, without class, or null if none.
528 */
529 public String getPackageName() {
530 String name = _project.getNameCache().getExternalForm(getName(), true);
531 int index = name.lastIndexOf('.');
532 if (index == -1)
533 return null;
534 return name.substring(0, index);
535 }
536
537 /***
538 * Set the name of this class, including package name.
539 */
540 public void setName(String name) {
541 name = _project.getNameCache().getExternalForm(name, false);
542 String oldName = getName();
543
544
545 int index = getIndex();
546 if (index == 0)
547 index = getPool().findClassEntry(name, true);
548 ClassEntry entry = (ClassEntry) getPool().getEntry(index);
549
550
551 beforeRename(oldName, name);
552
553
554 int nameIndex = getPool().findUTF8Entry(_project.getNameCache().
555 getInternalForm(name, false), true);
556 entry.setNameIndex(nameIndex);
557
558
559 _state.setIndex(index);
560 }
561
562 /***
563 * Return the {@link Class} object for this class, if it is loadable.
564 */
565 public Class getType() {
566 return Strings.toClass(getName(), getClassLoader());
567 }
568
569 /***
570 * Return the component type name of this class, or null if not an array.
571 * The name will be in a form suitable for a {@link Class#forName} call.
572 */
573 public String getComponentName() {
574 return _state.getComponentName();
575 }
576
577 /***
578 * Return the component type of this class, or null if not an array.
579 */
580 public Class getComponentType() {
581 String componentName = getComponentName();
582 if (componentName == null)
583 return null;
584 return Strings.toClass(componentName, getClassLoader());
585 }
586
587 /***
588 * Return the component type of this class, or null if not an array.
589 */
590 public BCClass getComponentBC() {
591 String componentName = getComponentName();
592 if (componentName == null)
593 return null;
594 return getProject().loadClass(componentName, getClassLoader());
595 }
596
597
598
599
600
601 /***
602 * Return the {@link ConstantPool} index of the
603 * {@link ClassEntry} for the superclass of this class. Returns -1 if
604 * the class does not have a constant pool (such as a primitive or array).
605 */
606 public int getSuperclassIndex() {
607 return _state.getSuperclassIndex();
608 }
609
610 /***
611 * Set the {@link ConstantPool} index of the
612 * {@link ClassEntry} for the superclass of this class.
613 */
614 public void setSuperclassIndex(int index) {
615 _state.setSuperclassIndex(index);
616 }
617
618 /***
619 * Return the name of the superclass for this class, including package
620 * name. The name will be in a form suitable for a
621 * {@link Class#forName} call, or null for types without superclasses.
622 */
623 public String getSuperclassName() {
624 return _state.getSuperclassName();
625 }
626
627 /***
628 * Return the {@link Class} object for the superclass of this class, if it
629 * is loadable. Returns null for types without superclasses.
630 */
631 public Class getSuperclassType() {
632 String name = getSuperclassName();
633 if (name == null)
634 return null;
635 return Strings.toClass(name, getClassLoader());
636 }
637
638 /***
639 * Return the bytecode of the superclass of this class, or
640 * null for types without superclasses.
641 */
642 public BCClass getSuperclassBC() {
643 String name = getSuperclassName();
644 if (name == null)
645 return null;
646 return getProject().loadClass(name, getClassLoader());
647 }
648
649 /***
650 * Set the superclass of this class.
651 */
652 public void setSuperclass(String name) {
653 if (name == null)
654 setSuperclassIndex(0);
655 else
656 setSuperclassIndex(getPool().findClassEntry(_project.getNameCache().
657 getInternalForm(name, false), true));
658 }
659
660 /***
661 * Set the superclass of this class.
662 */
663 public void setSuperclass(Class type) {
664 if (type == null)
665 setSuperclass((String) null);
666 else
667 setSuperclass(type.getName());
668 }
669
670 /***
671 * Set the superclass of this class.
672 */
673 public void setSuperclass(BCClass type) {
674 if (type == null)
675 setSuperclass((String) null);
676 else
677 setSuperclass(type.getName());
678 }
679
680
681
682
683
684 /***
685 * Return the list of {@link ConstantPool} indexes of the
686 * {@link ClassEntry}s describing all the interfaces this class declares
687 * that it implements/extends.
688 *
689 * @return the implmented interfaces, or an empty array if none
690 */
691 public int[] getDeclaredInterfaceIndexes() {
692 List interfaces = _state.getInterfacesHolder();
693 int[] indexes = new int[interfaces.size()];
694 for (int i = 0; i < interfaces.size(); i++)
695 indexes[i] = ((Number) interfaces.get(i)).intValue();
696 return indexes;
697 }
698
699 /***
700 * Set the list of {@link ConstantPool} indexes of the
701 * {@link ClassEntry}s describing all the interfaces this class declares
702 * it implements/extends; set to null or an empty array if none.
703 */
704 public void setDeclaredInterfaceIndexes(int[] interfaceIndexes) {
705 List stateIndexes = _state.getInterfacesHolder();
706 stateIndexes.clear();
707 Integer idx;
708 for (int i = 0; i < interfaceIndexes.length; i++) {
709 idx = Numbers.valueOf(interfaceIndexes[i]);
710 if (!stateIndexes.contains(idx))
711 stateIndexes.add(idx);
712 }
713 }
714
715 /***
716 * Return the names of the interfaces declared for this class, including
717 * package names, or an empty array if none. The names will be in a form
718 * suitable for a {@link Class#forName} call.
719 */
720 public String[] getDeclaredInterfaceNames() {
721 int[] indexes = getDeclaredInterfaceIndexes();
722 String[] names = new String[indexes.length];
723 ClassEntry entry;
724 for (int i = 0; i < indexes.length; i++) {
725 entry = (ClassEntry) getPool().getEntry(indexes[i]);
726 names[i] = _project.getNameCache().getExternalForm
727 (entry.getNameEntry().getValue(), false);
728 }
729 return names;
730 }
731
732 /***
733 * Return the {@link Class} objects for the declared interfaces of this
734 * class, or an empty array if none.
735 */
736 public Class[] getDeclaredInterfaceTypes() {
737 String[] names = getDeclaredInterfaceNames();
738 Class[] types = new Class[names.length];
739 for (int i = 0; i < names.length; i++)
740 types[i] = Strings.toClass(names[i], getClassLoader());
741 return types;
742 }
743
744 /***
745 * Return the bytecode for the declared interfaces of this class, or an
746 * empty array if none.
747 */
748 public BCClass[] getDeclaredInterfaceBCs() {
749 String[] names = getDeclaredInterfaceNames();
750 BCClass[] types = new BCClass[names.length];
751 for (int i = 0; i < names.length; i++)
752 types[i] = getProject().loadClass(names[i], getClassLoader());
753 return types;
754 }
755
756 /***
757 * Set the interfaces declared implemented/extended by this class; set to
758 * null or an empty array if none.
759 */
760 public void setDeclaredInterfaces(String[] interfaces) {
761 clearDeclaredInterfaces();
762 if (interfaces != null)
763 for (int i = 0; i < interfaces.length; i++)
764 declareInterface(interfaces[i]);
765 }
766
767 /***
768 * Set the interfaces declared implemented/extended by this class; set to
769 * null or an empty array if none.
770 */
771 public void setDeclaredInterfaces(Class[] interfaces) {
772 String[] names = null;
773 if (interfaces != null) {
774 names = new String[interfaces.length];
775 for (int i = 0; i < interfaces.length; i++)
776 names[i] = interfaces[i].getName();
777 }
778 setDeclaredInterfaces(names);
779 }
780
781 /***
782 * Set the interfaces declared implemented/extended by this class; set to
783 * null or an empty array if none.
784 */
785 public void setDeclaredInterfaces(BCClass[] interfaces) {
786 String[] names = null;
787 if (interfaces != null) {
788 names = new String[interfaces.length];
789 for (int i = 0; i < interfaces.length; i++)
790 names[i] = interfaces[i].getName();
791 }
792 setDeclaredInterfaces(names);
793 }
794
795 /***
796 * Return the names of all unique interfaces implemented by this class,
797 * including those of all superclasses. The names will be returned in a
798 * form suitable for a {@link Class#forName} call.
799 * This method does not recurse into interfaces-of-interfaces.
800 */
801 public String[] getInterfaceNames() {
802 Collection allNames = new LinkedList();
803 String[] names;
804 for (BCClass type = this; type != null; type = type.getSuperclassBC()) {
805 names = type.getDeclaredInterfaceNames();
806 for (int i = 0; i < names.length; i++)
807 allNames.add(names[i]);
808 }
809 return (String[]) allNames.toArray(new String[allNames.size()]);
810 }
811
812 /***
813 * Return the {@link Class} objects of all unique interfaces implemented
814 * by this class, including those of all superclasses.
815 * This method does not recurse into interfaces-of-interfaces.
816 */
817 public Class[] getInterfaceTypes() {
818 Collection allTypes = new LinkedList();
819 Class[] types;
820 for (BCClass type = this; type != null; type = type.getSuperclassBC()) {
821 types = type.getDeclaredInterfaceTypes();
822 for (int i = 0; i < types.length; i++)
823 allTypes.add(types[i]);
824 }
825 return (Class[]) allTypes.toArray(new Class[allTypes.size()]);
826 }
827
828 /***
829 * Return the bytecode of all unique interfaces implemented by this class,
830 * including those of all superclasses.
831 * This method does not recurse into interfaces-of-interfaces.
832 */
833 public BCClass[] getInterfaceBCs() {
834 Collection allTypes = new LinkedList();
835 BCClass[] types;
836 for (BCClass type = this; type != null; type = type.getSuperclassBC()) {
837 types = type.getDeclaredInterfaceBCs();
838 for (int i = 0; i < types.length; i++)
839 allTypes.add(types[i]);
840 }
841 return (BCClass[]) allTypes.toArray(new BCClass[allTypes.size()]);
842 }
843
844 /***
845 * Clear this class of all interface declarations.
846 */
847 public void clearDeclaredInterfaces() {
848 _state.getInterfacesHolder().clear();
849 }
850
851 /***
852 * Remove an interface declared by this class.
853 *
854 * @return true if the class had the interface, false otherwise
855 */
856 public boolean removeDeclaredInterface(String name) {
857 String[] names = getDeclaredInterfaceNames();
858 Iterator itr = _state.getInterfacesHolder().iterator();
859 for (int i = 0; i < names.length; i++) {
860 itr.next();
861 if (names[i].equals(name)) {
862 itr.remove();
863 return true;
864 }
865 }
866 return false;
867 }
868
869 /***
870 * Remove an interface declared by this class.
871 *
872 * @return true if the class had the interface, false otherwise
873 */
874 public boolean removeDeclaredInterface(Class type) {
875 if (type == null)
876 return false;
877 return removeDeclaredInterface(type.getName());
878 }
879
880 /***
881 * Remove an interface declared by this class.
882 *
883 * @return true if the class had the interface, false otherwise
884 */
885 public boolean removeDeclaredInterface(BCClass type) {
886 if (type == null)
887 return false;
888 return removeDeclaredInterface(type.getName());
889 }
890
891 /***
892 * Rearrange declared interface order.
893 */
894 public void moveDeclaredInterface(int fromIdx, int toIdx) {
895 if (fromIdx == toIdx)
896 return;
897 List interfaces = _state.getInterfacesHolder();
898 Object o = interfaces.remove(fromIdx);
899 interfaces.add(toIdx, o);
900 }
901
902 /***
903 * Add an interface to those declared by this class.
904 */
905 public void declareInterface(String name) {
906 Integer index = Numbers.valueOf(getPool().findClassEntry(_project.
907 getNameCache().getInternalForm(name, false), true));
908 List interfaces = _state.getInterfacesHolder();
909 if (!interfaces.contains(index))
910 interfaces.add(index);
911 }
912
913 /***
914 * Add an interface to those declared by this class.
915 */
916 public void declareInterface(Class type) {
917 declareInterface(type.getName());
918 }
919
920 /***
921 * Add an interface to those declared by this class.
922 */
923 public void declareInterface(BCClass type) {
924 declareInterface(type.getName());
925 }
926
927 /***
928 * Return true if this class or any of its superclasses implement/extend
929 * the given interface/class.
930 * This method does not recurse into interfaces-of-interfaces.
931 */
932 public boolean isInstanceOf(String name) {
933 name = _project.getNameCache().getExternalForm(name, false);
934 String[] interfaces = getInterfaceNames();
935 for (int i = 0; i < interfaces.length; i++)
936 if (interfaces[i].equals(name))
937 return true;
938 for (BCClass type = this; type != null; type = type.getSuperclassBC())
939 if (type.getName().equals(name))
940 return true;
941 return false;
942 }
943
944 /***
945 * Return true if this class or any of its superclasses implement/extend
946 * the given interface/class.
947 * This method does not recurse into interfaces-of-interfaces.
948 */
949 public boolean isInstanceOf(Class type) {
950 if (type == null)
951 return false;
952 return isInstanceOf(type.getName());
953 }
954
955 /***
956 * Return true if this class or any of its superclasses implement/extend
957 * the given interface/class.
958 * This method does not recurse into interfaces-of-interfaces.
959 */
960 public boolean isInstanceOf(BCClass type) {
961 if (type == null)
962 return false;
963 return isInstanceOf(type.getName());
964 }
965
966
967
968
969
970 /***
971 * Return all the declared fields of this class, or an empty array if none.
972 */
973 public BCField[] getDeclaredFields() {
974 List fields = _state.getFieldsHolder();
975 return (BCField[]) fields.toArray(new BCField[fields.size()]);
976 }
977
978 /***
979 * Return the declared field with the given name, or null if none.
980 */
981 public BCField getDeclaredField(String name) {
982 BCField[] fields = getDeclaredFields();
983 for (int i = 0; i < fields.length; i++)
984 if (fields[i].getName().equals(name))
985 return fields[i];
986 return null;
987 }
988
989 /***
990 * Return all the fields of this class, including those of all
991 * superclasses, or an empty array if none.
992 */
993 public BCField[] getFields() {
994 Collection allFields = new LinkedList();
995 BCField[] fields;
996 for (BCClass type = this; type != null; type = type.getSuperclassBC()) {
997 fields = type.getDeclaredFields();
998 for (int i = 0; i < fields.length; i++)
999 allFields.add(fields[i]);
1000 }
1001 return (BCField[]) allFields.toArray(new BCField[allFields.size()]);
1002 }
1003
1004 /***
1005 * Return all fields with the given name, including those of all
1006 * superclasses, or an empty array if none.
1007 */
1008 public BCField[] getFields(String name) {
1009 List matches = new LinkedList();
1010 BCField[] fields = getFields();
1011 for (int i = 0; i < fields.length; i++)
1012 if (fields[i].getName().equals(name))
1013 matches.add(fields[i]);
1014 return (BCField[]) matches.toArray(new BCField[matches.size()]);
1015 }
1016
1017 /***
1018 * Set the fields for this class; this method is useful for importing all
1019 * fields from another class. Set to null or empty array if none.
1020 */
1021 public void setDeclaredFields(BCField[] fields) {
1022 clearDeclaredFields();
1023 if (fields != null)
1024 for (int i = 0; i < fields.length; i++)
1025 declareField(fields[i]);
1026 }
1027
1028 /***
1029 * Import the information from given field as a new field in this class.
1030 *
1031 * @return the added field
1032 */
1033 public BCField declareField(BCField field) {
1034 BCField newField = declareField(field.getName(), field.getTypeName());
1035 newField.setAccessFlags(field.getAccessFlags());
1036 newField.setAttributes(field.getAttributes());
1037 return newField;
1038 }
1039
1040 /***
1041 * Add a field to this class.
1042 *
1043 * @return the added field
1044 */
1045 public BCField declareField(String name, String type) {
1046 BCField field = new BCField(this);
1047 _state.getFieldsHolder().add(field);
1048 field.initialize(name, _project.getNameCache().getInternalForm(type,
1049 true));
1050 return field;
1051 }
1052
1053 /***
1054 * Add a field to this class.
1055 *
1056 * @return the added field
1057 */
1058 public BCField declareField(String name, Class type) {
1059 String typeName = (type == null) ? null : type.getName();
1060 return declareField(name, typeName);
1061 }
1062
1063 /***
1064 * Add a field to this class.
1065 *
1066 * @return the added field
1067 */
1068 public BCField declareField(String name, BCClass type) {
1069 String typeName = (type == null) ? null : type.getName();
1070 return declareField(name, typeName);
1071 }
1072
1073 /***
1074 * Clear all fields from this class.
1075 */
1076 public void clearDeclaredFields() {
1077 List fields = _state.getFieldsHolder();
1078 BCField field;
1079 for (Iterator itr = fields.iterator(); itr.hasNext();) {
1080 field = (BCField) itr.next();
1081 itr.remove();
1082 field.invalidate();
1083 }
1084 }
1085
1086 /***
1087 * Remove a field from this class. After this method, the removed field
1088 * will be invalid, and the result of any operations on it is undefined.
1089 *
1090 * @return true if this class contained the field, false otherwise
1091 */
1092 public boolean removeDeclaredField(String name) {
1093 List fields = _state.getFieldsHolder();
1094 BCField field;
1095 for (Iterator itr = fields.iterator(); itr.hasNext();) {
1096 field = (BCField) itr.next();
1097 if (field.getName().equals(name)) {
1098 itr.remove();
1099 field.invalidate();
1100 return true;
1101 }
1102 }
1103 return false;
1104 }
1105
1106 /***
1107 * Remove a field from this class. After this method, the removed field
1108 * will be invalid, and the result of any operations on it is undefined.
1109 *
1110 * @return true if this class contained the field, false otherwise
1111 */
1112 public boolean removeDeclaredField(BCField field) {
1113 if (field == null)
1114 return false;
1115 return removeDeclaredField(field.getName());
1116 }
1117
1118 /***
1119 * Rearrange declared field order.
1120 */
1121 public void moveDeclaredField(int fromIdx, int toIdx) {
1122 if (fromIdx == toIdx)
1123 return;
1124 List fields = _state.getFieldsHolder();
1125 Object o = fields.remove(fromIdx);
1126 fields.add(toIdx, o);
1127 }
1128
1129
1130
1131
1132
1133 /***
1134 * Return all methods declared by this class. Constructors and static
1135 * initializers are included.
1136 */
1137 public BCMethod[] getDeclaredMethods() {
1138 List methods = _state.getMethodsHolder();
1139 return (BCMethod[]) methods.toArray(new BCMethod[methods.size()]);
1140 }
1141
1142 /***
1143 * Return the declared method with the given name, or null if none.
1144 * If multiple methods are declared with the given name, which is returned
1145 * is undefined.
1146 * Note that in bytecode, constructors are named <code><init></code>
1147 * and static initializers are named <code><clinit></code>.
1148 */
1149 public BCMethod getDeclaredMethod(String name) {
1150 BCMethod[] methods = getDeclaredMethods();
1151 for (int i = 0; i < methods.length; i++)
1152 if (methods[i].getName().equals(name))
1153 return methods[i];
1154 return null;
1155 }
1156
1157 /***
1158 * Return all the declared methods with the given name, or an empty array
1159 * if none.
1160 * Note that in bytecode, constructors are named <code><init></code>
1161 * and static initializers are named <code><clinit></code>.
1162 */
1163 public BCMethod[] getDeclaredMethods(String name) {
1164 Collection matches = new LinkedList();
1165 BCMethod[] methods = getDeclaredMethods();
1166 for (int i = 0; i < methods.length; i++)
1167 if (methods[i].getName().equals(name))
1168 matches.add(methods[i]);
1169 return (BCMethod[]) matches.toArray(new BCMethod[matches.size()]);
1170 }
1171
1172 /***
1173 * Return the declared method with the given name and parameter types,
1174 * or null if none. If multiple methods are declared with the given name
1175 * and parameters, which is returned is undefined.
1176 * Note that in bytecode, constructors are named <code><init></code>
1177 * and static initializers are named <code><clinit></code>.
1178 */
1179 public BCMethod getDeclaredMethod(String name, String[] paramTypes) {
1180 if (paramTypes == null)
1181 paramTypes = new String[0];
1182
1183 BCMethod[] methods = getDeclaredMethods();
1184 for (int i = 0; i < methods.length; i++) {
1185 if (methods[i].getName().equals(name)
1186 && paramsMatch(methods[i], paramTypes))
1187 return methods[i];
1188 }
1189 return null;
1190 }
1191
1192 /***
1193 * Return true iff the given method's parameters match <code>params</code>.
1194 */
1195 private boolean paramsMatch(BCMethod meth, String[] params) {
1196 String[] mparams = meth.getParamNames();
1197 if (mparams.length != params.length)
1198 return false;
1199
1200 for (int i = 0; i < params.length; i++) {
1201 if (!mparams[i].equals(_project.getNameCache().
1202 getExternalForm(params[i], false)))
1203 return false;
1204 }
1205 return true;
1206 }
1207
1208 /***
1209 * Return the declared method with the given name and parameter types,
1210 * or null if none. If multiple methods are declared with the given name
1211 * and parameters, which is returned is undefined.
1212 * Note that in bytecode, constructors are named <code><init></code>
1213 * and static initializers are named <code><clinit></code>.
1214 */
1215 public BCMethod getDeclaredMethod(String name, Class[] paramTypes) {
1216 if (paramTypes == null)
1217 return getDeclaredMethod(name, (String[]) null);
1218
1219 String[] paramNames = new String[paramTypes.length];
1220 for (int i = 0; i < paramTypes.length; i++)
1221 paramNames[i] = paramTypes[i].getName();
1222 return getDeclaredMethod(name, paramNames);
1223 }
1224
1225 /***
1226 * Return the declared method with the given name and parameter types,
1227 * or null if none. If multiple methods are declared with the given name
1228 * and parameters, which is returned is undefined.
1229 * Note that in bytecode, constructors are named <code><init></code>
1230 * and static initializers are named <code><clinit></code>.
1231 */
1232 public BCMethod getDeclaredMethod(String name, BCClass[] paramTypes) {
1233 if (paramTypes == null)
1234 return getDeclaredMethod(name, (String[]) null);
1235
1236 String[] paramNames = new String[paramTypes.length];
1237 for (int i = 0; i < paramTypes.length; i++)
1238 paramNames[i] = paramTypes[i].getName();
1239 return getDeclaredMethod(name, paramNames);
1240 }
1241
1242 /***
1243 * Return all declared methods with the given name and parameter types.
1244 * Note that in bytecode, constructors are named <code><init></code>
1245 * and static initializers are named <code><clinit></code>.
1246 */
1247 public BCMethod[] getDeclaredMethods(String name, String[] paramTypes) {
1248 if (paramTypes == null)
1249 paramTypes = new String[0];
1250
1251 BCMethod[] methods = getDeclaredMethods();
1252 List matches = null;
1253 for (int i = 0; i < methods.length; i++) {
1254 if (methods[i].getName().equals(name)
1255 && paramsMatch(methods[i], paramTypes)) {
1256 if (matches == null)
1257 matches = new ArrayList(3);
1258 matches.add(methods[i]);
1259 }
1260 }
1261 if (matches == null)
1262 return new BCMethod[0];
1263 return (BCMethod[]) matches.toArray(new BCMethod[matches.size()]);
1264 }
1265
1266 /***
1267 * Return all declared methods with the given name and parameter types.
1268 * Note that in bytecode, constructors are named <code><init></code>
1269 * and static initializers are named <code><clinit></code>.
1270 */
1271 public BCMethod[] getDeclaredMethods(String name, Class[] paramTypes) {
1272 if (paramTypes == null)
1273 return getDeclaredMethods(name, (String[]) null);
1274
1275 String[] paramNames = new String[paramTypes.length];
1276 for (int i = 0; i < paramTypes.length; i++)
1277 paramNames[i] = paramTypes[i].getName();
1278 return getDeclaredMethods(name, paramNames);
1279 }
1280
1281 /***
1282 * Return all declared methods with the given name and parameter types.
1283 * Note that in bytecode, constructors are named <code><init></code>
1284 * and static initializers are named <code><clinit></code>.
1285 */
1286 public BCMethod[] getDeclaredMethods(String name, BCClass[] paramTypes) {
1287 if (paramTypes == null)
1288 return getDeclaredMethods(name, (String[]) null);
1289
1290 String[] paramNames = new String[paramTypes.length];
1291 for (int i = 0; i < paramTypes.length; i++)
1292 paramNames[i] = paramTypes[i].getName();
1293 return getDeclaredMethods(name, paramNames);
1294 }
1295
1296 /***
1297 * Return the declared method with the given name and signature,
1298 * or null if none.
1299 * Note that in bytecode, constructors are named <code><init></code>
1300 * and static initializers are named <code><clinit></code>.
1301 */
1302 public BCMethod getDeclaredMethod(String name, String returnType,
1303 String[] paramTypes) {
1304 if (paramTypes == null)
1305 paramTypes = new String[0];
1306
1307 BCMethod[] methods = getDeclaredMethods();
1308 for (int i = 0; i < methods.length; i++) {
1309 if (methods[i].getName().equals(name)
1310 && methods[i].getReturnName().equals(_project.getNameCache().
1311 getExternalForm(returnType, false))
1312 && paramsMatch(methods[i], paramTypes))
1313 return methods[i];
1314 }
1315 return null;
1316 }
1317
1318 /***
1319 * Return the declared method with the given name and signature,
1320 * or null if none.
1321 * Note that in bytecode, constructors are named <code><init></code>
1322 * and static initializers are named <code><clinit></code>.
1323 */
1324 public BCMethod getDeclaredMethod(String name, Class returnType,
1325 Class[] paramTypes) {
1326 if (paramTypes == null)
1327 return getDeclaredMethod(name, returnType.getName(),
1328 (String[]) null);
1329
1330 String[] paramNames = new String[paramTypes.length];
1331 for (int i = 0; i < paramTypes.length; i++)
1332 paramNames[i] = paramTypes[i].getName();
1333 return getDeclaredMethod(name, returnType.getName(), paramNames);
1334 }
1335
1336 /***
1337 * Return the declared method with the given name and signature,
1338 * or null if none.
1339 * Note that in bytecode, constructors are named <code><init></code>
1340 * and static initializers are named <code><clinit></code>.
1341 */
1342 public BCMethod getDeclaredMethod(String name, BCClass returnType,
1343 BCClass[] paramTypes) {
1344 if (paramTypes == null)
1345 return getDeclaredMethod(name, returnType.getName(),
1346 (String[]) null);
1347
1348 String[] paramNames = new String[paramTypes.length];
1349 for (int i = 0; i < paramTypes.length; i++)
1350 paramNames[i] = paramTypes[i].getName();
1351 return getDeclaredMethod(name, returnType.getName(), paramNames);
1352 }
1353
1354 /***
1355 * Return the methods of this class, including those of all superclasses,
1356 * or an empty array if none.
1357 * The base version of methods that are overridden will be included, as
1358 * will all constructors and static initializers.
1359 * The methods will be ordered from those in the most-specific type up to
1360 * those in {@link Object}.
1361 */
1362 public BCMethod[] getMethods() {
1363 Collection allMethods = new LinkedList();
1364 BCMethod[] methods;
1365 for (BCClass type = this; type != null; type = type.getSuperclassBC()) {
1366 methods = type.getDeclaredMethods();
1367 for (int i = 0; i < methods.length; i++)
1368 allMethods.add(methods[i]);
1369 }
1370 return (BCMethod[]) allMethods.toArray(new BCMethod[allMethods.size()]);
1371 }
1372
1373 /***
1374 * Return the methods with the given name, including those of all
1375 * superclasses, or an empty array if none.
1376 * Note that in bytecode, constructors are named <code><init></code>
1377 * and static initializers are named <code><clinit></code>.
1378 */
1379 public BCMethod[] getMethods(String name) {
1380 Collection matches = new LinkedList();
1381 BCMethod[] methods = getMethods();
1382 for (int i = 0; i < methods.length; i++)
1383 if (methods[i].getName().equals(name))
1384 matches.add(methods[i]);
1385 return (BCMethod[]) matches.toArray(new BCMethod[matches.size()]);
1386 }
1387
1388 /***
1389 * Return the methods with the given name and parameter types, including
1390 * those of all superclasses, or an empty array if none.
1391 * Note that in bytecode, constructors are named <code><init></code>
1392 * and static initializers are named <code><clinit></code>.
1393 */
1394 public BCMethod[] getMethods(String name, String[] paramTypes) {
1395 if (paramTypes == null)
1396 paramTypes = new String[0];
1397
1398 String[] curParams;
1399 boolean match;
1400 BCMethod[] methods = getMethods();
1401 Collection matches = new LinkedList();
1402 for (int i = 0; i < methods.length; i++) {
1403 if (!methods[i].getName().equals(name))
1404 continue;
1405 curParams = methods[i].getParamNames();
1406 if (curParams.length != paramTypes.length)
1407 continue;
1408
1409 match = true;
1410 for (int j = 0; j < paramTypes.length; j++) {
1411 if (!curParams[j].equals(_project.getNameCache().
1412 getExternalForm(paramTypes[j], false))) {
1413 match = false;
1414 break;
1415 }
1416 }
1417 if (match)
1418 matches.add(methods[i]);
1419 }
1420 return (BCMethod[]) matches.toArray(new BCMethod[matches.size()]);
1421 }
1422
1423 /***
1424 * Return the methods with the given name and parameter types, including
1425 * those of all superclasses, or an empty array if none.
1426 * Note that in bytecode, constructors are named <code><init></code>
1427 * and static initializers are named <code><clinit></code>.
1428 */
1429 public BCMethod[] getMethods(String name, Class[] paramTypes) {
1430 if (paramTypes == null)
1431 return getMethods(name, (String[]) null);
1432
1433 String[] paramNames = new String[paramTypes.length];
1434 for (int i = 0; i < paramTypes.length; i++)
1435 paramNames[i] = paramTypes[i].getName();
1436 return getMethods(name, paramNames);
1437 }
1438
1439 /***
1440 * Return the methods with the given name and parameter types, including
1441 * those of all superclasses, or an empty array if none.
1442 * Note that in bytecode, constructors are named <code><init></code>
1443 * and static initializers are named <code><clinit></code>.
1444 */
1445 public BCMethod[] getMethods(String name, BCClass[] paramTypes) {
1446 if (paramTypes == null)
1447 return getMethods(name, (String[]) null);
1448
1449 String[] paramNames = new String[paramTypes.length];
1450 for (int i = 0; i < paramTypes.length; i++)
1451 paramNames[i] = paramTypes[i].getName();
1452 return getMethods(name, paramNames);
1453 }
1454
1455 /***
1456 * Set the methods for this class; this method is useful for importing all
1457 * methods from another class. Set to null or empty array if none.
1458 */
1459 public void setDeclaredMethods(BCMethod[] methods) {
1460 clearDeclaredMethods();
1461 if (methods != null)
1462 for (int i = 0; i < methods.length; i++)
1463 declareMethod(methods[i]);
1464 }
1465
1466 /***
1467 * Import the information in the given method as a new method of this class.
1468 *
1469 * @return the added method
1470 */
1471 public BCMethod declareMethod(BCMethod method) {
1472 BCMethod newMethod = declareMethod(method.getName(),
1473 method.getReturnName(), method.getParamNames());
1474 newMethod.setAccessFlags(method.getAccessFlags());
1475 newMethod.setAttributes(method.getAttributes());
1476 return newMethod;
1477 }
1478
1479 /***
1480 * Add a method to this class.
1481 * Note that in bytecode, constructors are named <code><init></code>
1482 * and static initializers are named <code><clinit></code>.
1483 *
1484 * @return the added method
1485 */
1486 public BCMethod declareMethod(String name, String returnType,
1487 String[] paramTypes) {
1488 BCMethod method = new BCMethod(this);
1489 _state.getMethodsHolder().add(method);
1490 method.initialize(name, _project.getNameCache().
1491 getDescriptor(returnType, paramTypes));
1492 return method;
1493 }
1494
1495 /***
1496 * Add a method to this class.
1497 * Note that in bytecode, constructors are named <code><init></code>
1498 * and static initializers are named <code><clinit></code>.
1499 *
1500 * @return the added method
1501 */
1502 public BCMethod declareMethod(String name, Class returnType,
1503 Class[] paramTypes) {
1504 String[] paramNames = null;
1505 if (paramTypes != null) {
1506 paramNames = new String[paramTypes.length];
1507 for (int i = 0; i < paramTypes.length; i++)
1508 paramNames[i] = paramTypes[i].getName();
1509 }
1510 String returnName = (returnType == null) ? null : returnType.getName();
1511 return declareMethod(name, returnName, paramNames);
1512 }
1513
1514 /***
1515 * Add a method to this class.
1516 * Note that in bytecode, constructors are named <code><init></code>
1517 * and static initializers are named <code><clinit></code>.
1518 *
1519 * @return the added method
1520 */
1521 public BCMethod declareMethod(String name, BCClass returnType,
1522 BCClass[] paramTypes) {
1523 String[] paramNames = null;
1524 if (paramTypes != null) {
1525 paramNames = new String[paramTypes.length];
1526 for (int i = 0; i < paramTypes.length; i++)
1527 paramNames[i] = paramTypes[i].getName();
1528 }
1529 String returnName = (returnType == null) ? null : returnType.getName();
1530 return declareMethod(name, returnName, paramNames);
1531 }
1532
1533 /***
1534 * Clear all declared methods from this class.
1535 */
1536 public void clearDeclaredMethods() {
1537 List methods = _state.getMethodsHolder();
1538 BCMethod method;
1539 for (Iterator itr = methods.iterator(); itr.hasNext();) {
1540 method = (BCMethod) itr.next();
1541 itr.remove();
1542 method.invalidate();
1543 }
1544 }
1545
1546 /***
1547 * Remove a method from this class. After this method, the removed method
1548 * will be invalid, and the result of any operations on it is undefined.
1549 * If multiple methods match the given name, which is removed is undefined.
1550 * Note that in bytecode, constructors are named <code><init></code>
1551 * and static initializers are named <code><clinit></code>.
1552 *
1553 * @return true if this class contained the method, false otherwise
1554 */
1555 public boolean removeDeclaredMethod(String name) {
1556 List methods = _state.getMethodsHolder();
1557 BCMethod method;
1558 for (Iterator itr = methods.iterator(); itr.hasNext();) {
1559 method = (BCMethod) itr.next();
1560 if (method.getName().equals(name)) {
1561 itr.remove();
1562 method.invalidate();
1563 return true;
1564 }
1565 }
1566 return false;
1567 }
1568
1569 /***
1570 * Removes a method from this class. After this method, the removed method
1571 * will be invalid, and the result of any operations on it is undefined.
1572 *
1573 * @return true if this class contained the method, false otherwise
1574 */
1575 public boolean removeDeclaredMethod(BCMethod method) {
1576 if (method == null)
1577 return false;
1578 return removeDeclaredMethod(method.getName(), method.getParamNames());
1579 }
1580
1581 /***
1582 * Removes a method from this class. After this method, the removed method
1583 * will be invalid, and the result of any operations on it is undefined.
1584 * Note that in bytecode, constructors are named <code><init></code>
1585 * and static initializers are named <code><clinit></code>.
1586 *
1587 * @return true if this class contained the method, false otherwise
1588 */
1589 public boolean removeDeclaredMethod(String name, String[] paramTypes) {
1590 if (paramTypes == null)
1591 paramTypes = new String[0];
1592
1593 String[] curParams;
1594 boolean match;
1595 List methods = _state.getMethodsHolder();
1596 BCMethod method;
1597 for (Iterator itr = methods.iterator(); itr.hasNext();) {
1598 method = (BCMethod) itr.next();
1599 if (!method.getName().equals(name))
1600 continue;
1601 curParams = method.getParamNames();
1602 if (curParams.length != paramTypes.length)
1603 continue;
1604
1605 match = true;
1606 for (int j = 0; j < paramTypes.length; j++) {
1607 if (!curParams[j].equals(_project.getNameCache().
1608 getExternalForm(paramTypes[j], false))) {
1609 match = false;
1610 break;
1611 }
1612 }
1613 if (match) {
1614 itr.remove();
1615 method.invalidate();
1616 return true;
1617 }
1618 }
1619 return false;
1620 }
1621
1622 /***
1623 * Removes a method from this class. After this method, the removed method
1624 * will be invalid, and the result of any operations on it is undefined.
1625 * Note that in bytecode, constructors are named <code><init></code>
1626 * and static initializers are named <code><clinit></code>.
1627 *
1628 * @return true if this class contained the method, false otherwise
1629 */
1630 public boolean removeDeclaredMethod(String name, Class[] paramTypes) {
1631 if (paramTypes == null)
1632 return removeDeclaredMethod(name, (String[]) null);
1633
1634 String[] paramNames = new String[paramTypes.length];
1635 for (int i = 0; i < paramTypes.length; i++)
1636 paramNames[i] = paramTypes[i].getName();
1637 return removeDeclaredMethod(name, paramNames);
1638 }
1639
1640 /***
1641 * Removes a method from this class. After this method, the removed method
1642 * will be invalid, and the result of any operations on it is undefined.
1643 * Note that in bytecode, constructors are named <code><init></code>
1644 * and static initializers are named <code><clinit></code>.
1645 *
1646 * @return true if this class contained the method, false otherwise
1647 */
1648 public boolean removeDeclaredMethod(String name, BCClass[] paramTypes) {
1649 if (paramTypes == null)
1650 return removeDeclaredMethod(name, (String[]) null);
1651
1652 String[] paramNames = new String[paramTypes.length];
1653 for (int i = 0; i < paramTypes.length; i++)
1654 paramNames[i] = paramTypes[i].getName();
1655 return removeDeclaredMethod(name, paramNames);
1656 }
1657
1658 /***
1659 * Rearrange method order.
1660 */
1661 public void moveDeclaredMethod(int fromIdx, int toIdx) {
1662 if (fromIdx == toIdx)
1663 return;
1664 List methods = _state.getMethodsHolder();
1665 Object o = methods.remove(fromIdx);
1666 methods.add(toIdx, o);
1667 }
1668
1669
1670
1671
1672
1673 /***
1674 * Convenience method to add a default constructor to this class.
1675 * If a default constructor already exists, this method will return it
1676 * without modification.
1677 * This method can only be called if the superclass has been set.
1678 *
1679 * @return the default constructor
1680 */
1681 public BCMethod addDefaultConstructor() {
1682 BCMethod method = getDeclaredMethod("<init>", (String[]) null);
1683 if (method != null)
1684 return method;
1685
1686 method = declareMethod("<init>", void.class, null);
1687 Code code = method.getCode(true);
1688 code.setMaxStack(1);
1689 code.setMaxLocals(1);
1690
1691 code.xload().setThis();
1692 code.invokespecial()
1693 .setMethod(getSuperclassName(), "<init>", "void", null);
1694 code.vreturn();
1695 return method;
1696 }
1697
1698 /***
1699 * Return source file information for the class.
1700 * Acts internally through the {@link Attributes} interface.
1701 *
1702 * @param add if true, a new source file attribute will be added
1703 * if not already present
1704 * @return the source file information, or null if none and the
1705 * <code>add</code> param is set to false
1706 */
1707 public SourceFile getSourceFile(boolean add) {
1708 SourceFile source = (SourceFile) getAttribute(Constants.ATTR_SOURCE);
1709 if (!add || (source != null))
1710 return source;
1711 return (SourceFile) addAttribute(Constants.ATTR_SOURCE);
1712 }
1713
1714 /***
1715 * Remove the source file attribute for the class.
1716 * Acts internally through the {@link Attributes} interface.
1717 *
1718 * @return true if there was a file to remove
1719 */
1720 public boolean removeSourceFile() {
1721 return removeAttribute(Constants.ATTR_SOURCE);
1722 }
1723
1724 /***
1725 * Return inner classes information for the class.
1726 * Acts internally through the {@link Attributes} interface.
1727 *
1728 * @param add if true, a new inner classes attribute will be added
1729 * if not already present
1730 * @return the inner classes information, or null if none and the
1731 * <code>add</code> param is set to false
1732 */
1733 public InnerClasses getInnerClasses(boolean add) {
1734 InnerClasses inner = (InnerClasses) getAttribute
1735 (Constants.ATTR_INNERCLASS);
1736 if (!add || (inner != null))
1737 return inner;
1738 return (InnerClasses) addAttribute(Constants.ATTR_INNERCLASS);
1739 }
1740
1741 /***
1742 * Remove the inner classes attribute for the class.
1743 * Acts internally through the {@link Attributes} interface.
1744 *
1745 * @return true if there was an attribute to remove
1746 */
1747 public boolean removeInnerClasses() {
1748 return removeAttribute(Constants.ATTR_INNERCLASS);
1749 }
1750
1751 /***
1752 * Convenience method to return deprecation information for the class.
1753 * Acts internally through the {@link Attributes} interface.
1754 */
1755 public boolean isDeprecated() {
1756 return getAttribute(Constants.ATTR_DEPRECATED) != null;
1757 }
1758
1759 /***
1760 * Convenience method to set whether this class should be considered
1761 * deprecated. Acts internally through the {@link Attributes} interface.
1762 */
1763 public void setDeprecated(boolean on) {
1764 if (!on)
1765 removeAttribute(Constants.ATTR_DEPRECATED);
1766 else if (!isDeprecated())
1767 addAttribute(Constants.ATTR_DEPRECATED);
1768 }
1769
1770
1771
1772
1773
1774 public void acceptVisit(BCVisitor visit) {
1775 visit.enterBCClass(this);
1776
1777 ConstantPool pool = null;
1778 try {
1779 pool = _state.getPool();
1780 } catch (UnsupportedOperationException uoe) {
1781 }
1782 if (pool != null)
1783 pool.acceptVisit(visit);
1784
1785 BCField[] fields = getDeclaredFields();
1786 for (int i = 0; i < fields.length; i++) {
1787 visit.enterBCMember(fields[i]);
1788 fields[i].acceptVisit(visit);
1789 visit.exitBCMember(fields[i]);
1790 }
1791
1792 BCMethod[] methods = getDeclaredMethods();
1793 for (int i = 0; i < methods.length; i++) {
1794 visit.enterBCMember(methods[i]);
1795 methods[i].acceptVisit(visit);
1796 visit.exitBCMember(methods[i]);
1797 }
1798
1799 visitAttributes(visit);
1800 visit.exitBCClass(this);
1801 }
1802
1803
1804
1805
1806
1807 public Project getProject() {
1808 return _project;
1809 }
1810
1811 public ConstantPool getPool() {
1812 return _state.getPool();
1813 }
1814
1815 public ClassLoader getClassLoader() {
1816 if (_loader != null)
1817 return _loader;
1818 return Thread.currentThread().getContextClassLoader();
1819 }
1820
1821 public boolean isValid() {
1822 return _project != null;
1823 }
1824
1825 Collection getAttributesHolder() {
1826 return _state.getAttributesHolder();
1827 }
1828
1829
1830
1831
1832
1833 BCClass getBCClass() {
1834 return this;
1835 }
1836
1837 /***
1838 * Attempts to change the class name with the owning project. The project
1839 * can reject the change if a class with the given new name already
1840 * exists; therefore this method should be called before the change is
1841 * recorded in the class.
1842 */
1843 private void beforeRename(String oldName, String newName) {
1844 if ((_project != null) && (oldName != null))
1845 _project.renameClass(oldName, newName, this);
1846 }
1847 }