1/*
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3 *
4 * This code is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 2 only, as
6 * published by the Free Software Foundation.  Oracle designates this
7 * particular file as subject to the "Classpath" exception as provided
8 * by Oracle in the LICENSE file that accompanied this code.
9 *
10 * This code is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
13 * version 2 for more details (a copy is included in the LICENSE file that
14 * accompanied this code).
15 *
16 * You should have received a copy of the GNU General Public License version
17 * 2 along with this work; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19 *
20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21 * or visit www.oracle.com if you need additional information or have any
22 * questions.
23 */
24
25/*
26 * This file is available under and governed by the GNU General Public
27 * License version 2 only, as published by the Free Software Foundation.
28 * However, the following notice accompanied the original version of this
29 * file:
30 *
31 * ASM: a very small and fast Java bytecode manipulation framework
32 * Copyright (c) 2000-2011 INRIA, France Telecom
33 * All rights reserved.
34 *
35 * Redistribution and use in source and binary forms, with or without
36 * modification, are permitted provided that the following conditions
37 * are met:
38 * 1. Redistributions of source code must retain the above copyright
39 *    notice, this list of conditions and the following disclaimer.
40 * 2. Redistributions in binary form must reproduce the above copyright
41 *    notice, this list of conditions and the following disclaimer in the
42 *    documentation and/or other materials provided with the distribution.
43 * 3. Neither the name of the copyright holders nor the names of its
44 *    contributors may be used to endorse or promote products derived from
45 *    this software without specific prior written permission.
46 *
47 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
48 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
50 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
51 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
52 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
53 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
54 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
55 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
56 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
57 * THE POSSIBILITY OF SUCH DAMAGE.
58 */
59package jdk.internal.org.objectweb.asm.tree;
60
61import java.util.ArrayList;
62import java.util.List;
63
64import jdk.internal.org.objectweb.asm.AnnotationVisitor;
65import jdk.internal.org.objectweb.asm.Opcodes;
66
67/**
68 * A node that represents an annotationn.
69 *
70 * @author Eric Bruneton
71 */
72public class AnnotationNode extends AnnotationVisitor {
73
74    /**
75     * The class descriptor of the annotation class.
76     */
77    public String desc;
78
79    /**
80     * The name value pairs of this annotation. Each name value pair is stored
81     * as two consecutive elements in the list. The name is a {@link String},
82     * and the value may be a {@link Byte}, {@link Boolean}, {@link Character},
83     * {@link Short}, {@link Integer}, {@link Long}, {@link Float},
84     * {@link Double}, {@link String} or {@link jdk.internal.org.objectweb.asm.Type}, or an
85     * two elements String array (for enumeration values), a
86     * {@link AnnotationNode}, or a {@link List} of values of one of the
87     * preceding types. The list may be <tt>null</tt> if there is no name value
88     * pair.
89     */
90    public List<Object> values;
91
92    /**
93     * Constructs a new {@link AnnotationNode}. <i>Subclasses must not use this
94     * constructor</i>. Instead, they must use the
95     * {@link #AnnotationNode(int, String)} version.
96     *
97     * @param desc
98     *            the class descriptor of the annotation class.
99     * @throws IllegalStateException
100     *             If a subclass calls this constructor.
101     */
102    public AnnotationNode(final String desc) {
103        this(Opcodes.ASM5, desc);
104        if (getClass() != AnnotationNode.class) {
105            throw new IllegalStateException();
106        }
107    }
108
109    /**
110     * Constructs a new {@link AnnotationNode}.
111     *
112     * @param api
113     *            the ASM API version implemented by this visitor. Must be one
114     *            of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
115     * @param desc
116     *            the class descriptor of the annotation class.
117     */
118    public AnnotationNode(final int api, final String desc) {
119        super(api);
120        this.desc = desc;
121    }
122
123    /**
124     * Constructs a new {@link AnnotationNode} to visit an array value.
125     *
126     * @param values
127     *            where the visited values must be stored.
128     */
129    AnnotationNode(final List<Object> values) {
130        super(Opcodes.ASM5);
131        this.values = values;
132    }
133
134    // ------------------------------------------------------------------------
135    // Implementation of the AnnotationVisitor abstract class
136    // ------------------------------------------------------------------------
137
138    @Override
139    public void visit(final String name, final Object value) {
140        if (values == null) {
141            values = new ArrayList<Object>(this.desc != null ? 2 : 1);
142        }
143        if (this.desc != null) {
144            values.add(name);
145        }
146        values.add(value);
147    }
148
149    @Override
150    public void visitEnum(final String name, final String desc,
151            final String value) {
152        if (values == null) {
153            values = new ArrayList<Object>(this.desc != null ? 2 : 1);
154        }
155        if (this.desc != null) {
156            values.add(name);
157        }
158        values.add(new String[] { desc, value });
159    }
160
161    @Override
162    public AnnotationVisitor visitAnnotation(final String name,
163            final String desc) {
164        if (values == null) {
165            values = new ArrayList<Object>(this.desc != null ? 2 : 1);
166        }
167        if (this.desc != null) {
168            values.add(name);
169        }
170        AnnotationNode annotation = new AnnotationNode(desc);
171        values.add(annotation);
172        return annotation;
173    }
174
175    @Override
176    public AnnotationVisitor visitArray(final String name) {
177        if (values == null) {
178            values = new ArrayList<Object>(this.desc != null ? 2 : 1);
179        }
180        if (this.desc != null) {
181            values.add(name);
182        }
183        List<Object> array = new ArrayList<Object>();
184        values.add(array);
185        return new AnnotationNode(array);
186    }
187
188    @Override
189    public void visitEnd() {
190    }
191
192    // ------------------------------------------------------------------------
193    // Accept methods
194    // ------------------------------------------------------------------------
195
196    /**
197     * Checks that this annotation node is compatible with the given ASM API
198     * version. This methods checks that this node, and all its nodes
199     * recursively, do not contain elements that were introduced in more recent
200     * versions of the ASM API than the given version.
201     *
202     * @param api
203     *            an ASM API version. Must be one of {@link Opcodes#ASM4} or
204     *            {@link Opcodes#ASM5}.
205     */
206    public void check(final int api) {
207        // nothing to do
208    }
209
210    /**
211     * Makes the given visitor visit this annotation.
212     *
213     * @param av
214     *            an annotation visitor. Maybe <tt>null</tt>.
215     */
216    public void accept(final AnnotationVisitor av) {
217        if (av != null) {
218            if (values != null) {
219                for (int i = 0; i < values.size(); i += 2) {
220                    String name = (String) values.get(i);
221                    Object value = values.get(i + 1);
222                    accept(av, name, value);
223                }
224            }
225            av.visitEnd();
226        }
227    }
228
229    /**
230     * Makes the given visitor visit a given annotation value.
231     *
232     * @param av
233     *            an annotation visitor. Maybe <tt>null</tt>.
234     * @param name
235     *            the value name.
236     * @param value
237     *            the actual value.
238     */
239    static void accept(final AnnotationVisitor av, final String name,
240            final Object value) {
241        if (av != null) {
242            if (value instanceof String[]) {
243                String[] typeconst = (String[]) value;
244                av.visitEnum(name, typeconst[0], typeconst[1]);
245            } else if (value instanceof AnnotationNode) {
246                AnnotationNode an = (AnnotationNode) value;
247                an.accept(av.visitAnnotation(name, an.desc));
248            } else if (value instanceof List) {
249                AnnotationVisitor v = av.visitArray(name);
250                if (v != null) {
251                    List<?> array = (List<?>) value;
252                    for (int j = 0; j < array.size(); ++j) {
253                        accept(v, null, array.get(j));
254                    }
255                    v.visitEnd();
256                }
257            } else {
258                av.visit(name, value);
259            }
260        }
261    }
262}
263