001 package serp.bytecode; 002 003 import java.io.*; 004 import java.lang.reflect.*; 005 import java.util.*; 006 007 import serp.bytecode.lowlevel.*; 008 import serp.bytecode.visitor.*; 009 import serp.util.*; 010 011 /** 012 * A declared annotation. 013 * 014 * @author Abe White 015 */ 016 public class Annotation implements BCEntity, VisitAcceptor { 017 private static Method ENUM_VALUEOF = null; 018 private static Method ENUM_NAME = null; 019 static { 020 try { 021 Class c = Class.forName("java.lang.Enum"); 022 ENUM_VALUEOF = c.getMethod("valueOf", new Class[] { 023 Class.class, String.class }); 024 ENUM_NAME = c.getMethod("name", (Class[]) null); 025 } catch (Throwable t) { 026 // pre-1.5 JDK 027 } 028 } 029 030 private BCEntity _owner = null; 031 private int _typeIndex = 0; 032 private List _properties = null; 033 034 Annotation(BCEntity owner) { 035 _owner = owner; 036 } 037 038 /** 039 * Annotations are stored in an {@link Annotations} table or as 040 * part of an {@link Annotation} property value. 041 */ 042 public BCEntity getOwner() { 043 return _owner; 044 } 045 046 void invalidate() { 047 _owner = null; 048 } 049 050 /** 051 * The index in the class {@link ConstantPool} of the 052 * {@link UTF8Entry} holding the type of this annotation. 053 */ 054 public int getTypeIndex() { 055 return _typeIndex; 056 } 057 058 /** 059 * The index in the class {@link ConstantPool} of the 060 * {@link UTF8Entry} holding the type of this annotation. 061 */ 062 public void setTypeIndex(int index) { 063 _typeIndex = index; 064 } 065 066 /** 067 * The name of this annotation's type. 068 */ 069 public String getTypeName() { 070 String desc = ((UTF8Entry) getPool().getEntry(_typeIndex)).getValue(); 071 return getProject().getNameCache().getExternalForm(desc, false); 072 } 073 074 /** 075 * The {@link Class} object for this annotation's type. 076 */ 077 public Class getType() { 078 return Strings.toClass(getTypeName(), getClassLoader()); 079 } 080 081 /** 082 * The bytecode for the type of this annotation. 083 */ 084 public BCClass getTypeBC() { 085 return getProject().loadClass(getTypeName(), getClassLoader()); 086 } 087 088 /** 089 * This annotation's type. 090 */ 091 public void setType(String type) { 092 type = getProject().getNameCache().getInternalForm(type, true); 093 _typeIndex = getPool().findUTF8Entry(type, true); 094 } 095 096 /** 097 * This annotation's type. 098 */ 099 public void setType(Class type) { 100 setType(type.getName()); 101 } 102 103 /** 104 * This annotation's type. 105 */ 106 public void setType(BCClass type) { 107 setType(type.getName()); 108 } 109 110 /** 111 * All declared properties. 112 */ 113 public Property[] getProperties() { 114 if (_properties == null) 115 return new Property[0]; 116 return (Property[]) _properties.toArray 117 (new Property[_properties.size()]); 118 } 119 120 /** 121 * Set the annotation properties. This method is useful when 122 * importing properties from another instance. 123 */ 124 public void setProperties(Property[] props) { 125 clearProperties(); 126 if (props != null) 127 for (int i = 0; i < props.length; i++) 128 addProperty(props[i]); 129 } 130 131 /** 132 * Return the property with the given name, or null if none. 133 */ 134 public Property getProperty(String name) { 135 if (_properties == null) 136 return null; 137 Property prop; 138 for (int i = 0; i < _properties.size(); i++) { 139 prop = (Property) _properties.get(i); 140 if (prop.getName().equals(name)) 141 return prop; 142 } 143 return null; 144 } 145 146 /** 147 * Import a property from another instance. 148 * 149 * @return the newly added property 150 */ 151 public Property addProperty(Property p) { 152 Property prop = addProperty(p.getName()); 153 prop.setValue(p.getValue()); 154 return prop; 155 } 156 157 /** 158 * Add a new property. 159 */ 160 public Property addProperty(String name) { 161 Property prop = new Property(this); 162 prop.setName(name); 163 if (_properties == null) 164 _properties = new ArrayList(); 165 _properties.add(prop); 166 return prop; 167 } 168 169 /** 170 * Clear all annotation properties. 171 */ 172 public void clearProperties() { 173 if (_properties == null) 174 return; 175 for (int i = 0; i < _properties.size(); i++) 176 ((Property) _properties.get(i)).invalidate(); 177 _properties.clear(); 178 } 179 180 /** 181 * Remove the given property. 182 * 183 * @return true if an property was removed, false otherwise 184 */ 185 public boolean removeProperty(Property prop) { 186 return prop != null && removeProperty(prop.getName()); 187 } 188 189 /** 190 * Remove the property with the given name. 191 * 192 * @return true if a property was removed, false otherwise 193 */ 194 public boolean removeProperty(String name) { 195 if (name == null || _properties == null) 196 return false; 197 Property prop; 198 for (int i = 0; i < _properties.size(); i++) { 199 prop = (Property) _properties.get(i); 200 if (prop.getName().equals(name)) { 201 prop.invalidate(); 202 _properties.remove(i); 203 return true; 204 } 205 } 206 return false; 207 } 208 209 public Project getProject() { 210 return _owner.getProject(); 211 } 212 213 public ConstantPool getPool() { 214 return _owner.getPool(); 215 } 216 217 public ClassLoader getClassLoader() { 218 return _owner.getClassLoader(); 219 } 220 221 public boolean isValid() { 222 return _owner != null; 223 } 224 225 public void acceptVisit(BCVisitor visit) { 226 visit.enterAnnotation(this); 227 if (_properties != null) 228 for (int i = 0; i < _properties.size(); i++) 229 ((Property) _properties.get(i)).acceptVisit(visit); 230 visit.exitAnnotation(this); 231 } 232 233 int getLength() { 234 int len = 4; 235 if (_properties != null) 236 for (int i = 0; i < _properties.size(); i++) 237 len += ((Property) _properties.get(i)).getLength(); 238 return len; 239 } 240 241 void read(DataInput in) throws IOException { 242 _typeIndex = in.readUnsignedShort(); 243 clearProperties(); 244 int props = in.readUnsignedShort(); 245 if (props > 0) { 246 if (_properties == null) 247 _properties = new ArrayList(props); 248 Property prop; 249 for (int i = 0; i < props; i++) { 250 prop = new Property(this); 251 prop.read(in); 252 _properties.add(prop); 253 } 254 } 255 } 256 257 void write(DataOutput out) throws IOException { 258 out.writeShort(_typeIndex); 259 out.writeShort((_properties == null) ? 0 : _properties.size()); 260 if (_properties != null) { 261 for (int i = 0; i < _properties.size(); i++) 262 ((Property) _properties.get(i)).write(out); 263 } 264 } 265 266 /** 267 * An annotation property. 268 */ 269 public static class Property implements BCEntity, VisitAcceptor { 270 private Annotation _owner = null; 271 private int _nameIndex = 0; 272 private final Value _value = new Value(); 273 private Value[] _values = null; 274 275 Property(Annotation owner) { 276 _owner = owner; 277 } 278 279 /** 280 * The owning annotation. 281 */ 282 public Annotation getAnnotation() { 283 return _owner; 284 } 285 286 void invalidate() { 287 _owner = null; 288 } 289 290 /** 291 * Return the index in the class {@link ConstantPool} of the 292 * {@link UTF8Entry} holding the name of this property. 293 */ 294 public int getNameIndex() { 295 return _nameIndex; 296 } 297 298 /** 299 * Set the index in the class {@link ConstantPool} of the 300 * {@link UTF8Entry} holding the name of this property. 301 */ 302 public void setNameIndex(int index) { 303 _nameIndex = index; 304 } 305 306 /** 307 * Return the name of this property. 308 */ 309 public String getName() { 310 return ((UTF8Entry) getPool().getEntry(_nameIndex)).getValue(); 311 } 312 313 /** 314 * Set the name of this property. 315 */ 316 public void setName(String name) { 317 _nameIndex = getPool().findUTF8Entry(name, true); 318 } 319 320 /** 321 * Return the value of the property as its wrapper type. 322 * Returns class values as the class name. 323 */ 324 public Object getValue() { 325 if (_values == null) 326 return getValue(_value); 327 Object[] vals = new Object[_values.length]; 328 for (int i = 0; i < vals.length; i++) 329 vals[i] = getValue(_values[i]); 330 return vals; 331 } 332 333 /** 334 * Extract the Java value. 335 */ 336 private Object getValue(Value val) { 337 if (val.index == -1) 338 return val.value; 339 340 Object o = ((ConstantEntry) getPool().getEntry(val.index)). 341 getConstant(); 342 if (val.index2 != -1) { 343 // enum value 344 String e = getProject().getNameCache(). 345 getExternalForm((String) o, false); 346 String name = ((UTF8Entry) getPool().getEntry(val.index2)). 347 getValue(); 348 try { 349 Class cls = Class.forName(e, true, getClassLoader()); 350 return ENUM_VALUEOF.invoke(null, new Object[] {cls, name}); 351 } catch (Throwable t) { 352 return e + "." + name; 353 } 354 } 355 if (val.type == null) 356 return o; 357 358 switch (val.type.getName().charAt(0)) { 359 case 'b': 360 if (val.type == boolean.class) 361 return (((Number) o).intValue() != 0) ? Boolean.TRUE 362 : Boolean.FALSE; 363 return new Byte(((Number) o).byteValue()); 364 case 'c': 365 return new Character((char) ((Number) o).intValue()); 366 case 'j': // java.lang.Class 367 return getProject().getNameCache().getExternalForm((String) o, 368 false); 369 case 's': 370 return new Short(((Number) o).shortValue()); 371 default: 372 return o; 373 } 374 } 375 376 /** 377 * Set value of this property. The value should be an instance of any 378 * primitive wrapper type, String, Class, BCClass, an enum constant, 379 * an annotation, or an array of any of these types. 380 */ 381 public void setValue(Object value) { 382 if (!value.getClass().isArray()) { 383 _values = null; 384 setValue(_value, value); 385 } else { 386 _value.value = null; 387 _values = new Value[Array.getLength(value)]; 388 for (int i = 0; i < _values.length; i++) { 389 _values[i] = new Value(); 390 setValue(_values[i], Array.get(value, i)); 391 } 392 } 393 } 394 395 /** 396 * Set the given value. 397 */ 398 private void setValue(Value val, Object o) { 399 if (o instanceof String) 400 setValue(val, (String) o); 401 else if (o instanceof Boolean) 402 setValue(val, ((Boolean) o).booleanValue()); 403 else if (o instanceof Byte) 404 setValue(val, ((Byte) o).byteValue()); 405 else if (o instanceof Character) 406 setValue(val, ((Character) o).charValue()); 407 else if (o instanceof Double) 408 setValue(val, ((Double) o).doubleValue()); 409 else if (o instanceof Float) 410 setValue(val, ((Float) o).floatValue()); 411 else if (o instanceof Integer) 412 setValue(val, ((Integer) o).intValue()); 413 else if (o instanceof Long) 414 setValue(val, ((Long) o).longValue()); 415 else if (o instanceof Short) 416 setValue(val, ((Short) o).shortValue()); 417 else if (o instanceof Class) 418 setClassNameValue(val, ((Class) o).getName()); 419 else if (o instanceof BCClass) 420 setClassNameValue(val, ((BCClass) o).getName()); 421 else if (o instanceof Annotation) 422 setValue(val, (Annotation) o); 423 else { 424 String name = getEnumName(o); 425 if (name != null) { 426 String type = getProject().getNameCache(). 427 getInternalForm(o.getClass().getName(), false); 428 val.index = getPool().findUTF8Entry(type, true); 429 val.index2 = getPool().findUTF8Entry(name, true); 430 val.value = null; 431 val.type = null; 432 } else { 433 val.index = -1; 434 val.index2 = -1; 435 val.value = o; 436 val.type = o.getClass(); 437 } 438 } 439 } 440 441 /** 442 * Return the name of this enum value, or null if not an enum. 443 */ 444 private static String getEnumName(Object o) { 445 for (Class c = o.getClass(); true; c = c.getSuperclass()) { 446 if (c == Object.class || c == null) 447 return null; 448 if ("java.lang.Enum".equals(c.getName())) 449 break; 450 } 451 try { 452 return (String) ENUM_NAME.invoke(o, (Object[]) null); 453 } catch (Throwable t) { 454 return o.toString(); 455 } 456 } 457 458 /** 459 * Return the string value of this property, or null if not set. 460 */ 461 public String getStringValue() { 462 return (String) getValue(); 463 } 464 465 /** 466 * Return the boolean value of this property, or false if not set. 467 */ 468 public boolean getBooleanValue() { 469 Object value = getValue(); 470 return (value == null) ? false : ((Boolean) value).booleanValue(); 471 } 472 473 /** 474 * Return the byte value of this property, or false if not set. 475 */ 476 public byte getByteValue() { 477 Object value = getValue(); 478 return (value == null) ? (byte) 0 : ((Number) value).byteValue(); 479 } 480 481 /** 482 * Return the int value of this property, or 0 if not set. 483 */ 484 public int getIntValue() { 485 Object value = getValue(); 486 return (value == null) ? 0 : ((Number) value).intValue(); 487 } 488 489 /** 490 * Return the long value of this property, or 0 if not set. 491 */ 492 public long getLongValue() { 493 Object value = getValue(); 494 return (value == null) ? 0L : ((Number) value).longValue(); 495 } 496 497 /** 498 * Return the float value of this property, or 0 if not set. 499 */ 500 public float getFloatValue() { 501 Object value = getValue(); 502 return (value == null) ? 0F : ((Number) value).floatValue(); 503 } 504 505 /** 506 * Return the double value of this property, or 0 if not set. 507 */ 508 public double getDoubleValue() { 509 Object value = getValue(); 510 return (value == null) ? 0D : ((Number) value).doubleValue(); 511 } 512 513 /** 514 * Return the short value of this property, or 0 if not set. 515 */ 516 public short getShortValue() { 517 Object value = getValue(); 518 return (value == null) ? (short) 0 : ((Number) value).shortValue(); 519 } 520 521 /** 522 * Return the class value of this property, or null if not set. 523 */ 524 public String getClassNameValue() { 525 return (String) getValue(); 526 } 527 528 /** 529 * Return the annotation value of this property, or null if not set. 530 */ 531 public Annotation getAnnotationValue() { 532 return (Annotation) getValue(); 533 } 534 535 /** 536 * Set the string value of this property. 537 */ 538 public void setValue(String value) { 539 _values = null; 540 setValue(_value, value); 541 } 542 543 /** 544 * Set the string value of this property. 545 */ 546 private void setValue(Value val, String o) { 547 val.index = getPool().findUTF8Entry(o, true); 548 val.index2 = -1; 549 val.value = null; 550 val.type = null; 551 } 552 553 /** 554 * Set the boolean value of this property. 555 */ 556 public void setValue(boolean value) { 557 _values = null; 558 setValue(_value, value); 559 } 560 561 /** 562 * Set the boolean value of this property. 563 */ 564 private void setValue(Value val, boolean o) { 565 setValue(val, (o) ? 1 : 0); 566 val.type = boolean.class; 567 } 568 569 /** 570 * Set the byte value of this property. 571 */ 572 public void setValue(byte value) { 573 _values = null; 574 setValue(_value, value); 575 } 576 577 /** 578 * Set the byte value of this property. 579 */ 580 private void setValue(Value val, byte o) { 581 setValue(val, (int) o); 582 val.type = byte.class; 583 } 584 585 /** 586 * Set the int value of this property. 587 */ 588 public void setValue(int value) { 589 _values = null; 590 setValue(_value, value); 591 } 592 593 /** 594 * Set the int value of this property. 595 */ 596 private void setValue(Value val, int o) { 597 val.index = getPool().findIntEntry(o, true); 598 val.index2 = -1; 599 val.value = null; 600 val.type = null; 601 } 602 603 /** 604 * Set the long value of this property. 605 */ 606 public void setValue(long value) { 607 _values = null; 608 setValue(_value, value); 609 } 610 611 /** 612 * Set the long value of this property. 613 */ 614 private void setValue(Value val, long o) { 615 val.index = getPool().findLongEntry(o, true); 616 val.index2 = -1; 617 val.value = null; 618 val.type = null; 619 } 620 621 /** 622 * Set the float value of this property. 623 */ 624 public void setValue(float value) { 625 _values = null; 626 setValue(_value, value); 627 } 628 629 /** 630 * Set the float value of this property. 631 */ 632 private void setValue(Value val, float o) { 633 val.index = getPool().findFloatEntry(o, true); 634 val.index2 = -1; 635 val.value = null; 636 val.type = null; 637 } 638 639 /** 640 * Set the double value of this property. 641 */ 642 public void setValue(double value) { 643 _values = null; 644 setValue(_value, value); 645 } 646 647 /** 648 * Set the double value of this property. 649 */ 650 private void setValue(Value val, double o) { 651 val.index = getPool().findDoubleEntry(o, true); 652 val.index2 = -1; 653 val.value = null; 654 val.type = null; 655 } 656 657 /** 658 * Set the short value of this property. 659 */ 660 public void setValue(short value) { 661 _values = null; 662 setValue(_value, value); 663 } 664 665 /** 666 * Set the short value of this property. 667 */ 668 private void setValue(Value val, short o) { 669 setValue(val, (int) o); 670 val.type = short.class; 671 } 672 673 /** 674 * Set the class value of this property. 675 */ 676 public void setValue(Class value) { 677 setClassNameValue(value.getName()); 678 } 679 680 /** 681 * Set the class value of this property. 682 */ 683 public void setValue(BCClass value) { 684 setClassNameValue(value.getName()); 685 } 686 687 /** 688 * Set the class value of this property. 689 */ 690 public void setClassNameValue(String value) { 691 _values = null; 692 setClassNameValue(_value, value); 693 } 694 695 /** 696 * Set the class value of this property. 697 */ 698 private void setClassNameValue(Value val, String o) { 699 o = getProject().getNameCache().getInternalForm(o, true); 700 val.index = getPool().findUTF8Entry(o, true); 701 val.index2 = -1; 702 val.value = null; 703 val.type = Class.class; 704 } 705 706 /** 707 * Set the annotation value of this property by importing the given 708 * annotation from another instance. 709 */ 710 public Annotation setValue(Annotation value) { 711 _values = null; 712 return setValue(_value, value); 713 } 714 715 /** 716 * Set the annotation value of this property by importing the given 717 * annotation from another instance. 718 */ 719 private Annotation setValue(Value val, Annotation o) { 720 Annotation anno = new Annotation(this); 721 anno.setType(o.getTypeName()); 722 anno.setProperties(o.getProperties()); 723 val.index = -1; 724 val.index2 = -1; 725 val.value = anno; 726 val.type = null; 727 return anno; 728 } 729 730 /** 731 * Set the annotation value of this property by importing the given 732 * annotation from another instance. 733 */ 734 public Annotation[] setValue(Annotation[] value) { 735 _value.value = null; 736 _values = new Value[value.length]; 737 Annotation[] ret = new Annotation[value.length]; 738 for (int i = 0; i < _values.length; i++) { 739 _values[i] = new Value(); 740 ret[i] = setValue(_values[i], value[i]); 741 } 742 return ret; 743 } 744 745 /** 746 * Set this property value to a new annotation of the given type, 747 * returning the annotation for manipulation. 748 */ 749 public Annotation newAnnotationValue(Class type) { 750 return newAnnotationValue(type.getName()); 751 } 752 753 /** 754 * Set this property value to a new annotation of the given type, 755 * returning the annotation for manipulation. 756 */ 757 public Annotation newAnnotationValue(BCClass type) { 758 return newAnnotationValue(type.getName()); 759 } 760 761 /** 762 * Set this property value to a new annotation of the given type, 763 * returning the annotation for manipulation. 764 */ 765 public Annotation newAnnotationValue(String type) { 766 Annotation anno = new Annotation(this); 767 anno.setType(type); 768 _values = null; 769 _value.index = -1; 770 _value.index2 = -1; 771 _value.value = anno; 772 _value.type = null; 773 return anno; 774 } 775 776 /** 777 * Set this property value to a new annotation array of the given type 778 * and length, returning the annotations for manipulation. 779 */ 780 public Annotation[] newAnnotationArrayValue(Class type, int length) { 781 return newAnnotationArrayValue(type.getName(), length); 782 } 783 784 /** 785 * Set this property value to a new annotation array of the given type 786 * and length, returning the annotations for manipulation. 787 */ 788 public Annotation[] newAnnotationArrayValue(BCClass type, int length) { 789 return newAnnotationArrayValue(type.getName(), length); 790 } 791 792 /** 793 * Set this property value to a new annotation array of the given type 794 * and length, returning the annotations for manipulation. 795 */ 796 public Annotation[] newAnnotationArrayValue(String type, int length) { 797 _value.value = null; 798 _values = new Value[length]; 799 Annotation[] ret = new Annotation[length]; 800 for (int i = 0; i < length; i++) { 801 ret[i] = new Annotation(this); 802 ret[i].setType(type); 803 _values[i] = new Value(); 804 _values[i].index = -1; 805 _values[i].index2 = -1; 806 _values[i].value = ret[i]; 807 _values[i].type = null; 808 } 809 return ret; 810 } 811 812 public Project getProject() { 813 return _owner.getProject(); 814 } 815 816 public ConstantPool getPool() { 817 return _owner.getPool(); 818 } 819 820 public ClassLoader getClassLoader() { 821 return _owner.getClassLoader(); 822 } 823 824 public boolean isValid() { 825 return _owner != null && (_values != null || _value.index != -1 826 || _value.value != null); 827 } 828 829 public void acceptVisit(BCVisitor visit) { 830 visit.enterAnnotationProperty(this); 831 visit.exitAnnotationProperty(this); 832 } 833 834 int getLength() { 835 if (!isValid()) 836 throw new IllegalStateException(); 837 838 int len = 2; // name 839 if (_values == null) 840 len += getLength(_value); 841 else { 842 len += 3; // arr length + tag 843 for (int i = 0; i < _values.length; i++) 844 len += getLength(_values[i]); 845 } 846 return len; 847 } 848 849 /** 850 * Return the length of the given value. 851 */ 852 private int getLength(Value val) { 853 if (val.index2 != -1) 854 return 5; // tag + enum type + enum name 855 if (val.index != -1) 856 return 3; // tag + constant or class 857 return 1 + ((Annotation) val.value).getLength(); // tag + anno 858 } 859 860 void read(DataInput in) throws IOException { 861 _nameIndex = in.readUnsignedShort(); 862 int tag = in.readByte(); 863 if (tag == '[') { 864 int len = in.readUnsignedShort(); 865 _values = new Value[len]; 866 for (int i = 0; i < len; i++) { 867 _values[i] = new Value(); 868 read(_values[i], in.readByte(), in); 869 } 870 } else 871 read(_value, tag, in); 872 } 873 874 /** 875 * Read data into the given value. 876 */ 877 private void read(Value val, int tag, DataInput in) throws IOException { 878 switch (tag) { 879 case 'B': 880 val.index = in.readUnsignedShort(); 881 val.index2 = -1; 882 val.value = null; 883 val.type = byte.class; 884 break; 885 case 'C': 886 val.index = in.readUnsignedShort(); 887 val.index2 = -1; 888 val.value = null; 889 val.type = char.class; 890 break; 891 case 'D': 892 case 'F': 893 case 'I': 894 case 'J': 895 case 'S': 896 case 's': 897 val.index = in.readUnsignedShort(); 898 val.index2 = -1; 899 val.value = null; 900 val.type = null; 901 break; 902 case 'Z': 903 val.index = in.readUnsignedShort(); 904 val.index2 = -1; 905 val.value = null; 906 val.type = boolean.class; 907 break; 908 case 'c': 909 val.index = in.readUnsignedShort(); 910 val.index2 = -1; 911 val.value = null; 912 val.type = Class.class; 913 break; 914 case 'e': 915 val.index = in.readUnsignedShort(); 916 val.index2 = in.readUnsignedShort(); 917 val.value = null; 918 val.type = null; 919 break; 920 case '@': 921 Annotation anno = new Annotation(this); 922 anno.read(in); 923 val.index = -1; 924 val.index2 = -1; 925 val.value = anno; 926 val.type = null; 927 break; 928 default: 929 throw new IllegalStateException(String.valueOf(tag)); 930 } 931 } 932 933 void write(DataOutput out) throws IOException { 934 if (!isValid()) 935 throw new IllegalStateException(); 936 937 out.writeShort(_nameIndex); 938 if (_values == null) 939 write(_value, out); 940 else { 941 out.writeByte('['); 942 out.writeShort(_values.length); 943 for (int i = 0; i < _values.length; i++) 944 write(_values[i], out); 945 } 946 } 947 948 /** 949 * Write the data for the given value to the stream. 950 */ 951 private void write(Value val, DataOutput out) throws IOException { 952 if (val.index2 != -1) { 953 out.writeByte('e'); 954 out.writeShort(val.index); 955 out.writeShort(val.index2); 956 } else if (val.index != -1) { 957 if (val.type != null) { 958 switch (val.type.getName().charAt(0)) { 959 case 'b': 960 if (val.type == byte.class) 961 out.writeByte('B'); 962 else 963 out.writeByte('Z'); 964 break; 965 case 'c': 966 out.writeByte('C'); 967 break; 968 case 'j': // java.lang.Class 969 out.writeByte('c'); 970 break; 971 case 's': 972 out.writeByte('S'); 973 break; 974 default: 975 throw new IllegalStateException(val.type.getName()); 976 } 977 } else { 978 Entry entry = getPool().getEntry(val.index); 979 if (entry instanceof DoubleEntry) 980 out.writeByte('D'); 981 else if (entry instanceof FloatEntry) 982 out.writeByte('F'); 983 else if (entry instanceof IntEntry) 984 out.writeByte('I'); 985 else if (entry instanceof LongEntry) 986 out.writeByte('J'); 987 else if (entry instanceof UTF8Entry) 988 out.writeByte('s'); 989 else 990 throw new IllegalStateException(entry.getClass(). 991 getName()); 992 } 993 out.writeShort(val.index); 994 } else { 995 out.writeByte('@'); 996 ((Annotation) val.value).write(out); 997 } 998 } 999 1000 /** 1001 * Property value struct. 1002 */ 1003 private static class Value { 1004 public int index = -1; 1005 public int index2 = -1; 1006 public Class type = null; 1007 public Object value = null; 1008 } 1009 } 1010 }