001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *   https://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied.  See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019package org.apache.bcel.generic;
020
021import java.io.DataOutputStream;
022import java.io.IOException;
023
024import org.apache.bcel.classfile.ConstantDouble;
025import org.apache.bcel.classfile.ConstantFloat;
026import org.apache.bcel.classfile.ConstantInteger;
027import org.apache.bcel.classfile.ConstantLong;
028import org.apache.bcel.classfile.ConstantUtf8;
029import org.apache.bcel.classfile.ElementValue;
030import org.apache.bcel.classfile.SimpleElementValue;
031
032/**
033 * Generates simple element values in annotations.
034 *
035 * @since 6.0
036 */
037public class SimpleElementValueGen extends ElementValueGen {
038    // For primitive types and string type, this points to the value entry in
039    // the cpGen
040    // For 'class' this points to the class entry in the cpGen
041    private final int idx;
042
043    /**
044     * Constructs a SimpleElementValueGen for a boolean value.
045     *
046     * @param type The element value type.
047     * @param cpGen The constant pool generator.
048     * @param value The boolean value.
049     */
050    public SimpleElementValueGen(final int type, final ConstantPoolGen cpGen, final boolean value) {
051        super(type, cpGen);
052        if (value) {
053            idx = getConstantPool().addInteger(1);
054        } else {
055            idx = getConstantPool().addInteger(0);
056        }
057    }
058
059    /**
060     * Constructs a SimpleElementValueGen for a byte value.
061     *
062     * @param type The element value type.
063     * @param cpGen The constant pool generator.
064     * @param value The byte value.
065     */
066    public SimpleElementValueGen(final int type, final ConstantPoolGen cpGen, final byte value) {
067        super(type, cpGen);
068        idx = getConstantPool().addInteger(value);
069    }
070
071    /**
072     * Constructs a SimpleElementValueGen for a char value.
073     *
074     * @param type The element value type.
075     * @param cpGen The constant pool generator.
076     * @param value The char value.
077     */
078    public SimpleElementValueGen(final int type, final ConstantPoolGen cpGen, final char value) {
079        super(type, cpGen);
080        idx = getConstantPool().addInteger(value);
081    }
082
083    /**
084     * Constructs a SimpleElementValueGen for a double value.
085     *
086     * @param type The element value type.
087     * @param cpGen The constant pool generator.
088     * @param value The double value.
089     */
090    public SimpleElementValueGen(final int type, final ConstantPoolGen cpGen, final double value) {
091        super(type, cpGen);
092        idx = getConstantPool().addDouble(value);
093    }
094
095    /**
096     * Constructs a SimpleElementValueGen for a float value.
097     *
098     * @param type The element value type.
099     * @param cpGen The constant pool generator.
100     * @param value The float value.
101     */
102    public SimpleElementValueGen(final int type, final ConstantPoolGen cpGen, final float value) {
103        super(type, cpGen);
104        idx = getConstantPool().addFloat(value);
105    }
106
107    /**
108     * Constructs a SimpleElementValueGen for an int value.
109     *
110     * @param type The element value type.
111     * @param cpGen The constant pool generator.
112     * @param value The int value.
113     */
114    public SimpleElementValueGen(final int type, final ConstantPoolGen cpGen, final int value) {
115        super(type, cpGen);
116        idx = getConstantPool().addInteger(value);
117    }
118
119    /**
120     * Constructs a SimpleElementValueGen for a long value.
121     *
122     * @param type The element value type.
123     * @param cpGen The constant pool generator.
124     * @param value The long value.
125     */
126    public SimpleElementValueGen(final int type, final ConstantPoolGen cpGen, final long value) {
127        super(type, cpGen);
128        idx = getConstantPool().addLong(value);
129    }
130
131    /**
132     * Constructs a SimpleElementValueGen for a short value.
133     *
134     * @param type The element value type.
135     * @param cpGen The constant pool generator.
136     * @param value The short value.
137     */
138    public SimpleElementValueGen(final int type, final ConstantPoolGen cpGen, final short value) {
139        super(type, cpGen);
140        idx = getConstantPool().addInteger(value);
141    }
142
143    /**
144     * Constructs a SimpleElementValueGen for a String value.
145     *
146     * @param type The element value type.
147     * @param cpGen The constant pool generator.
148     * @param value The string value.
149     */
150    public SimpleElementValueGen(final int type, final ConstantPoolGen cpGen, final String value) {
151        super(type, cpGen);
152        idx = getConstantPool().addUtf8(value);
153    }
154
155    // ctors for each supported type... type could be inferred but for now lets
156    // force it to be passed
157
158    /**
159     * Protected ctor used for deserialization, doesn't *put* an entry in the constant pool, assumes the one at the supplied
160     * index is correct.
161     *
162     * @param type The element value type.
163     * @param idx The constant pool index.
164     * @param cpGen The constant pool generator.
165     */
166    protected SimpleElementValueGen(final int type, final int idx, final ConstantPoolGen cpGen) {
167        super(type, cpGen);
168        this.idx = idx;
169    }
170
171    /**
172     * The boolean controls whether we copy info from the 'old' constant pool to the 'new'. You need to use this ctor if the
173     * annotation is being copied from one file to another.
174     *
175     * @param value The simple element value to copy.
176     * @param cpool The constant pool generator.
177     * @param copyPoolEntries whether to copy pool entries.
178     */
179    public SimpleElementValueGen(final SimpleElementValue value, final ConstantPoolGen cpool, final boolean copyPoolEntries) {
180        super(value.getElementValueType(), cpool);
181        if (!copyPoolEntries) {
182            // J5ASSERT: Could assert value.stringifyValue() is the same as
183            // cpool.getConstant(SimpleElementValuevalue.getIndex())
184            idx = value.getIndex();
185        } else {
186            switch (value.getElementValueType()) {
187            case STRING:
188                idx = cpool.addUtf8(value.getValueString());
189                break;
190            case PRIMITIVE_INT:
191                idx = cpool.addInteger(value.getValueInt());
192                break;
193            case PRIMITIVE_BYTE:
194                idx = cpool.addInteger(value.getValueByte());
195                break;
196            case PRIMITIVE_CHAR:
197                idx = cpool.addInteger(value.getValueChar());
198                break;
199            case PRIMITIVE_LONG:
200                idx = cpool.addLong(value.getValueLong());
201                break;
202            case PRIMITIVE_FLOAT:
203                idx = cpool.addFloat(value.getValueFloat());
204                break;
205            case PRIMITIVE_DOUBLE:
206                idx = cpool.addDouble(value.getValueDouble());
207                break;
208            case PRIMITIVE_BOOLEAN:
209                if (value.getValueBoolean()) {
210                    idx = cpool.addInteger(1);
211                } else {
212                    idx = cpool.addInteger(0);
213                }
214                break;
215            case PRIMITIVE_SHORT:
216                idx = cpool.addInteger(value.getValueShort());
217                break;
218            default:
219                throw new IllegalArgumentException("SimpleElementValueGen class does not know how to copy this type " + super.getElementValueType());
220            }
221        }
222    }
223
224    @Override
225    public void dump(final DataOutputStream dos) throws IOException {
226        dos.writeByte(super.getElementValueType()); // u1 kind of value
227        switch (super.getElementValueType()) {
228        case PRIMITIVE_INT:
229        case PRIMITIVE_BYTE:
230        case PRIMITIVE_CHAR:
231        case PRIMITIVE_FLOAT:
232        case PRIMITIVE_LONG:
233        case PRIMITIVE_BOOLEAN:
234        case PRIMITIVE_SHORT:
235        case PRIMITIVE_DOUBLE:
236        case STRING:
237            dos.writeShort(idx);
238            break;
239        default:
240            throw new IllegalStateException("SimpleElementValueGen doesn't know how to write out type " + super.getElementValueType());
241        }
242    }
243
244    /**
245     * Gets the immutable variant.
246     *
247     * @return The immutable variant.
248     */
249    @Override
250    public ElementValue getElementValue() {
251        return new SimpleElementValue(super.getElementValueType(), idx, getConstantPool().getConstantPool());
252    }
253
254    /**
255     * Gets the constant pool index.
256     *
257     * @return The index.
258     */
259    public int getIndex() {
260        return idx;
261    }
262
263    /**
264     * Gets the int value.
265     *
266     * @return The int value.
267     */
268    public int getValueInt() {
269        if (super.getElementValueType() != PRIMITIVE_INT) {
270            throw new IllegalStateException("Don't call getValueString() on a non STRING ElementValue");
271        }
272        final ConstantInteger c = (ConstantInteger) getConstantPool().getConstant(idx);
273        return c.getBytes();
274    }
275
276    /**
277     * Gets the string value.
278     *
279     * @return The string value.
280     */
281    public String getValueString() {
282        if (super.getElementValueType() != STRING) {
283            throw new IllegalStateException("Don't call getValueString() on a non STRING ElementValue");
284        }
285        final ConstantUtf8 c = (ConstantUtf8) getConstantPool().getConstant(idx);
286        return c.getBytes();
287    }
288
289    // Whatever kind of value it is, return it as a string
290    @Override
291    public String stringifyValue() {
292        switch (super.getElementValueType()) {
293        case PRIMITIVE_INT:
294            final ConstantInteger c = (ConstantInteger) getConstantPool().getConstant(idx);
295            return Integer.toString(c.getBytes());
296        case PRIMITIVE_LONG:
297            final ConstantLong j = (ConstantLong) getConstantPool().getConstant(idx);
298            return Long.toString(j.getBytes());
299        case PRIMITIVE_DOUBLE:
300            final ConstantDouble d = (ConstantDouble) getConstantPool().getConstant(idx);
301            return Double.toString(d.getBytes());
302        case PRIMITIVE_FLOAT:
303            final ConstantFloat f = (ConstantFloat) getConstantPool().getConstant(idx);
304            return Float.toString(f.getBytes());
305        case PRIMITIVE_SHORT:
306            final ConstantInteger s = (ConstantInteger) getConstantPool().getConstant(idx);
307            return Integer.toString(s.getBytes());
308        case PRIMITIVE_BYTE:
309            final ConstantInteger b = (ConstantInteger) getConstantPool().getConstant(idx);
310            return Integer.toString(b.getBytes());
311        case PRIMITIVE_CHAR:
312            final ConstantInteger ch = (ConstantInteger) getConstantPool().getConstant(idx);
313            return Integer.toString(ch.getBytes());
314        case PRIMITIVE_BOOLEAN:
315            final ConstantInteger bo = (ConstantInteger) getConstantPool().getConstant(idx);
316            if (bo.getBytes() == 0) {
317                return "false";
318            }
319            return "true";
320        case STRING:
321            final ConstantUtf8 cu8 = (ConstantUtf8) getConstantPool().getConstant(idx);
322            return cu8.getBytes();
323        default:
324            throw new IllegalStateException("SimpleElementValueGen class does not know how to stringify type " + super.getElementValueType());
325        }
326    }
327}