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
13
14
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
40
41
42 public BCEntity getOwner() {
43 return _owner;
44 }
45
46 void invalidate() {
47 _owner = null;
48 }
49
50
51
52
53
54 public int getTypeIndex() {
55 return _typeIndex;
56 }
57
58
59
60
61
62 public void setTypeIndex(int index) {
63 _typeIndex = index;
64 }
65
66
67
68
69 public String getTypeName() {
70 String desc = ((UTF8Entry) getPool().getEntry(_typeIndex)).getValue();
71 return getProject().getNameCache().getExternalForm(desc, false);
72 }
73
74
75
76
77 public Class getType() {
78 return Strings.toClass(getTypeName(), getClassLoader());
79 }
80
81
82
83
84 public BCClass getTypeBC() {
85 return getProject().loadClass(getTypeName(), getClassLoader());
86 }
87
88
89
90
91 public void setType(String type) {
92 type = getProject().getNameCache().getInternalForm(type, true);
93 _typeIndex = getPool().findUTF8Entry(type, true);
94 }
95
96
97
98
99 public void setType(Class type) {
100 setType(type.getName());
101 }
102
103
104
105
106 public void setType(BCClass type) {
107 setType(type.getName());
108 }
109
110
111
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
122
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
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
148
149
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
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
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
182
183
184
185 public boolean removeProperty(Property prop) {
186 return prop != null && removeProperty(prop.getName());
187 }
188
189
190
191
192
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
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
281
282 public Annotation getAnnotation() {
283 return _owner;
284 }
285
286 void invalidate() {
287 _owner = null;
288 }
289
290
291
292
293
294 public int getNameIndex() {
295 return _nameIndex;
296 }
297
298
299
300
301
302 public void setNameIndex(int index) {
303 _nameIndex = index;
304 }
305
306
307
308
309 public String getName() {
310 return ((UTF8Entry) getPool().getEntry(_nameIndex)).getValue();
311 }
312
313
314
315
316 public void setName(String name) {
317 _nameIndex = getPool().findUTF8Entry(name, true);
318 }
319
320
321
322
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
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
378
379
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
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
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
460
461 public String getStringValue() {
462 return (String) getValue();
463 }
464
465
466
467
468 public boolean getBooleanValue() {
469 Object value = getValue();
470 return (value == null) ? false : ((Boolean) value).booleanValue();
471 }
472
473
474
475
476 public byte getByteValue() {
477 Object value = getValue();
478 return (value == null) ? (byte) 0 : ((Number) value).byteValue();
479 }
480
481
482
483
484 public int getIntValue() {
485 Object value = getValue();
486 return (value == null) ? 0 : ((Number) value).intValue();
487 }
488
489
490
491
492 public long getLongValue() {
493 Object value = getValue();
494 return (value == null) ? 0L : ((Number) value).longValue();
495 }
496
497
498
499
500 public float getFloatValue() {
501 Object value = getValue();
502 return (value == null) ? 0F : ((Number) value).floatValue();
503 }
504
505
506
507
508 public double getDoubleValue() {
509 Object value = getValue();
510 return (value == null) ? 0D : ((Number) value).doubleValue();
511 }
512
513
514
515
516 public short getShortValue() {
517 Object value = getValue();
518 return (value == null) ? (short) 0 : ((Number) value).shortValue();
519 }
520
521
522
523
524 public String getClassNameValue() {
525 return (String) getValue();
526 }
527
528
529
530
531 public Annotation getAnnotationValue() {
532 return (Annotation) getValue();
533 }
534
535
536
537
538 public void setValue(String value) {
539 _values = null;
540 setValue(_value, value);
541 }
542
543
544
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
555
556 public void setValue(boolean value) {
557 _values = null;
558 setValue(_value, value);
559 }
560
561
562
563
564 private void setValue(Value val, boolean o) {
565 setValue(val, (o) ? 1 : 0);
566 val.type = boolean.class;
567 }
568
569
570
571
572 public void setValue(byte value) {
573 _values = null;
574 setValue(_value, value);
575 }
576
577
578
579
580 private void setValue(Value val, byte o) {
581 setValue(val, (int) o);
582 val.type = byte.class;
583 }
584
585
586
587
588 public void setValue(int value) {
589 _values = null;
590 setValue(_value, value);
591 }
592
593
594
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
605
606 public void setValue(long value) {
607 _values = null;
608 setValue(_value, value);
609 }
610
611
612
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
623
624 public void setValue(float value) {
625 _values = null;
626 setValue(_value, value);
627 }
628
629
630
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
641
642 public void setValue(double value) {
643 _values = null;
644 setValue(_value, value);
645 }
646
647
648
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
659
660 public void setValue(short value) {
661 _values = null;
662 setValue(_value, value);
663 }
664
665
666
667
668 private void setValue(Value val, short o) {
669 setValue(val, (int) o);
670 val.type = short.class;
671 }
672
673
674
675
676 public void setValue(Class value) {
677 setClassNameValue(value.getName());
678 }
679
680
681
682
683 public void setValue(BCClass value) {
684 setClassNameValue(value.getName());
685 }
686
687
688
689
690 public void setClassNameValue(String value) {
691 _values = null;
692 setClassNameValue(_value, value);
693 }
694
695
696
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
708
709
710 public Annotation setValue(Annotation value) {
711 _values = null;
712 return setValue(_value, value);
713 }
714
715
716
717
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
732
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
747
748
749 public Annotation newAnnotationValue(Class type) {
750 return newAnnotationValue(type.getName());
751 }
752
753
754
755
756
757 public Annotation newAnnotationValue(BCClass type) {
758 return newAnnotationValue(type.getName());
759 }
760
761
762
763
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
778
779
780 public Annotation[] newAnnotationArrayValue(Class type, int length) {
781 return newAnnotationArrayValue(type.getName(), length);
782 }
783
784
785
786
787
788 public Annotation[] newAnnotationArrayValue(BCClass type, int length) {
789 return newAnnotationArrayValue(type.getName(), length);
790 }
791
792
793
794
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
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
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
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
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 }