KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javassist > bytecode > AnnotationsAttribute


1 /*
2  * Javassist, a Java-bytecode translator toolkit.
3  * Copyright (C) 1999-2005 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  *
10  * Software distributed under the License is distributed on an "AS IS" basis,
11  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12  * for the specific language governing rights and limitations under the
13  * License.
14  */

15
16 package javassist.bytecode;
17
18 import java.util.Map JavaDoc;
19 import java.io.IOException JavaDoc;
20 import java.io.DataInputStream JavaDoc;
21 import java.io.ByteArrayOutputStream JavaDoc;
22 import javassist.bytecode.annotation.*;
23
24 /**
25  * A class representing
26  * <code>RuntimeVisibleAnnotations_attribute</code> and
27  * <code>RuntimeInvisibleAnnotations_attribute</code>.
28  *
29  * <p>To obtain an AnnotationAttribute object, invoke
30  * <code>getAttribute(AnnotationsAttribute.invisibleTag)</code>
31  * in <code>ClassFile</code>, <code>MethodInfo</code>,
32  * or <code>FieldInfo</code>. The obtained attribute is a
33  * runtime invisible annotations attribute.
34  * If the parameter is
35  * <code>AnnotationAttribute.visibleTag</code>, then the obtained
36  * attribute is a runtime visible one.
37  *
38  * <p>If you want to record a new AnnotationAttribute object, execute the
39  * following snippet:
40  *
41  * <ul><pre>
42  * ClassFile cf = ... ;
43  * ConstPool cp = cf.getConstPool();
44  * AnnotationsAttribute attr
45  * = new AnnotationsAttribute(cp, AnnotationsAttribute.invisibleTag);
46  * Annotation a = new Annotation("Author", cp);
47  * a.addMemberValue("name", new StringMemberValue("Chiba", cp));
48  * attr.setAnnotation(a);
49  * cf.addAttribute(attr);
50  * </pre></ul>
51  */

52 public class AnnotationsAttribute extends AttributeInfo {
53     /**
54      * The name of the <code>RuntimeVisibleAnnotations</code> attribute.
55      */

56     public static final String JavaDoc visibleTag = "RuntimeVisibleAnnotations";
57
58     /**
59      * The name of the <code>RuntimeInvisibleAnnotations</code> attribute.
60      */

61     public static final String JavaDoc invisibleTag = "RuntimeInvisibleAnnotations";
62
63     /**
64      * Constructs a <code>Runtime(In)VisisbleAnnotations_attribute</code>.
65      *
66      * @param cp constant pool
67      * @param attrname attribute name (<code>visibleTag</code> or
68      * <code>invisibleTag</code>).
69      * @param info the contents of this attribute. It does not
70      * include <code>attribute_name_index</code> or
71      * <code>attribute_length</code>.
72      */

73     public AnnotationsAttribute(ConstPool cp, String JavaDoc attrname, byte[] info) {
74         super(cp, attrname, info);
75     }
76
77     /**
78      * Constructs an empty
79      * <code>Runtime(In)VisisbleAnnotations_attribute</code>.
80      * A new annotation can be later added to the created attribute
81      * by <code>setAnnotations()</code>.
82      *
83      * @param cp constant pool
84      * @param attrname attribute name (<code>visibleTag</code> or
85      * <code>invisibleTag</code>).
86      * @see #setAnnotations(Annotation[])
87      */

88     public AnnotationsAttribute(ConstPool cp, String JavaDoc attrname) {
89         this(cp, attrname, new byte[] { 0, 0 });
90     }
91
92     /**
93      * @param n the attribute name.
94      */

95     AnnotationsAttribute(ConstPool cp, int n, DataInputStream JavaDoc in)
96         throws IOException JavaDoc
97     {
98         super(cp, n, in);
99     }
100
101     /**
102      * Returns <code>num_annotations</code>.
103      */

104     public int numAnnotations() {
105         return ByteArray.readU16bit(info, 0);
106     }
107
108     /**
109      * Copies this attribute and returns a new copy.
110      */

111     public AttributeInfo copy(ConstPool newCp, Map JavaDoc classnames) {
112         Copier copier = new Copier(info, constPool, newCp, classnames);
113         try {
114             copier.annotationArray();
115             return new AnnotationsAttribute(newCp, getName(), copier.close());
116         }
117         catch (Exception JavaDoc e) {
118             throw new RuntimeException JavaDoc(e.toString());
119         }
120     }
121
122     /**
123      * Parses the annotations and returns a data structure representing
124      * the annotation with the specified type. See also
125      * <code>getAnnotations()</code> as to the returned data structure.
126      *
127      * @param type the annotation type.
128      * @see #getAnnotations()
129      */

130     public Annotation getAnnotation(String JavaDoc type) {
131         Annotation[] annotations = getAnnotations();
132         for (int i = 0; i < annotations.length; i++) {
133             if (annotations[i].getTypeName().equals(type))
134                 return annotations[i];
135         }
136
137         return null;
138     }
139
140     /**
141      * Adds an annotation. If there is an annotation with the same type,
142      * it is removed before the new annotation is added.
143      *
144      * @param annotation the added annotation.
145      */

146     public void addAnnotation(Annotation annotation) {
147         String JavaDoc type = annotation.getTypeName();
148         Annotation[] annotations = getAnnotations();
149         for (int i = 0; i < annotations.length; i++) {
150             if (annotations[i].getTypeName().equals(type)) {
151                 annotations[i] = annotation;
152                 setAnnotations(annotations);
153                 return;
154             }
155         }
156
157         Annotation[] newlist = new Annotation[annotations.length + 1];
158         System.arraycopy(annotations, 0, newlist, 0, annotations.length);
159         newlist[annotations.length] = annotation;
160         setAnnotations(newlist);
161     }
162
163     /**
164      * Parses the annotations and returns a data structure representing
165      * that parsed annotations. Note that changes of the node values of the
166      * returned tree are not reflected on the annotations represented by
167      * this object unless the tree is copied back to this object by
168      * <code>setAnnotations()</code>.
169      *
170      * @see #setAnnotations(Annotation[])
171      */

172     public Annotation[] getAnnotations() {
173         try {
174             return new Parser(info, constPool).parseAnnotations();
175         }
176         catch (Exception JavaDoc e) {
177             throw new RuntimeException JavaDoc(e.toString());
178         }
179     }
180
181     /**
182      * Changes the annotations represented by this object according to
183      * the given array of <code>Annotation</code> objects.
184      *
185      * @param annotations the data structure representing the
186      * new annotations.
187      */

188     public void setAnnotations(Annotation[] annotations) {
189         ByteArrayOutputStream JavaDoc output = new ByteArrayOutputStream JavaDoc();
190         AnnotationsWriter writer = new AnnotationsWriter(output, constPool);
191         try {
192             int n = annotations.length;
193             writer.numAnnotations(n);
194             for (int i = 0; i < n; ++i)
195                 annotations[i].write(writer);
196
197             writer.close();
198         }
199         catch (IOException JavaDoc e) {
200             throw new RuntimeException JavaDoc(e); // should never reach here.
201
}
202
203         set(output.toByteArray());
204     }
205
206     /**
207      * Changes the annotations. A call to this method is equivalent to:
208      * <ul><pre>setAnnotations(new Annotation[] { annotation })</pre></ul>
209      *
210      * @param annotation the data structure representing
211      * the new annotation.
212      */

213     public void setAnnotation(Annotation annotation) {
214         setAnnotations(new Annotation[] { annotation });
215     }
216
217     /**
218      * Returns a string representation of this object.
219      */

220     public String JavaDoc toString() {
221         Annotation[] a = getAnnotations();
222         StringBuffer JavaDoc sbuf = new StringBuffer JavaDoc();
223         int i = 0;
224         while (i < a.length) {
225             sbuf.append(a[i++].toString());
226             if (i != a.length)
227                 sbuf.append(", ");
228         }
229
230         return sbuf.toString();
231     }
232
233     static class Walker {
234         byte[] info;
235
236         Walker(byte[] attrInfo) {
237             info = attrInfo;
238         }
239
240         final void parameters() throws Exception JavaDoc {
241             int numParam = info[0] & 0xff;
242             parameters(numParam, 1);
243         }
244
245         void parameters(int numParam, int pos) throws Exception JavaDoc {
246             for (int i = 0; i < numParam; ++i)
247                 pos = annotationArray(pos);
248         }
249
250         final void annotationArray() throws Exception JavaDoc {
251             annotationArray(0);
252         }
253
254         final int annotationArray(int pos) throws Exception JavaDoc {
255             int num = ByteArray.readU16bit(info, pos);
256             return annotationArray(pos + 2, num);
257         }
258
259         int annotationArray(int pos, int num) throws Exception JavaDoc {
260             for (int i = 0; i < num; ++i)
261                 pos = annotation(pos);
262
263             return pos;
264         }
265
266         final int annotation(int pos) throws Exception JavaDoc {
267             int type = ByteArray.readU16bit(info, pos);
268             int numPairs = ByteArray.readU16bit(info, pos + 2);
269             return annotation(pos + 4, type, numPairs);
270         }
271
272         int annotation(int pos, int type, int numPairs) throws Exception JavaDoc {
273             for (int j = 0; j < numPairs; ++j)
274                 pos = memberValuePair(pos);
275
276             return pos;
277         }
278
279         final int memberValuePair(int pos) throws Exception JavaDoc {
280             int nameIndex = ByteArray.readU16bit(info, pos);
281             return memberValuePair(pos + 2, nameIndex);
282         }
283
284         int memberValuePair(int pos, int nameIndex) throws Exception JavaDoc {
285             return memberValue(pos);
286         }
287
288         final int memberValue(int pos) throws Exception JavaDoc {
289             int tag = info[pos] & 0xff;
290             if (tag == 'e') {
291                 int typeNameIndex = ByteArray.readU16bit(info, pos + 1);
292                 int constNameIndex = ByteArray.readU16bit(info, pos + 3);
293                 enumMemberValue(typeNameIndex, constNameIndex);
294                 return pos + 5;
295             }
296             else if (tag == 'c') {
297                 int index = ByteArray.readU16bit(info, pos + 1);
298                 classMemberValue(index);
299                 return pos + 3;
300             }
301             else if (tag == '@')
302                 return annotationMemberValue(pos + 1);
303             else if (tag == '[') {
304                 int num = ByteArray.readU16bit(info, pos + 1);
305                 return arrayMemberValue(pos + 3, num);
306             }
307             else { // primitive types or String.
308
int index = ByteArray.readU16bit(info, pos + 1);
309                 constValueMember(tag, index);
310                 return pos + 3;
311             }
312         }
313
314         void constValueMember(int tag, int index) throws Exception JavaDoc {}
315
316         void enumMemberValue(int typeNameIndex, int constNameIndex)
317             throws Exception JavaDoc {
318         }
319
320         void classMemberValue(int index) throws Exception JavaDoc {}
321
322         int annotationMemberValue(int pos) throws Exception JavaDoc {
323             return annotation(pos);
324         }
325
326         int arrayMemberValue(int pos, int num) throws Exception JavaDoc {
327             for (int i = 0; i < num; ++i) {
328                 pos = memberValue(pos);
329             }
330
331             return pos;
332         }
333     }
334
335     static class Copier extends Walker {
336         ByteArrayOutputStream JavaDoc output;
337         AnnotationsWriter writer;
338         ConstPool srcPool, destPool;
339         Map JavaDoc classnames;
340
341         /**
342          * Constructs a copier. This copier renames some class names
343          * into the new names specified by <code>map</code> when it copies
344          * an annotation attribute.
345          *
346          * @param info the source attribute.
347          * @param src the constant pool of the source class.
348          * @param dest the constant pool of the destination class.
349          * @param map pairs of replaced and substituted class names.
350          * It can be null.
351          */

352         Copier(byte[] info, ConstPool src, ConstPool dest, Map JavaDoc map) {
353             super(info);
354             output = new ByteArrayOutputStream JavaDoc();
355             writer = new AnnotationsWriter(output, dest);
356             srcPool = src;
357             destPool = dest;
358             classnames = map;
359         }
360
361         byte[] close() throws IOException JavaDoc {
362             writer.close();
363             return output.toByteArray();
364         }
365
366         void parameters(int numParam, int pos) throws Exception JavaDoc {
367             writer.numParameters(numParam);
368             super.parameters(numParam, pos);
369         }
370
371         int annotationArray(int pos, int num) throws Exception JavaDoc {
372             writer.numAnnotations(num);
373             return super.annotationArray(pos, num);
374         }
375
376         int annotation(int pos, int type, int numPairs) throws Exception JavaDoc {
377             writer.annotation(copy(type), numPairs);
378             return super.annotation(pos, type, numPairs);
379         }
380
381         int memberValuePair(int pos, int nameIndex) throws Exception JavaDoc {
382             writer.memberValuePair(copy(nameIndex));
383             return super.memberValuePair(pos, nameIndex);
384         }
385
386         void constValueMember(int tag, int index) throws Exception JavaDoc {
387             writer.constValueIndex(tag, copy(index));
388             super.constValueMember(tag, index);
389         }
390
391         void enumMemberValue(int typeNameIndex, int constNameIndex)
392             throws Exception JavaDoc
393         {
394             writer.enumConstValue(copy(typeNameIndex), copy(constNameIndex));
395             super.enumMemberValue(typeNameIndex, constNameIndex);
396         }
397
398         void classMemberValue(int index) throws Exception JavaDoc {
399             writer.classInfoIndex(copy(index));
400             super.classMemberValue(index);
401         }
402
403         int annotationMemberValue(int pos) throws Exception JavaDoc {
404             writer.annotationValue();
405             return super.annotationMemberValue(pos);
406         }
407
408         int arrayMemberValue(int pos, int num) throws Exception JavaDoc {
409             writer.arrayValue(num);
410             return super.arrayMemberValue(pos, num);
411         }
412
413         /**
414          * Copies a constant pool entry into the destination constant pool
415          * and returns the index of the copied entry.
416          *
417          * @param srcIndex the index of the copied entry into the source
418          * constant pool.
419          * @return the index of the copied item into the destination
420          * constant pool.
421          */

422         int copy(int srcIndex) {
423             return srcPool.copy(srcIndex, destPool, classnames);
424         }
425     }
426
427     static class Parser extends Walker {
428         ConstPool pool;
429         Annotation[][] allParams; // all parameters
430
Annotation[] allAnno; // all annotations
431
Annotation currentAnno; // current annotation
432
MemberValue memberValue;
433
434         /**
435          * Constructs a parser. This parser constructs a parse tree of
436          * the annotations.
437          *
438          * @param info the attribute.
439          * @param src the constant pool.
440          */

441         Parser(byte[] info, ConstPool cp) {
442             super(info);
443             pool = cp;
444         }
445
446         Annotation[][] parseParameters() throws Exception JavaDoc {
447             parameters();
448             return allParams;
449         }
450
451         Annotation[] parseAnnotations() throws Exception JavaDoc {
452             annotationArray();
453             return allAnno;
454         }
455
456         void parameters(int numParam, int pos) throws Exception JavaDoc {
457             Annotation[][] params = new Annotation[numParam][];
458             for (int i = 0; i < numParam; ++i) {
459                 pos = annotationArray(pos);
460                 params[i] = allAnno;
461             }
462
463             allParams = params;
464         }
465
466         int annotationArray(int pos, int num) throws Exception JavaDoc {
467             Annotation[] array = new Annotation[num];
468             for (int i = 0; i < num; ++i) {
469                 pos = annotation(pos);
470                 array[i] = currentAnno;
471             }
472
473             allAnno = array;
474             return pos;
475         }
476
477         int annotation(int pos, int type, int numPairs) throws Exception JavaDoc {
478             currentAnno = new Annotation(type, pool);
479             return super.annotation(pos, type, numPairs);
480         }
481
482         int memberValuePair(int pos, int nameIndex) throws Exception JavaDoc {
483             pos = super.memberValuePair(pos, nameIndex);
484             currentAnno.addMemberValue(nameIndex, memberValue);
485             return pos;
486         }
487
488         void constValueMember(int tag, int index) throws Exception JavaDoc {
489             MemberValue m;
490             ConstPool cp = pool;
491             switch (tag) {
492             case 'B' :
493                 m = new ByteMemberValue(index, cp);
494                 break;
495             case 'C' :
496                 m = new CharMemberValue(index, cp);
497                 break;
498             case 'D' :
499                 m = new DoubleMemberValue(index, cp);
500                 break;
501             case 'F' :
502                 m = new FloatMemberValue(index, cp);
503                 break;
504             case 'I' :
505                 m = new IntegerMemberValue(index, cp);
506                 break;
507             case 'J' :
508                 m = new LongMemberValue(index, cp);
509                 break;
510             case 'S' :
511                 m = new ShortMemberValue(index, cp);
512                 break;
513             case 'Z' :
514                 m = new BooleanMemberValue(index, cp);
515                 break;
516             case 's' :
517                 m = new StringMemberValue(index, cp);
518                 break;
519             default :
520                 throw new RuntimeException JavaDoc("unknown tag:" + tag);
521             }
522
523             memberValue = m;
524             super.constValueMember(tag, index);
525         }
526
527         void enumMemberValue(int typeNameIndex, int constNameIndex)
528             throws Exception JavaDoc
529         {
530             memberValue = new EnumMemberValue(typeNameIndex,
531                                               constNameIndex, pool);
532             super.enumMemberValue(typeNameIndex, constNameIndex);
533         }
534
535         void classMemberValue(int index) throws Exception JavaDoc {
536             memberValue = new ClassMemberValue(index, pool);
537             super.classMemberValue(index);
538         }
539
540         int annotationMemberValue(int pos) throws Exception JavaDoc {
541             Annotation anno = currentAnno;
542             pos = super.annotationMemberValue(pos);
543             memberValue = new AnnotationMemberValue(currentAnno, pool);
544             currentAnno = anno;
545             return pos;
546         }
547
548         int arrayMemberValue(int pos, int num) throws Exception JavaDoc {
549             ArrayMemberValue amv = new ArrayMemberValue(pool);
550             MemberValue[] elements = new MemberValue[num];
551             for (int i = 0; i < num; ++i) {
552                 pos = memberValue(pos);
553                 elements[i] = memberValue;
554             }
555
556             amv.setValue(elements);
557             memberValue = amv;
558             return pos;
559         }
560     }
561 }
562
Popular Tags