2 * ASM: a very small and fast Java bytecode manipulation framework
3 * Copyright (c) 2000-2005 INRIA, France Telecom
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
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.
30 package org.objectweb.asm;
33 * An {@link AnnotationVisitor} that generates annotations in bytecode form.
35 * @author Eric Bruneton
36 * @author Eugene Kuleshov
38 final class AnnotationWriter implements AnnotationVisitor {
41 * The class writer to which this annotation must be added.
43 private final ClassWriter cw;
46 * The number of values in this annotation.
51 * <tt>true<tt> if values are named, <tt>false</tt> otherwise. Annotation
52 * writers used for annotation default and annotation arrays use unnamed
55 private final boolean named;
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.
62 private final ByteVector bv;
65 * The byte vector to be used to store the number of values of this
66 * annotation. See {@link #bv}.
68 private final ByteVector parent;
71 * Where the number of values of this annotation must be stored in
74 private final int offset;
77 * Next annotation writer. This field is used to store annotation lists.
79 AnnotationWriter next;
82 * Previous annotation writer. This field is used to store annotation lists.
84 AnnotationWriter prev;
86 // ------------------------------------------------------------------------
88 // ------------------------------------------------------------------------
91 * Constructs a new {@link AnnotationWriter}.
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
101 final ClassWriter cw,
104 final ByteVector parent,
110 this.parent = parent;
111 this.offset = offset;
114 // ------------------------------------------------------------------------
115 // Implementation of the AnnotationVisitor interface
116 // ------------------------------------------------------------------------
118 public void visit(final String name, final Object value) {
121 bv.putShort(cw.newUTF8(name));
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);
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);
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);
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);
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);
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);
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);
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);
185 Item i = cw.newConstItem(value);
186 bv.put12(".s.IFJDCS".charAt(i.type), i.index);
190 public void visitEnum(
197 bv.putShort(cw.newUTF8(name));
199 bv.put12('e', cw.newUTF8(desc)).putShort(cw.newUTF8(value));
202 public AnnotationVisitor visitAnnotation(
208 bv.putShort(cw.newUTF8(name));
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);
215 public AnnotationVisitor visitArray(final String name) {
218 bv.putShort(cw.newUTF8(name));
220 // write tag, and reserve space for array size
222 return new AnnotationWriter(cw, false, bv, bv, bv.length - 2);
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;
233 // ------------------------------------------------------------------------
235 // ------------------------------------------------------------------------
238 * Returns the size of this annotation writer list.
240 * @return the size of this annotation writer list.
244 AnnotationWriter aw = this;
246 size += aw.bv.length;
253 * Puts the annotations of this annotation writer list into the given byte
256 * @param out where the annotations must be put.
258 void put(final ByteVector out) {
261 AnnotationWriter aw = this;
262 AnnotationWriter last = null;
265 size += aw.bv.length;
266 aw.visitEnd(); // in case user forgot to call visitEnd
275 out.putByteArray(aw.bv.data, 0, aw.bv.length);
281 * Puts the given annotation lists into the given byte vector.
283 * @param panns an array of annotation writer lists.
284 * @param out where the annotations must be put.
286 static void put(final AnnotationWriter[] panns, final ByteVector out) {
287 int size = 1 + 2 * panns.length;
288 for (int i = 0; i < panns.length; ++i) {
289 size += panns[i] == null ? 0 : panns[i].getSize();
291 out.putInt(size).putByte(panns.length);
292 for (int i = 0; i < panns.length; ++i) {
293 AnnotationWriter aw = panns[i];
294 AnnotationWriter last = null;
298 aw.visitEnd(); // in case user forgot to call visitEnd
306 out.putByteArray(aw.bv.data, 0, aw.bv.length);