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 }