1/*
2 * Javassist, a Java-bytecode translator toolkit.
3 * Copyright (C) 1999-2007 Shigeru Chiba. All Rights Reserved.
4 *
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License.  Alternatively, the contents of this file may be used under
8 * the terms of the GNU Lesser General Public License Version 2.1 or later.
9 *
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
14 */
15
16package javassist.bytecode;
17
18import java.io.DataInputStream;
19import java.io.DataOutputStream;
20import java.io.IOException;
21import java.util.List;
22import java.util.ArrayList;
23
24/**
25 * <code>field_info</code> structure.
26 *
27 * @see javassist.CtField#getFieldInfo()
28 */
29public final class FieldInfo {
30    ConstPool constPool;
31    int accessFlags;
32    int name;
33    String cachedName;
34    String cachedType;
35    int descriptor;
36    ArrayList attribute;       // may be null.
37
38    private FieldInfo(ConstPool cp) {
39        constPool = cp;
40        accessFlags = 0;
41        attribute = null;
42    }
43
44    /**
45     * Constructs a <code>field_info</code> structure.
46     *
47     * @param cp                a constant pool table
48     * @param fieldName         field name
49     * @param desc              field descriptor
50     *
51     * @see Descriptor
52     */
53    public FieldInfo(ConstPool cp, String fieldName, String desc) {
54        this(cp);
55        name = cp.addUtf8Info(fieldName);
56        cachedName = fieldName;
57        descriptor = cp.addUtf8Info(desc);
58    }
59
60    FieldInfo(ConstPool cp, DataInputStream in) throws IOException {
61        this(cp);
62        read(in);
63    }
64
65    /**
66     * Returns a string representation of the object.
67     */
68    public String toString() {
69        return getName() + " " + getDescriptor();
70    }
71
72    /**
73     * Copies all constant pool items to a given new constant pool
74     * and replaces the original items with the new ones.
75     * This is used for garbage collecting the items of removed fields
76     * and methods.
77     *
78     * @param cp    the destination
79     */
80    void compact(ConstPool cp) {
81        name = cp.addUtf8Info(getName());
82        descriptor = cp.addUtf8Info(getDescriptor());
83        attribute = AttributeInfo.copyAll(attribute, cp);
84        constPool = cp;
85    }
86
87    void prune(ConstPool cp) {
88        ArrayList newAttributes = new ArrayList();
89        AttributeInfo invisibleAnnotations
90            = getAttribute(AnnotationsAttribute.invisibleTag);
91        if (invisibleAnnotations != null) {
92            invisibleAnnotations = invisibleAnnotations.copy(cp, null);
93            newAttributes.add(invisibleAnnotations);
94         }
95
96        AttributeInfo visibleAnnotations
97            = getAttribute(AnnotationsAttribute.visibleTag);
98        if (visibleAnnotations != null) {
99            visibleAnnotations = visibleAnnotations.copy(cp, null);
100            newAttributes.add(visibleAnnotations);
101        }
102
103        AttributeInfo signature
104            = getAttribute(SignatureAttribute.tag);
105        if (signature != null) {
106            signature = signature.copy(cp, null);
107            newAttributes.add(signature);
108        }
109
110        int index = getConstantValue();
111        if (index != 0) {
112            index = constPool.copy(index, cp, null);
113            newAttributes.add(new ConstantAttribute(cp, index));
114        }
115
116        attribute = newAttributes;
117        name = cp.addUtf8Info(getName());
118        descriptor = cp.addUtf8Info(getDescriptor());
119        constPool = cp;
120    }
121
122    /**
123     * Returns the constant pool table used
124     * by this <code>field_info</code>.
125     */
126    public ConstPool getConstPool() {
127        return constPool;
128    }
129
130    /**
131     * Returns the field name.
132     */
133    public String getName() {
134       if (cachedName == null)
135           cachedName = constPool.getUtf8Info(name);
136
137       return cachedName;
138    }
139
140    /**
141     * Sets the field name.
142     */
143    public void setName(String newName) {
144        name = constPool.addUtf8Info(newName);
145        cachedName = newName;
146    }
147
148    /**
149     * Returns the access flags.
150     *
151     * @see AccessFlag
152     */
153    public int getAccessFlags() {
154        return accessFlags;
155    }
156
157    /**
158     * Sets the access flags.
159     *
160     * @see AccessFlag
161     */
162    public void setAccessFlags(int acc) {
163        accessFlags = acc;
164    }
165
166    /**
167     * Returns the field descriptor.
168     *
169     * @see Descriptor
170     */
171    public String getDescriptor() {
172        return constPool.getUtf8Info(descriptor);
173    }
174
175    /**
176     * Sets the field descriptor.
177     *
178     * @see Descriptor
179     */
180    public void setDescriptor(String desc) {
181        if (!desc.equals(getDescriptor()))
182            descriptor = constPool.addUtf8Info(desc);
183    }
184
185    /**
186     * Finds a ConstantValue attribute and returns the index into
187     * the <code>constant_pool</code> table.
188     *
189     * @return 0    if a ConstantValue attribute is not found.
190     */
191    public int getConstantValue() {
192        if ((accessFlags & AccessFlag.STATIC) == 0)
193            return 0;
194
195        ConstantAttribute attr
196            = (ConstantAttribute)getAttribute(ConstantAttribute.tag);
197        if (attr == null)
198            return 0;
199        else
200            return attr.getConstantValue();
201    }
202
203    /**
204     * Returns all the attributes.    The returned <code>List</code> object
205     * is shared with this object.  If you add a new attribute to the list,
206     * the attribute is also added to the field represented by this
207     * object.  If you remove an attribute from the list, it is also removed
208     * from the field.
209     *
210     * @return a list of <code>AttributeInfo</code> objects.
211     * @see AttributeInfo
212     */
213    public List getAttributes() {
214        if (attribute == null)
215            attribute = new ArrayList();
216
217        return attribute;
218    }
219
220    /**
221     * Returns the attribute with the specified name.
222     * It returns null if the specified attribute is not found.
223     *
224     * @param name      attribute name
225     * @see #getAttributes()
226     */
227    public AttributeInfo getAttribute(String name) {
228        return AttributeInfo.lookup(attribute, name);
229    }
230
231    /**
232     * Appends an attribute.  If there is already an attribute with
233     * the same name, the new one substitutes for it.
234     *
235     * @see #getAttributes()
236     */
237    public void addAttribute(AttributeInfo info) {
238        if (attribute == null)
239            attribute = new ArrayList();
240
241        AttributeInfo.remove(attribute, info.getName());
242        attribute.add(info);
243    }
244
245    private void read(DataInputStream in) throws IOException {
246        accessFlags = in.readUnsignedShort();
247        name = in.readUnsignedShort();
248        descriptor = in.readUnsignedShort();
249        int n = in.readUnsignedShort();
250        attribute = new ArrayList();
251        for (int i = 0; i < n; ++i)
252            attribute.add(AttributeInfo.read(constPool, in));
253    }
254
255    void write(DataOutputStream out) throws IOException {
256        out.writeShort(accessFlags);
257        out.writeShort(name);
258        out.writeShort(descriptor);
259        if (attribute == null)
260            out.writeShort(0);
261        else {
262            out.writeShort(attribute.size());
263            AttributeInfo.writeAll(attribute, out);
264        }
265    }
266}
267