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.tree;
31
32import java.util.ArrayList;
33import java.util.List;
34
35import org.mockito.asm.AnnotationVisitor;
36
37/**
38 * A node that represents an annotationn.
39 *
40 * @author Eric Bruneton
41 */
42public class AnnotationNode implements AnnotationVisitor {
43
44    /**
45     * The class descriptor of the annotation class.
46     */
47    public String desc;
48
49    /**
50     * The name value pairs of this annotation. Each name value pair is stored
51     * as two consecutive elements in the list. The name is a {@link String},
52     * and the value may be a {@link Byte}, {@link Boolean}, {@link Character},
53     * {@link Short}, {@link Integer}, {@link Long}, {@link Float},
54     * {@link Double}, {@link String} or {@link org.mockito.asm.Type}, or an
55     * two elements String array (for enumeration values), a
56     * {@link AnnotationNode}, or a {@link List} of values of one of the
57     * preceding types. The list may be <tt>null</tt> if there is no name
58     * value pair.
59     */
60    public List values;
61
62    /**
63     * Constructs a new {@link AnnotationNode}.
64     *
65     * @param desc the class descriptor of the annotation class.
66     */
67    public AnnotationNode(final String desc) {
68        this.desc = desc;
69    }
70
71    /**
72     * Constructs a new {@link AnnotationNode} to visit an array value.
73     *
74     * @param values where the visited values must be stored.
75     */
76    AnnotationNode(final List values) {
77        this.values = values;
78    }
79
80    // ------------------------------------------------------------------------
81    // Implementation of the AnnotationVisitor interface
82    // ------------------------------------------------------------------------
83
84    public void visit(final String name, final Object value) {
85        if (values == null) {
86            values = new ArrayList(this.desc != null ? 2 : 1);
87        }
88        if (this.desc != null) {
89            values.add(name);
90        }
91        values.add(value);
92    }
93
94    public void visitEnum(
95        final String name,
96        final String desc,
97        final String value)
98    {
99        if (values == null) {
100            values = new ArrayList(this.desc != null ? 2 : 1);
101        }
102        if (this.desc != null) {
103            values.add(name);
104        }
105        values.add(new String[] { desc, value });
106    }
107
108    public AnnotationVisitor visitAnnotation(
109        final String name,
110        final String desc)
111    {
112        if (values == null) {
113            values = new ArrayList(this.desc != null ? 2 : 1);
114        }
115        if (this.desc != null) {
116            values.add(name);
117        }
118        AnnotationNode annotation = new AnnotationNode(desc);
119        values.add(annotation);
120        return annotation;
121    }
122
123    public AnnotationVisitor visitArray(final String name) {
124        if (values == null) {
125            values = new ArrayList(this.desc != null ? 2 : 1);
126        }
127        if (this.desc != null) {
128            values.add(name);
129        }
130        List array = new ArrayList();
131        values.add(array);
132        return new AnnotationNode(array);
133    }
134
135    public void visitEnd() {
136    }
137
138    // ------------------------------------------------------------------------
139    // Accept methods
140    // ------------------------------------------------------------------------
141
142    /**
143     * Makes the given visitor visit this annotation.
144     *
145     * @param av an annotation visitor. Maybe <tt>null</tt>.
146     */
147    public void accept(final AnnotationVisitor av) {
148        if (av != null) {
149            if (values != null) {
150                for (int i = 0; i < values.size(); i += 2) {
151                    String name = (String) values.get(i);
152                    Object value = values.get(i + 1);
153                    accept(av, name, value);
154                }
155            }
156            av.visitEnd();
157        }
158    }
159
160    /**
161     * Makes the given visitor visit a given annotation value.
162     *
163     * @param av an annotation visitor. Maybe <tt>null</tt>.
164     * @param name the value name.
165     * @param value the actual value.
166     */
167    static void accept(
168        final AnnotationVisitor av,
169        final String name,
170        final Object value)
171    {
172        if (av != null) {
173            if (value instanceof String[]) {
174                String[] typeconst = (String[]) value;
175                av.visitEnum(name, typeconst[0], typeconst[1]);
176            } else if (value instanceof AnnotationNode) {
177                AnnotationNode an = (AnnotationNode) value;
178                an.accept(av.visitAnnotation(name, an.desc));
179            } else if (value instanceof List) {
180                AnnotationVisitor v = av.visitArray(name);
181                List array = (List) value;
182                for (int j = 0; j < array.size(); ++j) {
183                    accept(v, null, array.get(j));
184                }
185                v.visitEnd();
186            } else {
187                av.visit(name, value);
188            }
189        }
190    }
191}
192