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.util;
31
32import org.mockito.asm.AnnotationVisitor;
33import org.mockito.asm.Type;
34
35/**
36 * An {@link AnnotationVisitor} that prints a disassembled view of the
37 * annotations it visits.
38 *
39 * @author Eric Bruneton
40 */
41public class TraceAnnotationVisitor extends TraceAbstractVisitor implements
42        AnnotationVisitor
43{
44
45    /**
46     * The {@link AnnotationVisitor} to which this visitor delegates calls. May
47     * be <tt>null</tt>.
48     */
49    protected AnnotationVisitor av;
50
51    private int valueNumber = 0;
52
53    /**
54     * Constructs a new {@link TraceAnnotationVisitor}.
55     */
56    public TraceAnnotationVisitor() {
57        // ignore
58    }
59
60    // ------------------------------------------------------------------------
61    // Implementation of the AnnotationVisitor interface
62    // ------------------------------------------------------------------------
63
64    public void visit(final String name, final Object value) {
65        buf.setLength(0);
66        appendComa(valueNumber++);
67
68        if (name != null) {
69            buf.append(name).append('=');
70        }
71
72        if (value instanceof String) {
73            visitString((String) value);
74        } else if (value instanceof Type) {
75            visitType((Type) value);
76        } else if (value instanceof Byte) {
77            visitByte(((Byte) value).byteValue());
78        } else if (value instanceof Boolean) {
79            visitBoolean(((Boolean) value).booleanValue());
80        } else if (value instanceof Short) {
81            visitShort(((Short) value).shortValue());
82        } else if (value instanceof Character) {
83            visitChar(((Character) value).charValue());
84        } else if (value instanceof Integer) {
85            visitInt(((Integer) value).intValue());
86        } else if (value instanceof Float) {
87            visitFloat(((Float) value).floatValue());
88        } else if (value instanceof Long) {
89            visitLong(((Long) value).longValue());
90        } else if (value instanceof Double) {
91            visitDouble(((Double) value).doubleValue());
92        } else if (value.getClass().isArray()) {
93            buf.append('{');
94            if (value instanceof byte[]) {
95                byte[] v = (byte[]) value;
96                for (int i = 0; i < v.length; i++) {
97                    appendComa(i);
98                    visitByte(v[i]);
99                }
100            } else if (value instanceof boolean[]) {
101                boolean[] v = (boolean[]) value;
102                for (int i = 0; i < v.length; i++) {
103                    appendComa(i);
104                    visitBoolean(v[i]);
105                }
106            } else if (value instanceof short[]) {
107                short[] v = (short[]) value;
108                for (int i = 0; i < v.length; i++) {
109                    appendComa(i);
110                    visitShort(v[i]);
111                }
112            } else if (value instanceof char[]) {
113                char[] v = (char[]) value;
114                for (int i = 0; i < v.length; i++) {
115                    appendComa(i);
116                    visitChar(v[i]);
117                }
118            } else if (value instanceof int[]) {
119                int[] v = (int[]) value;
120                for (int i = 0; i < v.length; i++) {
121                    appendComa(i);
122                    visitInt(v[i]);
123                }
124            } else if (value instanceof long[]) {
125                long[] v = (long[]) value;
126                for (int i = 0; i < v.length; i++) {
127                    appendComa(i);
128                    visitLong(v[i]);
129                }
130            } else if (value instanceof float[]) {
131                float[] v = (float[]) value;
132                for (int i = 0; i < v.length; i++) {
133                    appendComa(i);
134                    visitFloat(v[i]);
135                }
136            } else if (value instanceof double[]) {
137                double[] v = (double[]) value;
138                for (int i = 0; i < v.length; i++) {
139                    appendComa(i);
140                    visitDouble(v[i]);
141                }
142            }
143            buf.append('}');
144        }
145
146        text.add(buf.toString());
147
148        if (av != null) {
149            av.visit(name, value);
150        }
151    }
152
153    private void visitInt(final int value) {
154        buf.append(value);
155    }
156
157    private void visitLong(final long value) {
158        buf.append(value).append('L');
159    }
160
161    private void visitFloat(final float value) {
162        buf.append(value).append('F');
163    }
164
165    private void visitDouble(final double value) {
166        buf.append(value).append('D');
167    }
168
169    private void visitChar(final char value) {
170        buf.append("(char)").append((int) value);
171    }
172
173    private void visitShort(final short value) {
174        buf.append("(short)").append(value);
175    }
176
177    private void visitByte(final byte value) {
178        buf.append("(byte)").append(value);
179    }
180
181    private void visitBoolean(final boolean value) {
182        buf.append(value);
183    }
184
185    private void visitString(final String value) {
186        appendString(buf, value);
187    }
188
189    private void visitType(final Type value) {
190        buf.append(value.getClassName()).append(".class");
191    }
192
193    public void visitEnum(
194        final String name,
195        final String desc,
196        final String value)
197    {
198        buf.setLength(0);
199        appendComa(valueNumber++);
200        if (name != null) {
201            buf.append(name).append('=');
202        }
203        appendDescriptor(FIELD_DESCRIPTOR, desc);
204        buf.append('.').append(value);
205        text.add(buf.toString());
206
207        if (av != null) {
208            av.visitEnum(name, desc, value);
209        }
210    }
211
212    public AnnotationVisitor visitAnnotation(
213        final String name,
214        final String desc)
215    {
216        buf.setLength(0);
217        appendComa(valueNumber++);
218        if (name != null) {
219            buf.append(name).append('=');
220        }
221        buf.append('@');
222        appendDescriptor(FIELD_DESCRIPTOR, desc);
223        buf.append('(');
224        text.add(buf.toString());
225        TraceAnnotationVisitor tav = createTraceAnnotationVisitor();
226        text.add(tav.getText());
227        text.add(")");
228        if (av != null) {
229            tav.av = av.visitAnnotation(name, desc);
230        }
231        return tav;
232    }
233
234    public AnnotationVisitor visitArray(final String name) {
235        buf.setLength(0);
236        appendComa(valueNumber++);
237        if (name != null) {
238            buf.append(name).append('=');
239        }
240        buf.append('{');
241        text.add(buf.toString());
242        TraceAnnotationVisitor tav = createTraceAnnotationVisitor();
243        text.add(tav.getText());
244        text.add("}");
245        if (av != null) {
246            tav.av = av.visitArray(name);
247        }
248        return tav;
249    }
250
251    public void visitEnd() {
252        if (av != null) {
253            av.visitEnd();
254        }
255    }
256
257    // ------------------------------------------------------------------------
258    // Utility methods
259    // ------------------------------------------------------------------------
260
261    private void appendComa(final int i) {
262        if (i != 0) {
263            buf.append(", ");
264        }
265    }
266}
267