1 package serp.bytecode;
2
3 import java.io.*;
4 import java.lang.reflect.*;
5 import java.util.*;
6
7 import serp.bytecode.lowlevel.*;
8 import serp.bytecode.visitor.*;
9 import serp.util.*;
10
11 /***
12 * A declared annotation.
13 *
14 * @author Abe White
15 */
16 public class Annotation implements BCEntity, VisitAcceptor {
17 private static Method ENUM_VALUEOF = null;
18 private static Method ENUM_NAME = null;
19 static {
20 try {
21 Class c = Class.forName("java.lang.Enum");
22 ENUM_VALUEOF = c.getMethod("valueOf", new Class[] {
23 Class.class, String.class });
24 ENUM_NAME = c.getMethod("name", (Class[]) null);
25 } catch (Throwable t) {
26
27 }
28 }
29
30 private BCEntity _owner = null;
31 private int _typeIndex = 0;
32 private List _properties = null;
33
34 Annotation(BCEntity owner) {
35 _owner = owner;
36 }
37
38 /***
39 * Annotations are stored in an {@link Annotations} table or as
40 * part of an {@link Annotation} property value.
41 */
42 public BCEntity getOwner() {
43 return _owner;
44 }
45
46 void invalidate() {
47 _owner = null;
48 }
49
50 /***
51 * The index in the class {@link ConstantPool} of the
52 * {@link UTF8Entry} holding the type of this annotation.
53 */
54 public int getTypeIndex() {
55 return _typeIndex;
56 }
57
58 /***
59 * The index in the class {@link ConstantPool} of the
60 * {@link UTF8Entry} holding the type of this annotation.
61 */
62 public void setTypeIndex(int index) {
63 _typeIndex = index;
64 }
65
66 /***
67 * The name of this annotation's type.
68 */
69 public String getTypeName() {
70 String desc = ((UTF8Entry) getPool().getEntry(_typeIndex)).getValue();
71 return getProject().getNameCache().getExternalForm(desc, false);
72 }
73
74 /***
75 * The {@link Class} object for this annotation's type.
76 */
77 public Class getType() {
78 return Strings.toClass(getTypeName(), getClassLoader());
79 }
80
81 /***
82 * The bytecode for the type of this annotation.
83 */
84 public BCClass getTypeBC() {
85 return getProject().loadClass(getTypeName(), getClassLoader());
86 }
87
88 /***
89 * This annotation's type.
90 */
91 public void setType(String type) {
92 type = getProject().getNameCache().getInternalForm(type, true);
93 _typeIndex = getPool().findUTF8Entry(type, true);
94 }
95
96 /***
97 * This annotation's type.
98 */
99 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
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':
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;
839 if (_values == null)
840 len += getLength(_value);
841 else {
842 len += 3;
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;
855 if (val.index != -1)
856 return 3;
857 return 1 + ((Annotation) val.value).getLength();
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':
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 }