001 package edu.rice.cs.cunit.classFile.attributes;
002
003 import edu.rice.cs.cunit.classFile.constantPool.AUTFPoolInfo;
004 import edu.rice.cs.cunit.classFile.constantPool.ConstantPool;
005 import edu.rice.cs.cunit.classFile.constantPool.APoolInfo;
006 import edu.rice.cs.cunit.classFile.constantPool.visitors.CheckUTFVisitor;
007 import edu.rice.cs.cunit.classFile.code.instructions.LineNumberTable;
008 import edu.rice.cs.cunit.classFile.ClassFileTools;
009 import edu.rice.cs.cunit.util.Types;
010
011 import java.io.ByteArrayOutputStream;
012 import java.io.IOException;
013 import java.util.List;
014 import java.util.ArrayList;
015 import java.util.Arrays;
016
017 /**
018 * Represents an abstract Annotations attribute in a class file.
019 *
020 * @author Mathias Ricken
021 */
022 public abstract class AAnnotationsAttributeInfo extends AAttributeInfo {
023 /**
024 * Storage class for annotations.
025 */
026 public static class Annotation {
027 /**
028 * Storage class for a member value.
029 */
030 public static abstract class AMemberValue {
031 /**
032 * Type tag.
033 */
034 public char tag;
035
036 /**
037 * Creates a new member value.
038 * @param tag _type tag of this value
039 */
040 protected AMemberValue(char tag) {
041 this.tag = tag;
042 }
043
044 /**
045 * Returns the size of this value.
046 * @return size in bytes
047 */
048 public abstract int getSize();
049
050 /**
051 * Returns the tag character of this value.
052 * @return tag
053 */
054 public char getTag() {
055 return tag;
056 }
057
058 /**
059 * Writes this value into the stream.
060 * @param cp constant pool
061 * @param baos stream
062 * @throws IOException
063 */
064 public abstract void writeToByteArrayOutputStream(ConstantPool cp, ByteArrayOutputStream baos) throws IOException;
065
066 /**
067 * Parses member value data and returns a member value.
068 * @param cp constant pool
069 * @param data data array
070 * @param start start index in data array
071 * @return parsed member value
072 */
073 public static AMemberValue read(ConstantPool cp, byte[] data, int start) {
074 char tag = (char)data[start];
075 if ("BCDFIJSZs".indexOf(tag) != -1) {
076 return new Annotation.ConstantMemberValue(tag, cp.get(Types.ushortFromBytes(data, start + 1)));
077 }
078 else if (tag == 'e') {
079 return new Annotation.EnumMemberValue(tag, cp.get(Types.ushortFromBytes(data, start + 1))
080 .execute(CheckUTFVisitor.singleton(), null), cp.get(Types.ushortFromBytes(data, start + 3))
081 .execute(CheckUTFVisitor.singleton(), null));
082 }
083 else if (tag == 'c') {
084 return new Annotation.ClassMemberValue(tag, cp.get(Types.ushortFromBytes(data, start + 1)).
085 execute(CheckUTFVisitor.singleton(), null));
086 }
087 else if (tag == '@') {
088 return new Annotation.AnnotationMemberValue(tag, new Annotation(cp, data, start + 1));
089 }
090 else if (tag == '[') {
091 return new Annotation.ArrayMemberValue(cp, data, start);
092 }
093 else {
094 throw new ClassFormatError("Unknown member value tag: " + tag);
095 }
096 }
097
098 /**
099 * Returns a string representation of the object like it would be seen in a Java listing.
100 * @return a string representation of the object.
101 */
102 public abstract String toStringJava();
103
104 /**
105 * Execute a visitor.
106 * @param v visitor
107 * @param param visitor-specific parameter
108 * @return visitor-specific return value
109 */
110 public abstract <R, P> R execute(IMemberValueVisitor<R, P> v, P param);
111
112
113 /**
114 * Returns a hash code value for the object.
115 * @return a hash code value for this object.
116 */
117 public abstract int hashCode();
118
119 /**
120 * Indicates whether some other object is "equal to" this one.
121 * @param o the reference object with which to compare.
122 * @return <code>true</code> if this object is the same as the obj argument; <code>false</code> otherwise.
123 */
124 public abstract boolean equals(Object o);
125 }
126
127 /**
128 * Visitor interface for member values.
129 */
130 public static interface IMemberValueVisitor<R, P> {
131 /**
132 * Case for constants.
133 * @param host constant member
134 * @param param visitor-specific parameter
135 * @return visitor-specific return value
136 */
137 public abstract R constantMemberCase(ConstantMemberValue host, P param);
138
139 /**
140 * Case for enums.
141 * @param host enum member
142 * @param param visitor-specific parameter
143 * @return visitor-specific return value
144 */
145 public abstract R enumMemberCase(EnumMemberValue host, P param);
146
147 /**
148 * Case for classes.
149 * @param host class member
150 * @param param visitor-specific parameter
151 * @return visitor-specific return value
152 */
153 public abstract R classMemberCase(ClassMemberValue host, P param);
154
155 /**
156 * Case for annotations.
157 * @param host annotation member
158 * @param param visitor-specific parameter
159 * @return visitor-specific return value
160 */
161 public abstract R annotationMemberCase(AnnotationMemberValue host, P param);
162
163 /**
164 * Case for arrays.
165 * @param host array member
166 * @param param visitor-specific parameter
167 * @return visitor-specific return value
168 */
169 public abstract R arrayMemberCase(ArrayMemberValue host, P param);
170 }
171
172 /**
173 * Default visitor where all cases delegate to an abstract default case.
174 */
175 public static abstract class ADefaultMemberValueVisitor<R, P> implements IMemberValueVisitor<R, P> {
176 /**
177 * Default case.
178 *
179 * @param host member
180 * @param param visitor-specific parameter
181 *
182 * @return visitor-specific return value
183 */
184 public abstract R defaultCase(AMemberValue host, P param);
185
186 /**
187 * Case for constants.
188 *
189 * @param host constant member
190 * @param param visitor-specific parameter
191 *
192 * @return visitor-specific return value
193 */
194 public R constantMemberCase(ConstantMemberValue host, P param) {
195 return defaultCase(host, param);
196 }
197
198 /**
199 * Case for enums.
200 *
201 * @param host enum member
202 * @param param visitor-specific parameter
203 *
204 * @return visitor-specific return value
205 */
206 public R enumMemberCase(EnumMemberValue host, P param) {
207 return defaultCase(host, param);
208 }
209
210 /**
211 * Case for classes.
212 *
213 * @param host class member
214 * @param param visitor-specific parameter
215 *
216 * @return visitor-specific return value
217 */
218 public R classMemberCase(ClassMemberValue host, P param) {
219 return defaultCase(host, param);
220 }
221
222 /**
223 * Case for annotations.
224 *
225 * @param host annotation member
226 * @param param visitor-specific parameter
227 *
228 * @return visitor-specific return value
229 */
230 public R annotationMemberCase(AnnotationMemberValue host, P param) {
231 return defaultCase(host, param);
232 }
233
234 /**
235 * Case for arrays.
236 *
237 * @param host array member
238 * @param param visitor-specific parameter
239 *
240 * @return visitor-specific return value
241 */
242 public R arrayMemberCase(ArrayMemberValue host, P param) {
243 return defaultCase(host, param);
244 }
245 }
246
247 public static class CheckConstantMemberVisitor extends ADefaultMemberValueVisitor<ConstantMemberValue, Object> {
248 /**
249 * Default case. Throws exception.
250 *
251 * @param host non-constant member
252 * @param param visitor-specific parameter
253 *
254 * @return does not return
255 */
256 public ConstantMemberValue defaultCase(AMemberValue host, Object param) {
257 throw new RuntimeException("Constant annotation member value expected.");
258 }
259
260 /**
261 * Case for constants.
262 *
263 * @param host constant member
264 * @param param visitor-specific parameter
265 *
266 * @return the host
267 */
268 public ConstantMemberValue constantMemberCase(ConstantMemberValue host, Object param) {
269 return host;
270 }
271
272 /**
273 * Singleton constructor.
274 */
275 private CheckConstantMemberVisitor() {
276 }
277
278 /**
279 * Singleton instance.
280 */
281 private static CheckConstantMemberVisitor _instance = new CheckConstantMemberVisitor();
282
283 /**
284 * Singleton accessor.
285 *
286 * @return singleton
287 */
288 public static CheckConstantMemberVisitor singleton() {
289 return _instance;
290 }
291 }
292
293 /**
294 * Storage class for constants.
295 */
296 public static class ConstantMemberValue extends Annotation.AMemberValue {
297 /**
298 * Constant value.
299 */
300 APoolInfo constValue;
301
302 /**
303 * Creates a new constant value.
304 * @param tag _type tag
305 * @param constValue constant value
306 */
307 public ConstantMemberValue(char tag, APoolInfo constValue) {
308 super(tag);
309 this.constValue = constValue;
310 }
311
312 /**
313 * Returns the size of this value.
314 * @return size in bytes
315 */
316 public int getSize() {
317 return 3;
318 }
319
320 /**
321 * Writes this value into the stream.
322 * @param cp constant pool
323 * @param baos stream
324 * @throws IOException
325 */
326 public void writeToByteArrayOutputStream(ConstantPool cp, ByteArrayOutputStream baos) throws IOException {
327 baos.write(tag);
328 baos.write(Types.bytesFromShort(cp.indexOf(constValue)));
329 }
330
331 /**
332 * Returns a string representation of the object.
333 * @return a string representation of the object.
334 */
335 public String toString() {
336 return constValue.toString();
337 }
338
339 /**
340 * Returns a string representation of the object like it would be seen in a Java listing.
341 * @return a string representation of the object.
342 */
343 public String toStringJava() {
344 switch(tag) {
345 case 's': return "\""+constValue.toString()+"\"";
346 case 'F': return constValue.toString()+"f";
347 default: return constValue.toString();
348 }
349 }
350
351 /**
352 * Execute a visitor.
353 *
354 * @param v visitor
355 * @param param visitor-specific parameter
356 *
357 * @return visitor-specific return value
358 */
359 public <R, P> R execute(IMemberValueVisitor<R, P> v, P param) {
360 return v.constantMemberCase(this, param);
361 }
362
363 /**
364 * Accessor for the constant value.
365 * @return constant value
366 */
367 public APoolInfo getConstValue() {
368 return constValue;
369 }
370
371
372 /**
373 * Indicates whether some other object is "equal to" this one.
374 * @param o the reference object with which to compare.
375 * @return <code>true</code> if this object is the same as the obj argument; <code>false</code> otherwise.
376 */
377 public boolean equals(Object o) {
378 if (this == o) {
379 return true;
380 }
381 if (o == null || getClass() != o.getClass()) {
382 return false;
383 }
384
385 ConstantMemberValue that = (ConstantMemberValue)o;
386
387 if (constValue != null ? !constValue.equals(that.constValue) : that.constValue != null) {
388 return false;
389 }
390
391 return true;
392 }
393
394 /**
395 * Returns a hash code value for the object.
396 * @return a hash code value for this object.
397 */
398 public int hashCode() {
399 return (constValue != null ? constValue.hashCode() : 0);
400 }
401 }
402
403 /**
404 * Storage class for an enum.
405 */
406 public static class EnumMemberValue extends Annotation.AMemberValue {
407 /**
408 * Name of the enum class.
409 */
410 AUTFPoolInfo typeName;
411 /**
412 * Name of the enum member.
413 */
414 AUTFPoolInfo constValue;
415
416 /**
417 * Creates a new enum value.
418 * @param tag _type tag
419 * @param typeName name of enum class
420 * @param constValue name of enum member
421 */
422 public EnumMemberValue(char tag, AUTFPoolInfo typeName, AUTFPoolInfo constValue) {
423 super(tag);
424 this.typeName = typeName;
425 this.constValue = constValue;
426 }
427
428 /**
429 * Returns the size of this value.
430 * @return size in bytes
431 */
432 public int getSize() {
433 return 5;
434 }
435
436 /**
437 * Writes this value into the stream.
438 * @param cp constant pool
439 * @param baos stream
440 * @throws IOException
441 */
442 public void writeToByteArrayOutputStream(ConstantPool cp, ByteArrayOutputStream baos) throws IOException {
443 baos.write(tag);
444 baos.write(Types.bytesFromShort(cp.indexOf(typeName)));
445 baos.write(Types.bytesFromShort(cp.indexOf(constValue)));
446 }
447
448 /**
449 * Returns a string representation of the object.
450 * @return a string representation of the object.
451 */
452 public String toString() {
453 return typeName.toString()+"."+constValue.toString();
454 }
455
456 /**
457 * Returns a string representation of the object like it would be seen in a Java listing.
458 * @return a string representation of the object.
459 */
460 public String toStringJava() {
461 String s = ClassFileTools.getTypeString(typeName.toString(),"").replace('$','.');
462 return s.substring(0, s.length()-1)+"."+constValue.toString();
463 }
464
465 /**
466 * Execute a visitor.
467 *
468 * @param v visitor
469 * @param param visitor-specific parameter
470 *
471 * @return visitor-specific return value
472 */
473 public <R, P> R execute(IMemberValueVisitor<R, P> v, P param) {
474 return v.enumMemberCase(this, param);
475 }
476
477 /**
478 * Accessor for the type name.
479 * @return type name
480 */
481 public AUTFPoolInfo getTypeName() {
482 return typeName;
483 }
484
485 /**
486 * Accessor for the constant value.
487 * @return constant value
488 */
489 public AUTFPoolInfo getConstValue() {
490 return constValue;
491 }
492
493
494 /**
495 * Indicates whether some other object is "equal to" this one.
496 * @param o the reference object with which to compare.
497 * @return <code>true</code> if this object is the same as the obj argument; <code>false</code> otherwise.
498 */
499 public boolean equals(Object o) {
500 if (this == o) {
501 return true;
502 }
503 if (o == null || getClass() != o.getClass()) {
504 return false;
505 }
506
507 EnumMemberValue that = (EnumMemberValue)o;
508
509 if (constValue != null ? !constValue.equals(that.constValue) : that.constValue != null) {
510 return false;
511 }
512 if (typeName != null ? !typeName.equals(that.typeName) : that.typeName != null) {
513 return false;
514 }
515
516 return true;
517 }
518
519 /**
520 * Returns a hash code value for the object.
521 * @return a hash code value for this object.
522 */
523 public int hashCode() {
524 int result;
525 result = (typeName != null ? typeName.hashCode() : 0);
526 result = 31 * result + (constValue != null ? constValue.hashCode() : 0);
527 return result;
528 }
529 }
530
531 /**
532 * Storage class for a class value.
533 */
534 public static class ClassMemberValue extends Annotation.AMemberValue {
535 /**
536 * Class name info.
537 * NOTE: Apparently this is an UTF item and not a CLASS item as documented.
538 */
539 AUTFPoolInfo classNameInfo;
540
541 /**
542 * Creates a new class value.
543 * @param tag _type tag
544 * @param classNameInfo class name info
545 */
546 public ClassMemberValue(char tag, AUTFPoolInfo classNameInfo) {
547 super(tag);
548 this.classNameInfo = classNameInfo;
549 }
550
551 /**
552 * Returns the size of this value.
553 * @return size in bytes
554 */
555 public int getSize() {
556 return 3;
557 }
558
559 /**
560 * Writes this value into the stream.
561 * @param cp constant pool
562 * @param baos stream
563 * @throws IOException
564 */
565 public void writeToByteArrayOutputStream(ConstantPool cp, ByteArrayOutputStream baos) throws IOException {
566 baos.write(tag);
567 baos.write(Types.bytesFromShort(cp.indexOf(classNameInfo)));
568 }
569
570 /**
571 * Returns a string representation of the object.
572 * @return a string representation of the object.
573 */
574 public String toString() {
575 return classNameInfo.toString();
576 }
577
578 /**
579 * Returns a string representation of the object like it would be seen in a Java listing.
580 * @return a string representation of the object.
581 */
582 public String toStringJava() {
583 String s = ClassFileTools.getTypeString(classNameInfo.toString(),"").replace('$','.');
584 return s.substring(0, s.length()-1)+".class";
585 }
586
587 /**
588 * Execute a visitor.
589 *
590 * @param v visitor
591 * @param param visitor-specific parameter
592 *
593 * @return visitor-specific return value
594 */
595 public <R, P> R execute(IMemberValueVisitor<R, P> v, P param) {
596 return v.classMemberCase(this, param);
597 }
598
599 /**
600 * Accessor for the class name.
601 * @return class name
602 */
603 public AUTFPoolInfo getClassName() {
604 return classNameInfo;
605 }
606
607
608 /**
609 * Indicates whether some other object is "equal to" this one.
610 * @param o the reference object with which to compare.
611 * @return <code>true</code> if this object is the same as the obj argument; <code>false</code> otherwise.
612 */
613 public boolean equals(Object o) {
614 if (this == o) {
615 return true;
616 }
617 if (o == null || getClass() != o.getClass()) {
618 return false;
619 }
620
621 ClassMemberValue that = (ClassMemberValue)o;
622
623 if (classNameInfo != null ? !classNameInfo.equals(that.classNameInfo) : that.classNameInfo != null) {
624 return false;
625 }
626
627 return true;
628 }
629
630 /**
631 * Returns a hash code value for the object.
632 * @return a hash code value for this object.
633 */
634 public int hashCode() {
635 return (classNameInfo != null ? classNameInfo.hashCode() : 0);
636 }
637 }
638
639 /**
640 * Storage class for an annotation value.
641 */
642 public static class AnnotationMemberValue extends Annotation.AMemberValue {
643 /**
644 * Annotation value.
645 */
646 Annotation annotation;
647
648 /**
649 * Creates a new annotation value.
650 * @param tag _type tag
651 * @param annotation annotation value
652 */
653 public AnnotationMemberValue(char tag, Annotation annotation) {
654 super(tag);
655 this.annotation = annotation;
656 }
657
658 /**
659 * Returns the size of this value.
660 * @return size in bytes
661 */
662 public int getSize() {
663 return 1 + annotation.getSize();
664 }
665
666 /**
667 * Writes this value into the stream.
668 * @param cp constant pool
669 * @param baos stream
670 * @throws IOException
671 */
672 public void writeToByteArrayOutputStream(ConstantPool cp, ByteArrayOutputStream baos) throws IOException {
673 baos.write(tag);
674 annotation.writeToByteArrayOutputStream(cp,baos);
675 }
676
677 /**
678 * Returns a string representation of the object.
679 * @return a string representation of the object.
680 */
681 public String toString() {
682 return annotation.toString();
683 }
684
685 /**
686 * Returns a string representation of the object like it would be seen in a Java listing.
687 * @return a string representation of the object.
688 */
689 public String toStringJava() {
690 return annotation.toStringJava();
691 }
692
693 /**
694 * Execute a visitor.
695 *
696 * @param v visitor
697 * @param param visitor-specific parameter
698 *
699 * @return visitor-specific return value
700 */
701 public <R, P> R execute(IMemberValueVisitor<R, P> v, P param) {
702 return v.annotationMemberCase(this, param);
703 }
704
705 /**
706 * Accessor for the annotation.
707 * @return annotation
708 */
709 public Annotation getAnnotation() {
710 return annotation;
711 }
712
713
714 /**
715 * Indicates whether some other object is "equal to" this one.
716 * @param o the reference object with which to compare.
717 * @return <code>true</code> if this object is the same as the obj argument; <code>false</code> otherwise.
718 */
719 public boolean equals(Object o) {
720 if (this == o) {
721 return true;
722 }
723 if (o == null || getClass() != o.getClass()) {
724 return false;
725 }
726
727 AnnotationMemberValue that = (AnnotationMemberValue)o;
728
729 if (annotation != null ? !annotation.equals(that.annotation) : that.annotation != null) {
730 return false;
731 }
732
733 return true;
734 }
735
736 /**
737 * Returns a hash code value for the object.
738 * @return a hash code value for this object.
739 */
740 public int hashCode() {
741 return (annotation != null ? annotation.hashCode() : 0);
742 }
743 }
744
745 /**
746 * Storage class for an array.
747 */
748 public static class ArrayMemberValue extends Annotation.AMemberValue {
749 /**
750 * Number of entries in array.
751 */
752 int numEntries;
753 /**
754 * Array of values.
755 */
756 AMemberValue[] entries;
757
758 /**
759 * Creates a new array.
760 * @param tag _type tag
761 * @param numEntries number of entries
762 * @param entries array of entries
763 */
764 public ArrayMemberValue(char tag, int numEntries, AMemberValue[] entries) {
765 super(tag);
766 assert(numEntries <= 0xffff);
767 this.numEntries = numEntries;
768 this.entries = entries;
769 }
770
771 /**
772 * Creates a new array.
773 * @param cp constant pool
774 * @param data data arrat
775 * @param start start index in array
776 */
777 public ArrayMemberValue(ConstantPool cp, byte[] data, int start) {
778 super((char)data[start]);
779 numEntries = Types.ushortFromBytes(data, start + 1);
780 entries = new Annotation.AMemberValue[numEntries];
781 int index = start + 3;
782 for (int i=0; i<numEntries; ++i) {
783 entries[i] = Annotation.AMemberValue.read(cp, data, index);
784 index += entries[i].getSize();
785 }
786 }
787
788 /**
789 * Returns the size of this value.
790 * @return size in bytes
791 */
792 public int getSize() {
793 int accum = 3;
794 for (Annotation.AMemberValue mv:entries) {
795 accum += mv.getSize();
796 }
797 return accum;
798 }
799
800 /**
801 * Writes this value into the stream.
802 * @param cp constant pool
803 * @param baos stream
804 * @throws IOException
805 */
806 public void writeToByteArrayOutputStream(ConstantPool cp, ByteArrayOutputStream baos) throws IOException {
807 baos.write(tag);
808 baos.write(Types.bytesFromShort((short)(numEntries & 0xffff)));
809 for (Annotation.AMemberValue mv:entries) {
810 mv.writeToByteArrayOutputStream(cp, baos);
811 }
812 }
813
814 /**
815 * Returns a string representation of the object.
816 * @return a string representation of the object.
817 */
818 public String toString() {
819 StringBuilder sb = new StringBuilder();;
820 sb.append("{");
821 boolean first = true;
822 for(AMemberValue mv:entries) {
823 if (first) {
824 first = false;
825 }
826 else {
827 sb.append(", ");
828 }
829 sb.append(mv.toString());
830 }
831 sb.append("}");
832 return sb.toString();
833 }
834
835 /**
836 * Returns a string representation of the object like it would be seen in a Java listing.
837 * @return a string representation of the object.
838 */
839 public String toStringJava() {
840 return toString();
841 }
842
843 /**
844 * Execute a visitor.
845 *
846 * @param v visitor
847 * @param param visitor-specific parameter
848 *
849 * @return visitor-specific return value
850 */
851 public <R, P> R execute(IMemberValueVisitor<R, P> v, P param) {
852 return v.arrayMemberCase(this, param);
853 }
854
855 /**
856 * Accessor for the entries.
857 * @return entries.
858 */
859 public AMemberValue[] getEntries() {
860 return entries;
861 }
862
863
864 /**
865 * Indicates whether some other object is "equal to" this one.
866 * @param o the reference object with which to compare.
867 * @return <code>true</code> if this object is the same as the obj argument; <code>false</code> otherwise.
868 */
869 public boolean equals(Object o) {
870 if (this == o) {
871 return true;
872 }
873 if (o == null || getClass() != o.getClass()) {
874 return false;
875 }
876
877 ArrayMemberValue that = (ArrayMemberValue)o;
878
879 if (numEntries != that.numEntries) {
880 return false;
881 }
882 if (!Arrays.equals(entries, that.entries)) {
883 return false;
884 }
885
886 return true;
887 }
888
889 /**
890 * Returns a hash code value for the object.
891 * @return a hash code value for this object.
892 */
893 public int hashCode() {
894 int result;
895 result = numEntries;
896 result = 31 * result + (entries != null ? Arrays.hashCode(entries) : 0);
897 return result;
898 }
899 }
900
901 /**
902 * Storage class for a name-value pair.
903 */
904 public static class NameValuePair {
905 /**
906 * Name.
907 */
908 private AUTFPoolInfo name;
909
910 /**
911 * Value.
912 */
913 private AMemberValue value;
914
915 /**
916 * Creates a new name-value pair.
917 * @param name name
918 * @param value value
919 */
920 public NameValuePair(AUTFPoolInfo name, AMemberValue value) {
921 this.name = name;
922 this.value = value;
923 }
924
925 /**
926 * Creates a new name-value pair.
927 * @param cp constant pool
928 * @param data data array
929 * @param start start index in array
930 */
931 public NameValuePair(ConstantPool cp, byte[] data, int start) {
932 name = cp.get(Types.ushortFromBytes(data, start + 0)).execute(CheckUTFVisitor.singleton(), null);
933 value = Annotation.AMemberValue.read(cp, data, start + 2);
934 }
935
936 /**
937 * Returns the size of this name-value pair.
938 * @return size in bytes
939 */
940 public int getSize() {
941 return 2 + value.getSize();
942 }
943
944 /**
945 * Writes this name-value pair into the stream.
946 * @param cp constant pool
947 * @param baos stream
948 * @throws IOException
949 */
950 public void writeToByteArrayOutputStream(ConstantPool cp, ByteArrayOutputStream baos) throws IOException {
951 baos.write(Types.bytesFromShort(cp.indexOf(name)));
952 value.writeToByteArrayOutputStream(cp, baos);
953 }
954
955 /**
956 * Returns a string representation of the object.
957 * @return a string representation of the object.
958 */
959 public String toString() {
960 return name.toString() + " = " + value.toString();
961 }
962
963 /**
964 * Accessor for the name.
965 * @return name name
966 */
967 public AUTFPoolInfo getName() {
968 return name;
969 }
970
971 /**
972 * Accessor for the value.
973 * @return value
974 */
975 public AMemberValue getValue() {
976 return value;
977 }
978
979
980 /**
981 * Indicates whether some other object is "equal to" this one.
982 * @param o the reference object with which to compare.
983 * @return <code>true</code> if this object is the same as the obj argument; <code>false</code> otherwise.
984 */
985 public boolean equals(Object o) {
986 if (this == o) {
987 return true;
988 }
989 if (o == null || getClass() != o.getClass()) {
990 return false;
991 }
992
993 NameValuePair that = (NameValuePair)o;
994
995 if (name != null ? !name.equals(that.name) : that.name != null) {
996 return false;
997 }
998 if (value != null ? !value.equals(that.value) : that.value != null) {
999 return false;
1000 }
1001
1002 return true;
1003 }
1004
1005 /**
1006 * Returns a hash code value for the object.
1007 * @return a hash code value for this object.
1008 */
1009 public int hashCode() {
1010 int result;
1011 result = (name != null ? name.hashCode() : 0);
1012 result = 31 * result + (value != null ? value.hashCode() : 0);
1013 return result;
1014 }
1015 }
1016
1017 /**
1018 * Type name of annotation.
1019 */
1020 private AUTFPoolInfo _type;
1021
1022 /**
1023 * Number of stored name-value _pairs.
1024 */
1025 private int _pairCount;
1026
1027 /**
1028 * Name-value _pairs.
1029 */
1030 private NameValuePair[] _pairs;
1031
1032 /**
1033 * Creates a new annotation.
1034 * @param type name of _type
1035 * @param pairCount number of name-value _pairs
1036 * @param pairs array of name-value _pairs
1037 */
1038 public Annotation(AUTFPoolInfo type,
1039 short pairCount,
1040 Annotation.NameValuePair[] pairs) {
1041 this._type = type;
1042 this._pairCount = pairCount;
1043 this._pairs = pairs;
1044 }
1045
1046 /**
1047 * Creates a new annotation.
1048 * @param cp constant pool
1049 * @param data data array
1050 * @param start start index in data array
1051 */
1052 public Annotation(ConstantPool cp, byte[] data, int start) {
1053 _type = cp.get(Types.ushortFromBytes(data, start + 0)).execute(CheckUTFVisitor.singleton(), null);
1054 _pairCount = Types.ushortFromBytes(data, start + 2);
1055 _pairs = new Annotation.NameValuePair[_pairCount];
1056 int index = start + 4;
1057 for(int i=0; i<_pairCount; ++i) {
1058 _pairs[i] = new Annotation.NameValuePair(cp, data, index);
1059 index += _pairs[i].getSize();
1060 }
1061 }
1062
1063 /**
1064 * Returns the size of this annotation.
1065 * @return size in bytes
1066 */
1067 public int getSize() {
1068 int accum = 4;
1069 for(Annotation.NameValuePair pair : _pairs) {
1070 accum += pair.getSize();
1071 }
1072 return accum;
1073 }
1074
1075 /**
1076 * Writes this annotation into the stream.
1077 * @param cp constant pool
1078 * @param baos stream
1079 * @throws IOException
1080 */
1081 public void writeToByteArrayOutputStream(ConstantPool cp, ByteArrayOutputStream baos) throws IOException {
1082 baos.write(Types.bytesFromShort(cp.indexOf(_type)));
1083 baos.write(Types.bytesFromShort((short)(_pairCount & 0xffff)));
1084 for(Annotation.NameValuePair nvp:_pairs) {
1085 nvp.writeToByteArrayOutputStream(cp, baos);
1086 }
1087 }
1088
1089 /**
1090 * Returns a string representation of the object.
1091 * @return a string representation of the object.
1092 */
1093 public String toString() {
1094 StringBuilder sb = new StringBuilder();
1095 sb.append("@");
1096 sb.append(_type.toString());
1097 if (_pairCount>0) {
1098 sb.append("(");
1099 boolean first = true;
1100 for(NameValuePair nvp:_pairs) {
1101 if (first) {
1102 first = false;
1103 }
1104 else {
1105 sb.append(", ");
1106 }
1107 sb.append(nvp.toString());
1108 }
1109 sb.append(")");
1110 }
1111 return sb.toString();
1112 }
1113
1114 /**
1115 * Returns a string representation of the object like it would be seen in a Java listing.
1116 * @return a string representation of the object.
1117 */
1118 public String toStringJava() {
1119 StringBuilder sb = new StringBuilder();
1120 sb.append("@");
1121 String typeName = ClassFileTools.getTypeString(_type.toString(),"").replace('$','.');
1122 typeName = typeName.substring(0, typeName.length()-1);
1123 sb.append(typeName);
1124 if (_pairCount>0) {
1125 sb.append("(");
1126 boolean first = true;
1127 for(NameValuePair nvp:_pairs) {
1128 if (first) {
1129 first = false;
1130 }
1131 else {
1132 sb.append(", ");
1133 }
1134 sb.append(nvp.toString());
1135 }
1136 sb.append(")");
1137 }
1138 return sb.toString();
1139 }
1140
1141 /**
1142 * Returns the type of the annotation.
1143 * @return _type string
1144 */
1145 public String getType() {
1146 return _type.toString();
1147 }
1148
1149 /**
1150 * Returns a list of the pairs.
1151 * @return list of name-value pairs.
1152 */
1153 public List<NameValuePair> getPairs() {
1154 ArrayList<NameValuePair> list = new ArrayList<NameValuePair>();
1155 for(NameValuePair nvp: _pairs) {
1156 list.add(nvp);
1157 }
1158 return list;
1159 }
1160
1161 /**
1162 * Indicates whether some other object is "equal to" this one.
1163 * @param o the reference object with which to compare.
1164 * @return <code>true</code> if this object is the same as the obj argument; <code>false</code> otherwise.
1165 */
1166 public boolean equals(Object o) {
1167 if (this == o) {
1168 return true;
1169 }
1170 if (o == null || getClass() != o.getClass()) {
1171 return false;
1172 }
1173
1174 Annotation that = (Annotation)o;
1175
1176 if (_pairCount != that._pairCount) {
1177 return false;
1178 }
1179 if (!Arrays.equals(_pairs, that._pairs)) {
1180 return false;
1181 }
1182 if (_type != null ? !_type.equals(that._type) : that._type != null) {
1183 return false;
1184 }
1185
1186 return true;
1187 }
1188
1189 /**
1190 * Returns a hash code value for the object.
1191 * @return a hash code value for this object.
1192 */
1193 public int hashCode() {
1194 int result;
1195 result = (_type != null ? _type.hashCode() : 0);
1196 result = 31 * result + _pairCount;
1197 result = 31 * result + (_pairs != null ? Arrays.hashCode(_pairs) : 0);
1198 return result;
1199 }
1200 }
1201
1202 /**
1203 * Creates a new abstract annotations attribute.
1204 * @param name name of attribute
1205 * @param data data array
1206 * @param cp constant pool
1207 */
1208 public AAnnotationsAttributeInfo(AUTFPoolInfo name, byte data[], ConstantPool cp) {
1209 super(name, data, cp);
1210 }
1211
1212 /**
1213 * Adjust program counter values contained in this attribute, starting at startPC, by adding deltaPC to them.
1214 *
1215 * @param startPC program counter to start at
1216 * @param deltaPC change in program counter values
1217 */
1218 public void adjustPC(int startPC, int deltaPC) {
1219 // nothing to do
1220 }
1221
1222 /**
1223 * Translate the program counter values contained in this attribute from an old line number table to a new one.
1224 *
1225 * @param index critical point (insertion or deletion point)
1226 * @param deltaIndex delta value to add to all old line numbers greater than the critical point
1227 * @param oldLnt old line number table
1228 * @param newLnt new line number table
1229 */
1230 public void translatePC(int index, int deltaIndex, LineNumberTable oldLnt, LineNumberTable newLnt) {
1231 // nothing to do
1232 }
1233
1234 /**
1235 * Creates and returns a copy of this object.
1236 */
1237 public Object clone() throws CloneNotSupportedException {
1238 return super.clone();
1239 }
1240 }