001package serp.bytecode;
002
003import java.io.*;
004
005import serp.bytecode.lowlevel.*;
006import serp.bytecode.visitor.*;
007
008/**
009 * A constant value for a member field.
010 *
011 * @author Abe White
012 */
013public class ConstantValue extends Attribute {
014    int _valueIndex = 0;
015
016    ConstantValue(int nameIndex, Attributes owner) {
017        super(nameIndex, owner);
018    }
019
020    int getLength() {
021        return 2;
022    }
023
024    /**
025     * Return the owning field.
026     */
027    public BCField getField() {
028        return (BCField) getOwner();
029    }
030
031    /**
032     * Return the {@link ConstantPool} index of the {@link ConstantEntry}
033     * holding the value of this constant. Defaults to 0.
034     */
035    public int getValueIndex() {
036        return _valueIndex;
037    }
038
039    /**
040     * Set the {@link ConstantPool} of the {@link ConstantEntry}
041     * holding the value of this constant.
042     */
043    public void setValueIndex(int valueIndex) {
044        _valueIndex = valueIndex;
045    }
046
047    /**
048     * Return the type of constant this attribute represents, or null if
049     * not set.
050     */
051    public String getTypeName() {
052        Class type = getType();
053        if (type == null)
054            return null;
055        return type.getName();
056    }
057
058    /**
059     * Return the type of constant this attribute represents (String.class,
060     * int.class, etc), or null if not set.
061     */
062    public Class getType() {
063        Object value = getValue();
064        if (value == null)
065            return null;
066
067        Class type = value.getClass();
068        if (type == Integer.class)
069            return int.class;
070        if (type == Float.class)
071            return float.class;
072        if (type == Double.class)
073            return double.class;
074        if (type == Long.class)
075            return long.class;
076        return String.class;
077    }
078
079    /**
080     * Return the bytecode for the type of constant this attribute represents.
081     */
082    public BCClass getTypeBC() {
083        return getProject().loadClass(getType());
084    }
085
086    /**
087     * Return the value of this constant as an Object of the appropriate
088     * type (String, Integer, Double, etc), or null if not set.
089     */
090    public Object getValue() {
091        if (_valueIndex <= 0)
092            return null;
093        return ((ConstantEntry) getPool().getEntry(_valueIndex)).getConstant();
094    }
095
096    /**
097     * Set the value of this constant using the appropriate wrapper Object
098     * type (String, Integer, Double, etc). Types that are not directly
099     * supported will be converted accordingly if possible.
100     */
101    public void setValue(Object value) {
102        Class type = value.getClass();
103        if (type == Boolean.class)
104            setIntValue((((Boolean) value).booleanValue()) ? 1 : 0);
105        else if (type == Character.class)
106            setIntValue((int) ((Character) value).charValue());
107        else if (type == Byte.class || type == Integer.class 
108            || type == Short.class)
109            setIntValue(((Number) value).intValue());
110        else if (type == Float.class)
111            setFloatValue(((Number) value).floatValue());
112        else if (type == Double.class)
113            setDoubleValue(((Number) value).doubleValue());
114        else if (type == Long.class)
115            setLongValue(((Number) value).longValue());
116        else
117            setStringValue(value.toString());
118    }
119
120    /**
121     * Get the value of this int constant, or 0 if not set.
122     */
123    public int getIntValue() {
124        if (getValueIndex() <= 0)
125            return 0;
126        return ((IntEntry) getPool().getEntry(getValueIndex())).getValue();
127    }
128
129    /**
130     * Set the value of this int constant.
131     */
132    public void setIntValue(int value) {
133        setValueIndex(getPool().findIntEntry(value, true));
134    }
135
136    /**
137     * Get the value of this float constant.
138     */
139    public float getFloatValue() {
140        if (getValueIndex() <= 0)
141            return 0F;
142        return ((FloatEntry) getPool().getEntry(getValueIndex())).getValue();
143    }
144
145    /**
146     * Set the value of this float constant.
147     */
148    public void setFloatValue(float value) {
149        setValueIndex(getPool().findFloatEntry(value, true));
150    }
151
152    /**
153     * Get the value of this double constant.
154     */
155    public double getDoubleValue() {
156        if (getValueIndex() <= 0)
157            return 0D;
158        return ((DoubleEntry) getPool().getEntry(getValueIndex())).getValue();
159    }
160
161    /**
162     * Set the value of this double constant.
163     */
164    public void setDoubleValue(double value) {
165        setValueIndex(getPool().findDoubleEntry(value, true));
166    }
167
168    /**
169     * Get the value of this long constant.
170     */
171    public long getLongValue() {
172        if (getValueIndex() <= 0)
173            return 0L;
174        return ((LongEntry) getPool().getEntry(getValueIndex())).getValue();
175    }
176
177    /**
178     * Set the value of this long constant.
179     */
180    public void setLongValue(long value) {
181        setValueIndex(getPool().findLongEntry(value, true));
182    }
183
184    /**
185     * Get the value of this string constant.
186     */
187    public String getStringValue() {
188        if (getValueIndex() <= 0)
189            return null;
190        return ((StringEntry) getPool().getEntry(getValueIndex())).
191            getStringEntry().getValue();
192    }
193
194    /**
195     * Set the value of this string constant.
196     */
197    public void setStringValue(String value) {
198        setValueIndex(getPool().findStringEntry(value, true));
199    }
200
201    public void acceptVisit(BCVisitor visit) {
202        visit.enterConstantValue(this);
203        visit.exitConstantValue(this);
204    }
205
206    void read(Attribute other) {
207        setValue(((ConstantValue) other).getValue());
208    }
209
210    void read(DataInput in, int length) throws IOException {
211        setValueIndex(in.readUnsignedShort());
212    }
213
214    void write(DataOutput out, int length) throws IOException {
215        out.writeShort(getValueIndex());
216    }
217}