001/***
002 * ASM: a very small and fast Java bytecode manipulation framework
003 * Copyright (c) 2000-2011 INRIA, France Telecom
004 * All rights reserved.
005 *
006 * Redistribution and use in source and binary forms, with or without
007 * modification, are permitted provided that the following conditions
008 * are met:
009 * 1. Redistributions of source code must retain the above copyright
010 *    notice, this list of conditions and the following disclaimer.
011 * 2. Redistributions in binary form must reproduce the above copyright
012 *    notice, this list of conditions and the following disclaimer in the
013 *    documentation and/or other materials provided with the distribution.
014 * 3. Neither the name of the copyright holders nor the names of its
015 *    contributors may be used to endorse or promote products derived from
016 *    this software without specific prior written permission.
017 *
018 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
020 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
021 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
022 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
023 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
024 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
025 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
026 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
027 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
028 * THE POSSIBILITY OF SUCH DAMAGE.
029 */
030package io.ebean.enhance.asm.tree;
031
032import io.ebean.enhance.asm.AnnotationVisitor;
033import io.ebean.enhance.asm.Attribute;
034import io.ebean.enhance.asm.ClassVisitor;
035import io.ebean.enhance.asm.FieldVisitor;
036import io.ebean.enhance.asm.Opcodes;
037import io.ebean.enhance.asm.Type;
038import io.ebean.enhance.asm.TypePath;
039
040import java.util.ArrayList;
041import java.util.List;
042
043/**
044 * A node that represents a field.
045 * 
046 * @author Eric Bruneton
047 */
048public class FieldNode extends FieldVisitor {
049
050    /**
051     * The field's access flags (see {@link Opcodes}). This
052     * field also indicates if the field is synthetic and/or deprecated.
053     */
054    public int access;
055
056    /**
057     * The field's name.
058     */
059    public String name;
060
061    /**
062     * The field's descriptor (see {@link Type}).
063     */
064    public String desc;
065
066    /**
067     * The field's signature. May be <tt>null</tt>.
068     */
069    public String signature;
070
071    /**
072     * The field's initial value. This field, which may be <tt>null</tt> if the
073     * field does not have an initial value, must be an {@link Integer}, a
074     * {@link Float}, a {@link Long}, a {@link Double} or a {@link String}.
075     */
076    public Object value;
077
078    /**
079     * The runtime visible annotations of this field. This list is a list of
080     * {@link AnnotationNode} objects. May be <tt>null</tt>.
081     * 
082     * @associates org.objectweb.asm.tree.AnnotationNode
083     * @label visible
084     */
085    public List<AnnotationNode> visibleAnnotations;
086
087    /**
088     * The runtime invisible annotations of this field. This list is a list of
089     * {@link AnnotationNode} objects. May be <tt>null</tt>.
090     * 
091     * @associates org.objectweb.asm.tree.AnnotationNode
092     * @label invisible
093     */
094    public List<AnnotationNode> invisibleAnnotations;
095
096    /**
097     * The runtime visible type annotations of this field. This list is a list
098     * of {@link TypeAnnotationNode} objects. May be <tt>null</tt>.
099     * 
100     * @associates org.objectweb.asm.tree.TypeAnnotationNode
101     * @label visible
102     */
103    public List<TypeAnnotationNode> visibleTypeAnnotations;
104
105    /**
106     * The runtime invisible type annotations of this field. This list is a list
107     * of {@link TypeAnnotationNode} objects. May be <tt>null</tt>.
108     * 
109     * @associates org.objectweb.asm.tree.TypeAnnotationNode
110     * @label invisible
111     */
112    public List<TypeAnnotationNode> invisibleTypeAnnotations;
113
114    /**
115     * The non standard attributes of this field. This list is a list of
116     * {@link Attribute} objects. May be <tt>null</tt>.
117     * 
118     * @associates org.objectweb.asm.Attribute
119     */
120    public List<Attribute> attrs;
121
122    /**
123     * Constructs a new {@link FieldNode}. <i>Subclasses must not use this
124     * constructor</i>. Instead, they must use the
125     * {@link #FieldNode(int, int, String, String, String, Object)} version.
126     * 
127     * @param access
128     *            the field's access flags (see
129     *            {@link Opcodes}). This parameter also
130     *            indicates if the field is synthetic and/or deprecated.
131     * @param name
132     *            the field's name.
133     * @param desc
134     *            the field's descriptor (see {@link Type
135     *            Type}).
136     * @param signature
137     *            the field's signature.
138     * @param value
139     *            the field's initial value. This parameter, which may be
140     *            <tt>null</tt> if the field does not have an initial value,
141     *            must be an {@link Integer}, a {@link Float}, a {@link Long}, a
142     *            {@link Double} or a {@link String}.
143     * @throws IllegalStateException
144     *             If a subclass calls this constructor.
145     */
146    public FieldNode(final int access, final String name, final String desc,
147            final String signature, final Object value) {
148        this(Opcodes.ASM6, access, name, desc, signature, value);
149        if (getClass() != FieldNode.class) {
150            throw new IllegalStateException();
151        }
152    }
153
154    /**
155     * Constructs a new {@link FieldNode}. <i>Subclasses must not use this
156     * constructor</i>.
157     * 
158     * @param api
159     *            the ASM API version implemented by this visitor. Must be one
160     *            of {@link Opcodes#ASM4} or {@link Opcodes#ASM5}.
161     * @param access
162     *            the field's access flags (see
163     *            {@link Opcodes}). This parameter also
164     *            indicates if the field is synthetic and/or deprecated.
165     * @param name
166     *            the field's name.
167     * @param desc
168     *            the field's descriptor (see {@link Type
169     *            Type}).
170     * @param signature
171     *            the field's signature.
172     * @param value
173     *            the field's initial value. This parameter, which may be
174     *            <tt>null</tt> if the field does not have an initial value,
175     *            must be an {@link Integer}, a {@link Float}, a {@link Long}, a
176     *            {@link Double} or a {@link String}.
177     */
178    public FieldNode(final int api, final int access, final String name,
179            final String desc, final String signature, final Object value) {
180        super(api);
181        this.access = access;
182        this.name = name;
183        this.desc = desc;
184        this.signature = signature;
185        this.value = value;
186    }
187
188    // ------------------------------------------------------------------------
189    // Implementation of the FieldVisitor abstract class
190    // ------------------------------------------------------------------------
191
192    @Override
193    public AnnotationVisitor visitAnnotation(final String desc,
194                                             final boolean visible) {
195        AnnotationNode an = new AnnotationNode(desc);
196        if (visible) {
197            if (visibleAnnotations == null) {
198                visibleAnnotations = new ArrayList<AnnotationNode>(1);
199            }
200            visibleAnnotations.add(an);
201        } else {
202            if (invisibleAnnotations == null) {
203                invisibleAnnotations = new ArrayList<AnnotationNode>(1);
204            }
205            invisibleAnnotations.add(an);
206        }
207        return an;
208    }
209
210    @Override
211    public AnnotationVisitor visitTypeAnnotation(int typeRef,
212                                                 TypePath typePath, String desc, boolean visible) {
213        TypeAnnotationNode an = new TypeAnnotationNode(typeRef, typePath, desc);
214        if (visible) {
215            if (visibleTypeAnnotations == null) {
216                visibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
217            }
218            visibleTypeAnnotations.add(an);
219        } else {
220            if (invisibleTypeAnnotations == null) {
221                invisibleTypeAnnotations = new ArrayList<TypeAnnotationNode>(1);
222            }
223            invisibleTypeAnnotations.add(an);
224        }
225        return an;
226    }
227
228    @Override
229    public void visitAttribute(final Attribute attr) {
230        if (attrs == null) {
231            attrs = new ArrayList<Attribute>(1);
232        }
233        attrs.add(attr);
234    }
235
236    @Override
237    public void visitEnd() {
238    }
239
240    // ------------------------------------------------------------------------
241    // Accept methods
242    // ------------------------------------------------------------------------
243
244    /**
245     * Checks that this field node is compatible with the given ASM API version.
246     * This methods checks that this node, and all its nodes recursively, do not
247     * contain elements that were introduced in more recent versions of the ASM
248     * API than the given version.
249     * 
250     * @param api
251     *            an ASM API version. Must be one of {@link Opcodes#ASM4},
252     *            {@link Opcodes#ASM5} or {@link Opcodes#ASM6}.
253     */
254    public void check(final int api) {
255        if (api == Opcodes.ASM4) {
256            if (visibleTypeAnnotations != null
257                    && visibleTypeAnnotations.size() > 0) {
258                throw new RuntimeException();
259            }
260            if (invisibleTypeAnnotations != null
261                    && invisibleTypeAnnotations.size() > 0) {
262                throw new RuntimeException();
263            }
264        }
265    }
266
267    /**
268     * Makes the given class visitor visit this field.
269     * 
270     * @param cv
271     *            a class visitor.
272     */
273    public void accept(final ClassVisitor cv) {
274        FieldVisitor fv = cv.visitField(access, name, desc, signature, value);
275        if (fv == null) {
276            return;
277        }
278        int i, n;
279        n = visibleAnnotations == null ? 0 : visibleAnnotations.size();
280        for (i = 0; i < n; ++i) {
281            AnnotationNode an = visibleAnnotations.get(i);
282            an.accept(fv.visitAnnotation(an.desc, true));
283        }
284        n = invisibleAnnotations == null ? 0 : invisibleAnnotations.size();
285        for (i = 0; i < n; ++i) {
286            AnnotationNode an = invisibleAnnotations.get(i);
287            an.accept(fv.visitAnnotation(an.desc, false));
288        }
289        n = visibleTypeAnnotations == null ? 0 : visibleTypeAnnotations.size();
290        for (i = 0; i < n; ++i) {
291            TypeAnnotationNode an = visibleTypeAnnotations.get(i);
292            an.accept(fv.visitTypeAnnotation(an.typeRef, an.typePath, an.desc,
293                    true));
294        }
295        n = invisibleTypeAnnotations == null ? 0 : invisibleTypeAnnotations
296                .size();
297        for (i = 0; i < n; ++i) {
298            TypeAnnotationNode an = invisibleTypeAnnotations.get(i);
299            an.accept(fv.visitTypeAnnotation(an.typeRef, an.typePath, an.desc,
300                    false));
301        }
302        n = attrs == null ? 0 : attrs.size();
303        for (i = 0; i < n; ++i) {
304            fv.visitAttribute(attrs.get(i));
305        }
306        fv.visitEnd();
307    }
308}