1 /*
2  * Javassist, a Java-bytecode translator toolkit.
3  * Copyright (C) 1999- Shigeru Chiba. All Rights Reserved.
4  *
5  * The contents of this file are subject to the Mozilla Public License Version
6  * 1.1 (the "License"); you may not use this file except in compliance with
7  * the License.  Alternatively, the contents of this file may be used under
8  * the terms of the GNU Lesser General Public License Version 2.1 or later,
9  * or the Apache License Version 2.0.
10  *
11  * Software distributed under the License is distributed on an "AS IS" basis,
12  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13  * for the specific language governing rights and limitations under the
14  * License.
15  */
16 
17 package javassist.bytecode;
18 
19 import java.io.ByteArrayOutputStream;
20 import java.io.DataInputStream;
21 import java.io.IOException;
22 import java.util.HashMap;
23 import java.util.Map;
24 
25 import javassist.bytecode.annotation.Annotation;
26 import javassist.bytecode.annotation.AnnotationMemberValue;
27 import javassist.bytecode.annotation.AnnotationsWriter;
28 import javassist.bytecode.annotation.ArrayMemberValue;
29 import javassist.bytecode.annotation.BooleanMemberValue;
30 import javassist.bytecode.annotation.ByteMemberValue;
31 import javassist.bytecode.annotation.CharMemberValue;
32 import javassist.bytecode.annotation.ClassMemberValue;
33 import javassist.bytecode.annotation.DoubleMemberValue;
34 import javassist.bytecode.annotation.EnumMemberValue;
35 import javassist.bytecode.annotation.FloatMemberValue;
36 import javassist.bytecode.annotation.IntegerMemberValue;
37 import javassist.bytecode.annotation.LongMemberValue;
38 import javassist.bytecode.annotation.MemberValue;
39 import javassist.bytecode.annotation.ShortMemberValue;
40 import javassist.bytecode.annotation.StringMemberValue;
41 
42 /**
43  * A class representing
44  * <code>RuntimeVisibleAnnotations_attribute</code> and
45  * <code>RuntimeInvisibleAnnotations_attribute</code>.
46  *
47  * <p>To obtain an AnnotationAttribute object, invoke
48  * <code>getAttribute(AnnotationsAttribute.visibleTag)</code>
49  * in <code>ClassFile</code>, <code>MethodInfo</code>,
50  * or <code>FieldInfo</code>.  The obtained attribute is a
51  * runtime visible annotations attribute.
52  * If the parameter is
53  * <code>AnnotationAttribute.invisibleTag</code>, then the obtained
54  * attribute is a runtime invisible one.
55  *
56  * <p>For example,
57  *
58  * <pre>
59  * import javassist.bytecode.annotation.Annotation;
60  *    :
61  * CtMethod m = ... ;
62  * MethodInfo minfo = m.getMethodInfo();
63  * AnnotationsAttribute attr = (AnnotationsAttribute)
64  *         minfo.getAttribute(AnnotationsAttribute.invisibleTag);
65  * Annotation an = attr.getAnnotation("Author");
66  * String s = ((StringMemberValue)an.getMemberValue("name")).getValue();
67  * System.out.println("@Author(name=" + s + ")");
68  * </pre>
69  *
70  * <p>This code snippet retrieves an annotation of the type <code>Author</code>
71  * from the <code>MethodInfo</code> object specified by <code>minfo</code>.
72  * Then, it prints the value of <code>name</code> in <code>Author</code>.
73  *
74  * <p>If the annotation type <code>Author</code> is annotated by a meta annotation:
75  *
76  * <pre>
77  * &#64;Retention(RetentionPolicy.RUNTIME)
78  * </pre>
79  *
80  * <p>Then <code>Author</code> is visible at runtime.  Therefore, the third
81  * statement of the code snippet above must be changed into:
82  *
83  * <pre>
84  * AnnotationsAttribute attr = (AnnotationsAttribute)
85  *         minfo.getAttribute(AnnotationsAttribute.visibleTag);
86  * </pre>
87  *
88  * <p>The attribute tag must be <code>visibleTag</code> instead of
89  * <code>invisibleTag</code>.
90  *
91  * <p>If the member value of an annotation is not specified, the default value
92  * is used as that member value.  If so, <code>getMemberValue()</code> in
93  * <code>Annotation</code> returns <code>null</code>
94  * since the default value is not included in the
95  * <code>AnnotationsAttribute</code>.  It is included in the
96  * <code>AnnotationDefaultAttribute</code> of the method declared in the
97  * annotation type.
98  *
99  * <p>If you want to record a new AnnotationAttribute object, execute the
100  * following snippet:
101  *
102  * <pre>
103  * ClassFile cf = ... ;
104  * ConstPool cp = cf.getConstPool();
105  * AnnotationsAttribute attr
106  *     = new AnnotationsAttribute(cp, AnnotationsAttribute.visibleTag);
107  * Annotation a = new Annotation("Author", cp);
108  * a.addMemberValue("name", new StringMemberValue("Chiba", cp));
109  * attr.setAnnotation(a);
110  * cf.addAttribute(attr);
111  * cf.setVersionToJava5();
112  * </pre>
113  *
114  * <p>The last statement is necessary if the class file was produced by
115  * <code>javac</code> of JDK 1.4 or earlier.  Otherwise, it is not necessary.
116  *
117  * @see AnnotationDefaultAttribute
118  * @see javassist.bytecode.annotation.Annotation
119  */
120 public class AnnotationsAttribute extends AttributeInfo {
121     /**
122      * The name of the <code>RuntimeVisibleAnnotations</code> attribute.
123      */
124     public static final String visibleTag = "RuntimeVisibleAnnotations";
125 
126     /**
127      * The name of the <code>RuntimeInvisibleAnnotations</code> attribute.
128      */
129     public static final String invisibleTag = "RuntimeInvisibleAnnotations";
130 
131     /**
132      * Constructs a <code>Runtime(In)VisibleAnnotations_attribute</code>.
133      *
134      * @param cp            constant pool
135      * @param attrname      attribute name (<code>visibleTag</code> or
136      *                      <code>invisibleTag</code>).
137      * @param info          the contents of this attribute.  It does not
138      *                      include <code>attribute_name_index</code> or
139      *                      <code>attribute_length</code>.
140      */
AnnotationsAttribute(ConstPool cp, String attrname, byte[] info)141     public AnnotationsAttribute(ConstPool cp, String attrname, byte[] info) {
142         super(cp, attrname, info);
143     }
144 
145     /**
146      * Constructs an empty
147      * <code>Runtime(In)VisibleAnnotations_attribute</code>.
148      * A new annotation can be later added to the created attribute
149      * by <code>setAnnotations()</code>.
150      *
151      * @param cp            constant pool
152      * @param attrname      attribute name (<code>visibleTag</code> or
153      *                      <code>invisibleTag</code>).
154      * @see #setAnnotations(Annotation[])
155      */
AnnotationsAttribute(ConstPool cp, String attrname)156     public AnnotationsAttribute(ConstPool cp, String attrname) {
157         this(cp, attrname, new byte[] { 0, 0 });
158     }
159 
160     /**
161      * @param n     the attribute name.
162      */
AnnotationsAttribute(ConstPool cp, int n, DataInputStream in)163     AnnotationsAttribute(ConstPool cp, int n, DataInputStream in)
164         throws IOException
165     {
166         super(cp, n, in);
167     }
168 
169     /**
170      * Returns <code>num_annotations</code>.
171      */
numAnnotations()172     public int numAnnotations() {
173         return ByteArray.readU16bit(info, 0);
174     }
175 
176     /**
177      * Copies this attribute and returns a new copy.
178      */
179     @Override
copy(ConstPool newCp, Map<String,String> classnames)180     public AttributeInfo copy(ConstPool newCp, Map<String,String> classnames) {
181         Copier copier = new Copier(info, constPool, newCp, classnames);
182         try {
183             copier.annotationArray();
184             return new AnnotationsAttribute(newCp, getName(), copier.close());
185         }
186         catch (Exception e) {
187             throw new RuntimeException(e);
188         }
189     }
190 
191     /**
192      * Parses the annotations and returns a data structure representing
193      * the annotation with the specified type.  See also
194      * <code>getAnnotations()</code> as to the returned data structure.
195      *
196      * @param type      the annotation type.
197      * @return null if the specified annotation type is not included.
198      * @see #getAnnotations()
199      */
getAnnotation(String type)200     public Annotation getAnnotation(String type) {
201         Annotation[] annotations = getAnnotations();
202         for (int i = 0; i < annotations.length; i++) {
203             if (annotations[i].getTypeName().equals(type))
204                 return annotations[i];
205         }
206 
207         return null;
208     }
209 
210     /**
211      * Adds an annotation.  If there is an annotation with the same type,
212      * it is removed before the new annotation is added.
213      *
214      * @param annotation        the added annotation.
215      */
addAnnotation(Annotation annotation)216     public void addAnnotation(Annotation annotation) {
217         String type = annotation.getTypeName();
218         Annotation[] annotations = getAnnotations();
219         for (int i = 0; i < annotations.length; i++) {
220             if (annotations[i].getTypeName().equals(type)) {
221                 annotations[i] = annotation;
222                 setAnnotations(annotations);
223                 return;
224             }
225         }
226 
227         Annotation[] newlist = new Annotation[annotations.length + 1];
228         System.arraycopy(annotations, 0, newlist, 0, annotations.length);
229         newlist[annotations.length] = annotation;
230         setAnnotations(newlist);
231     }
232 
233     /**
234      * Removes an annotation by type.
235      * After removing an annotation, if {@link #numAnnotations()} returns 0,
236      * this annotations attribute has to be removed.
237      *
238      * @param type        of annotation to remove
239      * @return whether an annotation with the given type has been removed
240      * @since 3.21
241      */
removeAnnotation(String type)242     public boolean removeAnnotation(String type) {
243         Annotation[] annotations = getAnnotations();
244         for (int i = 0; i < annotations.length; i++) {
245             if (annotations[i].getTypeName().equals(type)) {
246                 Annotation[] newlist = new Annotation[annotations.length - 1];
247                 System.arraycopy(annotations, 0, newlist, 0, i);
248                 if (i < annotations.length - 1) {
249                     System.arraycopy(annotations, i + 1, newlist, i,
250                                      annotations.length - i - 1);
251                 }
252                 setAnnotations(newlist);
253                 return true;
254             }
255         }
256         return false;
257     }
258 
259     /**
260      * Parses the annotations and returns a data structure representing
261      * that parsed annotations.  Note that changes of the node values of the
262      * returned tree are not reflected on the annotations represented by
263      * this object unless the tree is copied back to this object by
264      * <code>setAnnotations()</code>.
265      *
266      * @see #setAnnotations(Annotation[])
267      */
getAnnotations()268     public Annotation[] getAnnotations() {
269         try {
270             return new Parser(info, constPool).parseAnnotations();
271         }
272         catch (Exception e) {
273             throw new RuntimeException(e);
274         }
275     }
276 
277     /**
278      * Changes the annotations represented by this object according to
279      * the given array of <code>Annotation</code> objects.
280      *
281      * @param annotations           the data structure representing the
282      *                              new annotations.
283      */
setAnnotations(Annotation[] annotations)284     public void setAnnotations(Annotation[] annotations) {
285         ByteArrayOutputStream output = new ByteArrayOutputStream();
286         AnnotationsWriter writer = new AnnotationsWriter(output, constPool);
287         try {
288             int n = annotations.length;
289             writer.numAnnotations(n);
290             for (int i = 0; i < n; ++i)
291                 annotations[i].write(writer);
292 
293             writer.close();
294         }
295         catch (IOException e) {
296             throw new RuntimeException(e);      // should never reach here.
297         }
298 
299         set(output.toByteArray());
300     }
301 
302     /**
303      * Changes the annotations.  A call to this method is equivalent to:
304      * <pre>setAnnotations(new Annotation[] { annotation })</pre>
305      *
306      * @param annotation    the data structure representing
307      *                      the new annotation.
308      */
setAnnotation(Annotation annotation)309     public void setAnnotation(Annotation annotation) {
310         setAnnotations(new Annotation[] { annotation });
311     }
312 
313     /**
314      * @param oldname       a JVM class name.
315      * @param newname       a JVM class name.
316      */
317     @Override
renameClass(String oldname, String newname)318     void renameClass(String oldname, String newname) {
319         Map<String,String> map = new HashMap<String,String>();
320         map.put(oldname, newname);
321         renameClass(map);
322     }
323 
324     @Override
renameClass(Map<String,String> classnames)325     void renameClass(Map<String,String> classnames) {
326         Renamer renamer = new Renamer(info, getConstPool(), classnames);
327         try {
328             renamer.annotationArray();
329         } catch (Exception e) {
330             throw new RuntimeException(e);
331         }
332     }
333 
334     @Override
getRefClasses(Map<String,String> classnames)335     void getRefClasses(Map<String,String> classnames) { renameClass(classnames); }
336 
337     /**
338      * Returns a string representation of this object.
339      */
340     @Override
toString()341     public String toString() {
342         Annotation[] a = getAnnotations();
343         StringBuilder sbuf = new StringBuilder();
344         int i = 0;
345         while (i < a.length) {
346             sbuf.append(a[i++].toString());
347             if (i != a.length)
348                 sbuf.append(", ");
349         }
350 
351         return sbuf.toString();
352     }
353 
354     static class Walker {
355         byte[] info;
356 
Walker(byte[] attrInfo)357         Walker(byte[] attrInfo) {
358             info = attrInfo;
359         }
360 
parameters()361         final void parameters() throws Exception {
362             int numParam = info[0] & 0xff;
363             parameters(numParam, 1);
364         }
365 
parameters(int numParam, int pos)366         void parameters(int numParam, int pos) throws Exception {
367             for (int i = 0; i < numParam; ++i)
368                 pos = annotationArray(pos);
369         }
370 
annotationArray()371         final void annotationArray() throws Exception {
372             annotationArray(0);
373         }
374 
annotationArray(int pos)375         final int annotationArray(int pos) throws Exception {
376             int num = ByteArray.readU16bit(info, pos);
377             return annotationArray(pos + 2, num);
378         }
379 
annotationArray(int pos, int num)380         int annotationArray(int pos, int num) throws Exception {
381             for (int i = 0; i < num; ++i)
382                 pos = annotation(pos);
383 
384             return pos;
385         }
386 
annotation(int pos)387         final int annotation(int pos) throws Exception {
388             int type = ByteArray.readU16bit(info, pos);
389             int numPairs = ByteArray.readU16bit(info, pos + 2);
390             return annotation(pos + 4, type, numPairs);
391         }
392 
annotation(int pos, int type, int numPairs)393         int annotation(int pos, int type, int numPairs) throws Exception {
394             for (int j = 0; j < numPairs; ++j)
395                 pos = memberValuePair(pos);
396 
397             return pos;
398         }
399 
400         /**
401          * {@code element_value_paris}
402          */
memberValuePair(int pos)403         final int memberValuePair(int pos) throws Exception {
404             int nameIndex = ByteArray.readU16bit(info, pos);
405             return memberValuePair(pos + 2, nameIndex);
406         }
407 
408         /**
409          * {@code element_value_paris[]}
410          */
memberValuePair(int pos, int nameIndex)411         int memberValuePair(int pos, int nameIndex) throws Exception {
412             return memberValue(pos);
413         }
414 
415         /**
416          * {@code element_value}
417          */
memberValue(int pos)418         final int memberValue(int pos) throws Exception {
419             int tag = info[pos] & 0xff;
420             if (tag == 'e') {
421                 int typeNameIndex = ByteArray.readU16bit(info, pos + 1);
422                 int constNameIndex = ByteArray.readU16bit(info, pos + 3);
423                 enumMemberValue(pos, typeNameIndex, constNameIndex);
424                 return pos + 5;
425             }
426             else if (tag == 'c') {
427                 int index = ByteArray.readU16bit(info, pos + 1);
428                 classMemberValue(pos, index);
429                 return pos + 3;
430             }
431             else if (tag == '@')
432                 return annotationMemberValue(pos + 1);
433             else if (tag == '[') {
434                 int num = ByteArray.readU16bit(info, pos + 1);
435                 return arrayMemberValue(pos + 3, num);
436             }
437             else { // primitive types or String.
438                 int index = ByteArray.readU16bit(info, pos + 1);
439                 constValueMember(tag, index);
440                 return pos + 3;
441             }
442         }
443 
444         /**
445          * {@code const_value_index}
446          */
constValueMember(int tag, int index)447         void constValueMember(int tag, int index) throws Exception {}
448 
449         /**
450          * {@code enum_const_value}
451          */
enumMemberValue(int pos, int typeNameIndex, int constNameIndex)452         void enumMemberValue(int pos, int typeNameIndex, int constNameIndex)
453             throws Exception {
454         }
455 
456         /**
457          * {@code class_info_index}
458          */
classMemberValue(int pos, int index)459         void classMemberValue(int pos, int index) throws Exception {}
460 
461         /**
462          * {@code annotation_value}
463          */
annotationMemberValue(int pos)464         int annotationMemberValue(int pos) throws Exception {
465             return annotation(pos);
466         }
467 
468         /**
469          * {@code array_value}
470          */
arrayMemberValue(int pos, int num)471         int arrayMemberValue(int pos, int num) throws Exception {
472             for (int i = 0; i < num; ++i) {
473                 pos = memberValue(pos);
474             }
475 
476             return pos;
477         }
478     }
479 
480     static class Renamer extends Walker {
481         ConstPool cpool;
482         Map<String,String> classnames;
483 
484         /**
485          * Constructs a renamer.  It renames some class names
486          * into the new names specified by <code>map</code>.
487          *
488          * @param info      the annotations attribute.
489          * @param cp        the constant pool.
490          * @param map       pairs of replaced and substituted class names.
491          *                  It can be null.
492          */
Renamer(byte[] info, ConstPool cp, Map<String,String> map)493         Renamer(byte[] info, ConstPool cp, Map<String,String> map) {
494             super(info);
495             cpool = cp;
496             classnames = map;
497         }
498 
499         @Override
annotation(int pos, int type, int numPairs)500         int annotation(int pos, int type, int numPairs) throws Exception {
501             renameType(pos - 4, type);
502             return super.annotation(pos, type, numPairs);
503         }
504 
505         @Override
enumMemberValue(int pos, int typeNameIndex, int constNameIndex)506         void enumMemberValue(int pos, int typeNameIndex, int constNameIndex)
507             throws Exception
508         {
509             renameType(pos + 1, typeNameIndex);
510             super.enumMemberValue(pos, typeNameIndex, constNameIndex);
511         }
512 
513         @Override
classMemberValue(int pos, int index)514         void classMemberValue(int pos, int index) throws Exception {
515             renameType(pos + 1, index);
516             super.classMemberValue(pos, index);
517         }
518 
renameType(int pos, int index)519         private void renameType(int pos, int index) {
520             String name = cpool.getUtf8Info(index);
521             String newName = Descriptor.rename(name, classnames);
522             if (!name.equals(newName)) {
523                 int index2 = cpool.addUtf8Info(newName);
524                 ByteArray.write16bit(index2, info, pos);
525             }
526         }
527     }
528 
529     static class Copier extends Walker {
530         ByteArrayOutputStream output;
531         AnnotationsWriter writer;
532         ConstPool srcPool, destPool;
533         Map<String,String> classnames;
534 
535         /**
536          * Constructs a copier.  This copier renames some class names
537          * into the new names specified by <code>map</code> when it copies
538          * an annotation attribute.
539          *
540          * @param info      the source attribute.
541          * @param src       the constant pool of the source class.
542          * @param dest      the constant pool of the destination class.
543          * @param map       pairs of replaced and substituted class names.
544          *                  It can be null.
545          */
Copier(byte[] info, ConstPool src, ConstPool dest, Map<String,String> map)546         Copier(byte[] info, ConstPool src, ConstPool dest, Map<String,String> map) {
547             this(info, src, dest, map, true);
548         }
549 
Copier(byte[] info, ConstPool src, ConstPool dest, Map<String,String> map, boolean makeWriter)550         Copier(byte[] info, ConstPool src, ConstPool dest, Map<String,String> map, boolean makeWriter) {
551             super(info);
552             output = new ByteArrayOutputStream();
553             if (makeWriter)
554                 writer = new AnnotationsWriter(output, dest);
555 
556             srcPool = src;
557             destPool = dest;
558             classnames = map;
559         }
560 
close()561         byte[] close() throws IOException {
562             writer.close();
563             return output.toByteArray();
564         }
565 
566         @Override
parameters(int numParam, int pos)567         void parameters(int numParam, int pos) throws Exception {
568             writer.numParameters(numParam);
569             super.parameters(numParam, pos);
570         }
571 
572         @Override
annotationArray(int pos, int num)573         int annotationArray(int pos, int num) throws Exception {
574             writer.numAnnotations(num);
575             return super.annotationArray(pos, num);
576         }
577 
578         @Override
annotation(int pos, int type, int numPairs)579         int annotation(int pos, int type, int numPairs) throws Exception {
580             writer.annotation(copyType(type), numPairs);
581             return super.annotation(pos, type, numPairs);
582         }
583 
584         @Override
memberValuePair(int pos, int nameIndex)585         int memberValuePair(int pos, int nameIndex) throws Exception {
586             writer.memberValuePair(copy(nameIndex));
587             return super.memberValuePair(pos, nameIndex);
588         }
589 
590         @Override
constValueMember(int tag, int index)591         void constValueMember(int tag, int index) throws Exception {
592             writer.constValueIndex(tag, copy(index));
593             super.constValueMember(tag, index);
594         }
595 
596         @Override
enumMemberValue(int pos, int typeNameIndex, int constNameIndex)597         void enumMemberValue(int pos, int typeNameIndex, int constNameIndex)
598             throws Exception
599         {
600             writer.enumConstValue(copyType(typeNameIndex), copy(constNameIndex));
601             super.enumMemberValue(pos, typeNameIndex, constNameIndex);
602         }
603 
604         @Override
classMemberValue(int pos, int index)605         void classMemberValue(int pos, int index) throws Exception {
606             writer.classInfoIndex(copyType(index));
607             super.classMemberValue(pos, index);
608         }
609 
610         @Override
annotationMemberValue(int pos)611         int annotationMemberValue(int pos) throws Exception {
612             writer.annotationValue();
613             return super.annotationMemberValue(pos);
614         }
615 
616         @Override
arrayMemberValue(int pos, int num)617         int arrayMemberValue(int pos, int num) throws Exception {
618             writer.arrayValue(num);
619             return super.arrayMemberValue(pos, num);
620         }
621 
622         /**
623          * Copies a constant pool entry into the destination constant pool
624          * and returns the index of the copied entry.
625          *
626          * @param srcIndex      the index of the copied entry into the source
627          *                      constant pool.
628          * @return the index of the copied item into the destination
629          *         constant pool.
630          */
copy(int srcIndex)631         int copy(int srcIndex) {
632             return srcPool.copy(srcIndex, destPool, classnames);
633         }
634 
635         /**
636          * Copies a constant pool entry into the destination constant pool
637          * and returns the index of the copied entry.  That entry must be
638          * a Utf8Info representing a class name in the L<class name>; form.
639          *
640          * @param srcIndex  the index of the copied entry into the source
641          *                  constant pool.
642          * @return          the index of the copied item into the destination
643          *                  constant pool.
644          */
copyType(int srcIndex)645         int copyType(int srcIndex) {
646             String name = srcPool.getUtf8Info(srcIndex);
647             String newName = Descriptor.rename(name, classnames);
648             return destPool.addUtf8Info(newName);
649         }
650     }
651 
652     static class Parser extends Walker {
653         ConstPool pool;
654         Annotation[][] allParams;   // all parameters
655         Annotation[] allAnno;       // all annotations
656         Annotation currentAnno;     // current annotation
657         MemberValue currentMember;  // current member
658 
659         /**
660          * Constructs a parser.  This parser constructs a parse tree of
661          * the annotations.
662          *
663          * @param info      the attribute.
664          * @param src       the constant pool.
665          */
Parser(byte[] info, ConstPool cp)666         Parser(byte[] info, ConstPool cp) {
667             super(info);
668             pool = cp;
669         }
670 
parseParameters()671         Annotation[][] parseParameters() throws Exception {
672             parameters();
673             return allParams;
674         }
675 
parseAnnotations()676         Annotation[] parseAnnotations() throws Exception {
677             annotationArray();
678             return allAnno;
679         }
680 
parseMemberValue()681         MemberValue parseMemberValue() throws Exception {
682             memberValue(0);
683             return currentMember;
684         }
685 
686         @Override
parameters(int numParam, int pos)687         void parameters(int numParam, int pos) throws Exception {
688             Annotation[][] params = new Annotation[numParam][];
689             for (int i = 0; i < numParam; ++i) {
690                 pos = annotationArray(pos);
691                 params[i] = allAnno;
692             }
693 
694             allParams = params;
695         }
696 
697         @Override
annotationArray(int pos, int num)698         int annotationArray(int pos, int num) throws Exception {
699             Annotation[] array = new Annotation[num];
700             for (int i = 0; i < num; ++i) {
701                 pos = annotation(pos);
702                 array[i] = currentAnno;
703             }
704 
705             allAnno = array;
706             return pos;
707         }
708 
709         @Override
annotation(int pos, int type, int numPairs)710         int annotation(int pos, int type, int numPairs) throws Exception {
711             currentAnno = new Annotation(type, pool);
712             return super.annotation(pos, type, numPairs);
713         }
714 
715         @Override
memberValuePair(int pos, int nameIndex)716         int memberValuePair(int pos, int nameIndex) throws Exception {
717             pos = super.memberValuePair(pos, nameIndex);
718             currentAnno.addMemberValue(nameIndex, currentMember);
719             return pos;
720         }
721 
722         @Override
constValueMember(int tag, int index)723         void constValueMember(int tag, int index) throws Exception {
724             MemberValue m;
725             ConstPool cp = pool;
726             switch (tag) {
727             case 'B' :
728                 m = new ByteMemberValue(index, cp);
729                 break;
730             case 'C' :
731                 m = new CharMemberValue(index, cp);
732                 break;
733             case 'D' :
734                 m = new DoubleMemberValue(index, cp);
735                 break;
736             case 'F' :
737                 m = new FloatMemberValue(index, cp);
738                 break;
739             case 'I' :
740                 m = new IntegerMemberValue(index, cp);
741                 break;
742             case 'J' :
743                 m = new LongMemberValue(index, cp);
744                 break;
745             case 'S' :
746                 m = new ShortMemberValue(index, cp);
747                 break;
748             case 'Z' :
749                 m = new BooleanMemberValue(index, cp);
750                 break;
751             case 's' :
752                 m = new StringMemberValue(index, cp);
753                 break;
754             default :
755                 throw new RuntimeException("unknown tag:" + tag);
756             }
757 
758             currentMember = m;
759             super.constValueMember(tag, index);
760         }
761 
762         @Override
enumMemberValue(int pos, int typeNameIndex, int constNameIndex)763         void enumMemberValue(int pos, int typeNameIndex, int constNameIndex)
764             throws Exception
765         {
766             currentMember = new EnumMemberValue(typeNameIndex,
767                                               constNameIndex, pool);
768             super.enumMemberValue(pos, typeNameIndex, constNameIndex);
769         }
770 
771         @Override
classMemberValue(int pos, int index)772         void classMemberValue(int pos, int index) throws Exception {
773             currentMember = new ClassMemberValue(index, pool);
774             super.classMemberValue(pos, index);
775         }
776 
777         @Override
annotationMemberValue(int pos)778         int annotationMemberValue(int pos) throws Exception {
779             Annotation anno = currentAnno;
780             pos = super.annotationMemberValue(pos);
781             currentMember = new AnnotationMemberValue(currentAnno, pool);
782             currentAnno = anno;
783             return pos;
784         }
785 
786         @Override
arrayMemberValue(int pos, int num)787         int arrayMemberValue(int pos, int num) throws Exception {
788             ArrayMemberValue amv = new ArrayMemberValue(pool);
789             MemberValue[] elements = new MemberValue[num];
790             for (int i = 0; i < num; ++i) {
791                 pos = memberValue(pos);
792                 elements[i] = currentMember;
793             }
794 
795             amv.setValue(elements);
796             currentMember = amv;
797             return pos;
798         }
799     }
800 }
801