1/*
2 * Javassist, a Java-bytecode translator toolkit.
3 * Copyright (C) 1999-2007 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
16package javassist.bytecode.annotation;
17
18import java.io.*;
19
20import javassist.bytecode.ByteArray;
21import javassist.bytecode.ConstPool;
22
23/**
24 * A convenience class for constructing a
25 * <code>..Annotations_attribute</code>.
26 * See the source code of the <code>AnnotationsAttribute.Copier</code> class.
27 *
28 * <p>The following code snippet is an example of use of this class:
29 *
30 * <ul><pre>
31 * ConstPool pool = ...;
32 * output = new ByteArrayOutputStream();
33 * writer = new AnnotationsWriter(output, pool);
34 *
35 * writer.numAnnotations(1);
36 * writer.annotation("Author", 2);
37 * writer.memberValuePair("name");
38 * writer.constValueIndex("chiba");
39 * writer.memberValuePair("address");
40 * writer.constValueIndex("tokyo");
41 *
42 * writer.close();
43 * byte[] attribute_info = output.toByteArray();
44 * AnnotationsAttribute anno
45 *     = new AnnotationsAttribute(pool, AnnotationsAttribute.visibleTag,
46 *                                attribute_info);
47 * </pre></ul>
48 *
49 * <p>The code snippet above generates the annotation attribute
50 * corresponding to this annotation:
51 *
52 * <ul><pre>
53 * &nbsp;@Author(name = "chiba", address = "tokyo")
54 * </pre></ul>
55 *
56 * @see javassist.bytecode.AnnotationsAttribute
57 * @see javassist.bytecode.ParameterAnnotationsAttribute
58 */
59public class AnnotationsWriter {
60    private OutputStream output;
61    private ConstPool pool;
62
63    /**
64     * Constructs with the given output stream.
65     *
66     * @param os    the output stream.
67     * @param cp    the constant pool.
68     */
69    public AnnotationsWriter(OutputStream os, ConstPool cp) {
70        output = os;
71        pool = cp;
72    }
73
74    /**
75     * Obtains the constant pool given to the constructor.
76     */
77    public ConstPool getConstPool() {
78        return pool;
79    }
80
81    /**
82     * Closes the output stream.
83     *
84     */
85    public void close() throws IOException {
86        output.close();
87    }
88
89    /**
90     * Writes <code>num_parameters</code> in
91     * <code>Runtime(In)VisibleParameterAnnotations_attribute</code>.
92     * This method must be followed by <code>num</code> calls to
93     * <code>numAnnotations()</code>.
94     */
95    public void numParameters(int num) throws IOException {
96        output.write(num);
97    }
98
99    /**
100     * Writes <code>num_annotations</code> in
101     * <code>Runtime(In)VisibleAnnotations_attribute</code>.
102     * This method must be followed by <code>num</code> calls to
103     * <code>annotation()</code>.
104     */
105    public void numAnnotations(int num) throws IOException {
106        write16bit(num);
107    }
108
109    /**
110     * Writes <code>annotation</code>.
111     * This method must be followed by <code>numMemberValuePairs</code>
112     * calls to <code>memberValuePair()</code>.
113     *
114     * @param type                  the annotation interface name.
115     * @param numMemberValuePairs   <code>num_member_value_pairs</code>
116     *                              in <code>annotation</code>.
117     */
118    public void annotation(String type, int numMemberValuePairs)
119        throws IOException
120    {
121        annotation(pool.addUtf8Info(type), numMemberValuePairs);
122    }
123
124    /**
125     * Writes <code>annotation</code>.
126     * This method must be followed by <code>numMemberValuePairs</code>
127     * calls to <code>memberValuePair()</code>.
128     *
129     * @param typeIndex  <code>type_index</code> in <code>annotation</code>.
130     * @param numMemberValuePairs   <code>num_member_value_pairs</code>
131     *                              in <code>annotation</code>.
132     */
133    public void annotation(int typeIndex, int numMemberValuePairs)
134        throws IOException
135    {
136        write16bit(typeIndex);
137        write16bit(numMemberValuePairs);
138    }
139
140    /**
141     * Writes an element of a <code>member_value_pairs</code> array
142     * in <code>annotation</code>.
143     * This method must be followed by a
144     * call to <code>constValueIndex()</code>, <code>enumConstValue()</code>,
145     * etc.
146     *
147     * @param memberName        the name of the annotation type member.
148     */
149    public void memberValuePair(String memberName) throws IOException {
150        memberValuePair(pool.addUtf8Info(memberName));
151    }
152
153    /**
154     * Writes an element of a <code>member_value_pairs</code> array
155     * in <code>annotation</code>.
156     * This method must be followed by a
157     * call to <code>constValueIndex()</code>, <code>enumConstValue()</code>,
158     * etc.
159     *
160     * @param memberNameIndex   <code>member_name_index</code>
161     *                          in <code>member_value_pairs</code> array.
162     */
163    public void memberValuePair(int memberNameIndex) throws IOException {
164        write16bit(memberNameIndex);
165    }
166
167    /**
168     * Writes <code>tag</code> and <code>const_value_index</code>
169     * in <code>member_value</code>.
170     *
171     * @param value     the constant value.
172     */
173    public void constValueIndex(boolean value) throws IOException {
174        constValueIndex('Z', pool.addIntegerInfo(value ? 1 : 0));
175    }
176
177    /**
178     * Writes <code>tag</code> and <code>const_value_index</code>
179     * in <code>member_value</code>.
180     *
181     * @param value     the constant value.
182     */
183    public void constValueIndex(byte value) throws IOException {
184        constValueIndex('B', pool.addIntegerInfo(value));
185    }
186
187    /**
188     * Writes <code>tag</code> and <code>const_value_index</code>
189     * in <code>member_value</code>.
190     *
191     * @param value     the constant value.
192     */
193    public void constValueIndex(char value) throws IOException {
194        constValueIndex('C', pool.addIntegerInfo(value));
195    }
196
197    /**
198     * Writes <code>tag</code> and <code>const_value_index</code>
199     * in <code>member_value</code>.
200     *
201     * @param value     the constant value.
202     */
203    public void constValueIndex(short value) throws IOException {
204        constValueIndex('S', pool.addIntegerInfo(value));
205    }
206
207    /**
208     * Writes <code>tag</code> and <code>const_value_index</code>
209     * in <code>member_value</code>.
210     *
211     * @param value     the constant value.
212     */
213    public void constValueIndex(int value) throws IOException {
214        constValueIndex('I', pool.addIntegerInfo(value));
215    }
216
217    /**
218     * Writes <code>tag</code> and <code>const_value_index</code>
219     * in <code>member_value</code>.
220     *
221     * @param value     the constant value.
222     */
223    public void constValueIndex(long value) throws IOException {
224        constValueIndex('J', pool.addLongInfo(value));
225    }
226
227    /**
228     * Writes <code>tag</code> and <code>const_value_index</code>
229     * in <code>member_value</code>.
230     *
231     * @param value     the constant value.
232     */
233    public void constValueIndex(float value) throws IOException {
234        constValueIndex('F', pool.addFloatInfo(value));
235    }
236
237    /**
238     * Writes <code>tag</code> and <code>const_value_index</code>
239     * in <code>member_value</code>.
240     *
241     * @param value     the constant value.
242     */
243    public void constValueIndex(double value) throws IOException {
244        constValueIndex('D', pool.addDoubleInfo(value));
245    }
246
247    /**
248     * Writes <code>tag</code> and <code>const_value_index</code>
249     * in <code>member_value</code>.
250     *
251     * @param value     the constant value.
252     */
253    public void constValueIndex(String value) throws IOException {
254        constValueIndex('s', pool.addUtf8Info(value));
255    }
256
257    /**
258     * Writes <code>tag</code> and <code>const_value_index</code>
259     * in <code>member_value</code>.
260     *
261     * @param tag       <code>tag</code> in <code>member_value</code>.
262     * @param index     <code>const_value_index</code>
263     *                              in <code>member_value</code>.
264     */
265    public void constValueIndex(int tag, int index)
266        throws IOException
267    {
268        output.write(tag);
269        write16bit(index);
270    }
271
272    /**
273     * Writes <code>tag</code> and <code>enum_const_value</code>
274     * in <code>member_value</code>.
275     *
276     * @param typeName      the type name of the enum constant.
277     * @param constName     the simple name of the enum constant.
278     */
279    public void enumConstValue(String typeName, String constName)
280        throws IOException
281    {
282        enumConstValue(pool.addUtf8Info(typeName),
283                       pool.addUtf8Info(constName));
284    }
285
286    /**
287     * Writes <code>tag</code> and <code>enum_const_value</code>
288     * in <code>member_value</code>.
289     *
290     * @param typeNameIndex       <code>type_name_index</code>
291     *                              in <code>member_value</code>.
292     * @param constNameIndex     <code>const_name_index</code>
293     *                              in <code>member_value</code>.
294     */
295    public void enumConstValue(int typeNameIndex, int constNameIndex)
296        throws IOException
297    {
298        output.write('e');
299        write16bit(typeNameIndex);
300        write16bit(constNameIndex);
301    }
302
303    /**
304     * Writes <code>tag</code> and <code>class_info_index</code>
305     * in <code>member_value</code>.
306     *
307     * @param name      the class name.
308     */
309    public void classInfoIndex(String name) throws IOException {
310        classInfoIndex(pool.addUtf8Info(name));
311    }
312
313    /**
314     * Writes <code>tag</code> and <code>class_info_index</code>
315     * in <code>member_value</code>.
316     *
317     * @param index       <code>class_info_index</code>
318     */
319    public void classInfoIndex(int index) throws IOException {
320        output.write('c');
321        write16bit(index);
322    }
323
324    /**
325     * Writes <code>tag</code> and <code>annotation_value</code>
326     * in <code>member_value</code>.
327     * This method must be followed by a call to <code>annotation()</code>.
328     */
329    public void annotationValue() throws IOException {
330        output.write('@');
331    }
332
333    /**
334     * Writes <code>tag</code> and <code>array_value</code>
335     * in <code>member_value</code>.
336     * This method must be followed by <code>numValues</code> calls
337     * to <code>constValueIndex()</code>, <code>enumConstValue()</code>,
338     * etc.
339     *
340     * @param numValues     <code>num_values</code>
341     *                      in <code>array_value</code>.
342     */
343    public void arrayValue(int numValues) throws IOException {
344        output.write('[');
345        write16bit(numValues);
346    }
347
348    private void write16bit(int value) throws IOException {
349        byte[] buf = new byte[2];
350        ByteArray.write16bit(value, buf, 0);
351        output.write(buf);
352    }
353}
354