AnnotationWriter.java revision 674060f01e9090cd21b3c5656cc3204912ad17a6
1/***
2 * ASM: a very small and fast Java bytecode manipulation framework
3 * Copyright (c) 2000-2007 INRIA, France Telecom
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the copyright holders nor the names of its
15 *    contributors may be used to endorse or promote products derived from
16 *    this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
28 * THE POSSIBILITY OF SUCH DAMAGE.
29 */
30package org.mockito.asm;
31
32/**
33 * An {@link AnnotationVisitor} that generates annotations in bytecode form.
34 *
35 * @author Eric Bruneton
36 * @author Eugene Kuleshov
37 */
38final class AnnotationWriter implements AnnotationVisitor {
39
40    /**
41     * The class writer to which this annotation must be added.
42     */
43    private final ClassWriter cw;
44
45    /**
46     * The number of values in this annotation.
47     */
48    private int size;
49
50    /**
51     * <tt>true<tt> if values are named, <tt>false</tt> otherwise. Annotation
52     * writers used for annotation default and annotation arrays use unnamed
53     * values.
54     */
55    private final boolean named;
56
57    /**
58     * The annotation values in bytecode form. This byte vector only contains
59     * the values themselves, i.e. the number of values must be stored as a
60     * unsigned short just before these bytes.
61     */
62    private final ByteVector bv;
63
64    /**
65     * The byte vector to be used to store the number of values of this
66     * annotation. See {@link #bv}.
67     */
68    private final ByteVector parent;
69
70    /**
71     * Where the number of values of this annotation must be stored in
72     * {@link #parent}.
73     */
74    private final int offset;
75
76    /**
77     * Next annotation writer. This field is used to store annotation lists.
78     */
79    AnnotationWriter next;
80
81    /**
82     * Previous annotation writer. This field is used to store annotation lists.
83     */
84    AnnotationWriter prev;
85
86    // ------------------------------------------------------------------------
87    // Constructor
88    // ------------------------------------------------------------------------
89
90    /**
91     * Constructs a new {@link AnnotationWriter}.
92     *
93     * @param cw the class writer to which this annotation must be added.
94     * @param named <tt>true<tt> if values are named, <tt>false</tt> otherwise.
95     * @param bv where the annotation values must be stored.
96     * @param parent where the number of annotation values must be stored.
97     * @param offset where in <tt>parent</tt> the number of annotation values must
98     *      be stored.
99     */
100    AnnotationWriter(
101        final ClassWriter cw,
102        final boolean named,
103        final ByteVector bv,
104        final ByteVector parent,
105        final int offset)
106    {
107        this.cw = cw;
108        this.named = named;
109        this.bv = bv;
110        this.parent = parent;
111        this.offset = offset;
112    }
113
114    // ------------------------------------------------------------------------
115    // Implementation of the AnnotationVisitor interface
116    // ------------------------------------------------------------------------
117
118    public void visit(final String name, final Object value) {
119        ++size;
120        if (named) {
121            bv.putShort(cw.newUTF8(name));
122        }
123        if (value instanceof String) {
124            bv.put12('s', cw.newUTF8((String) value));
125        } else if (value instanceof Byte) {
126            bv.put12('B', cw.newInteger(((Byte) value).byteValue()).index);
127        } else if (value instanceof Boolean) {
128            int v = ((Boolean) value).booleanValue() ? 1 : 0;
129            bv.put12('Z', cw.newInteger(v).index);
130        } else if (value instanceof Character) {
131            bv.put12('C', cw.newInteger(((Character) value).charValue()).index);
132        } else if (value instanceof Short) {
133            bv.put12('S', cw.newInteger(((Short) value).shortValue()).index);
134        } else if (value instanceof Type) {
135            bv.put12('c', cw.newUTF8(((Type) value).getDescriptor()));
136        } else if (value instanceof byte[]) {
137            byte[] v = (byte[]) value;
138            bv.put12('[', v.length);
139            for (int i = 0; i < v.length; i++) {
140                bv.put12('B', cw.newInteger(v[i]).index);
141            }
142        } else if (value instanceof boolean[]) {
143            boolean[] v = (boolean[]) value;
144            bv.put12('[', v.length);
145            for (int i = 0; i < v.length; i++) {
146                bv.put12('Z', cw.newInteger(v[i] ? 1 : 0).index);
147            }
148        } else if (value instanceof short[]) {
149            short[] v = (short[]) value;
150            bv.put12('[', v.length);
151            for (int i = 0; i < v.length; i++) {
152                bv.put12('S', cw.newInteger(v[i]).index);
153            }
154        } else if (value instanceof char[]) {
155            char[] v = (char[]) value;
156            bv.put12('[', v.length);
157            for (int i = 0; i < v.length; i++) {
158                bv.put12('C', cw.newInteger(v[i]).index);
159            }
160        } else if (value instanceof int[]) {
161            int[] v = (int[]) value;
162            bv.put12('[', v.length);
163            for (int i = 0; i < v.length; i++) {
164                bv.put12('I', cw.newInteger(v[i]).index);
165            }
166        } else if (value instanceof long[]) {
167            long[] v = (long[]) value;
168            bv.put12('[', v.length);
169            for (int i = 0; i < v.length; i++) {
170                bv.put12('J', cw.newLong(v[i]).index);
171            }
172        } else if (value instanceof float[]) {
173            float[] v = (float[]) value;
174            bv.put12('[', v.length);
175            for (int i = 0; i < v.length; i++) {
176                bv.put12('F', cw.newFloat(v[i]).index);
177            }
178        } else if (value instanceof double[]) {
179            double[] v = (double[]) value;
180            bv.put12('[', v.length);
181            for (int i = 0; i < v.length; i++) {
182                bv.put12('D', cw.newDouble(v[i]).index);
183            }
184        } else {
185            Item i = cw.newConstItem(value);
186            bv.put12(".s.IFJDCS".charAt(i.type), i.index);
187        }
188    }
189
190    public void visitEnum(
191        final String name,
192        final String desc,
193        final String value)
194    {
195        ++size;
196        if (named) {
197            bv.putShort(cw.newUTF8(name));
198        }
199        bv.put12('e', cw.newUTF8(desc)).putShort(cw.newUTF8(value));
200    }
201
202    public AnnotationVisitor visitAnnotation(
203        final String name,
204        final String desc)
205    {
206        ++size;
207        if (named) {
208            bv.putShort(cw.newUTF8(name));
209        }
210        // write tag and type, and reserve space for values count
211        bv.put12('@', cw.newUTF8(desc)).putShort(0);
212        return new AnnotationWriter(cw, true, bv, bv, bv.length - 2);
213    }
214
215    public AnnotationVisitor visitArray(final String name) {
216        ++size;
217        if (named) {
218            bv.putShort(cw.newUTF8(name));
219        }
220        // write tag, and reserve space for array size
221        bv.put12('[', 0);
222        return new AnnotationWriter(cw, false, bv, bv, bv.length - 2);
223    }
224
225    public void visitEnd() {
226        if (parent != null) {
227            byte[] data = parent.data;
228            data[offset] = (byte) (size >>> 8);
229            data[offset + 1] = (byte) size;
230        }
231    }
232
233    // ------------------------------------------------------------------------
234    // Utility methods
235    // ------------------------------------------------------------------------
236
237    /**
238     * Returns the size of this annotation writer list.
239     *
240     * @return the size of this annotation writer list.
241     */
242    int getSize() {
243        int size = 0;
244        AnnotationWriter aw = this;
245        while (aw != null) {
246            size += aw.bv.length;
247            aw = aw.next;
248        }
249        return size;
250    }
251
252    /**
253     * Puts the annotations of this annotation writer list into the given byte
254     * vector.
255     *
256     * @param out where the annotations must be put.
257     */
258    void put(final ByteVector out) {
259        int n = 0;
260        int size = 2;
261        AnnotationWriter aw = this;
262        AnnotationWriter last = null;
263        while (aw != null) {
264            ++n;
265            size += aw.bv.length;
266            aw.visitEnd(); // in case user forgot to call visitEnd
267            aw.prev = last;
268            last = aw;
269            aw = aw.next;
270        }
271        out.putInt(size);
272        out.putShort(n);
273        aw = last;
274        while (aw != null) {
275            out.putByteArray(aw.bv.data, 0, aw.bv.length);
276            aw = aw.prev;
277        }
278    }
279
280    /**
281     * Puts the given annotation lists into the given byte vector.
282     *
283     * @param panns an array of annotation writer lists.
284     * @param off index of the first annotation to be written.
285     * @param out where the annotations must be put.
286     */
287    static void put(
288        final AnnotationWriter[] panns,
289        final int off,
290        final ByteVector out)
291    {
292        int size = 1 + 2 * (panns.length - off);
293        for (int i = off; i < panns.length; ++i) {
294            size += panns[i] == null ? 0 : panns[i].getSize();
295        }
296        out.putInt(size).putByte(panns.length - off);
297        for (int i = off; i < panns.length; ++i) {
298            AnnotationWriter aw = panns[i];
299            AnnotationWriter last = null;
300            int n = 0;
301            while (aw != null) {
302                ++n;
303                aw.visitEnd(); // in case user forgot to call visitEnd
304                aw.prev = last;
305                last = aw;
306                aw = aw.next;
307            }
308            out.putShort(n);
309            aw = last;
310            while (aw != null) {
311                out.putByteArray(aw.bv.data, 0, aw.bv.length);
312                aw = aw.prev;
313            }
314        }
315    }
316}
317