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;
023import java.util.ArrayList;
024import java.util.List;
025import java.util.stream.Collectors;
026
027import org.apache.bcel.classfile.ArrayElementValue;
028import org.apache.bcel.classfile.ElementValue;
029import org.apache.commons.lang3.stream.Streams;
030
031/**
032 * Generates array element values in annotations.
033 *
034 * @since 6.0
035 */
036public class ArrayElementValueGen extends ElementValueGen {
037    // J5TODO: Should we make this an array or a list? A list would be easier to
038    // modify ...
039    private final List<ElementValueGen> evalues;
040
041    /**
042     * Constructs an ArrayElementValueGen.
043     *
044     * @param value the array element value.
045     * @param cpool the constant pool generator.
046     * @param copyPoolEntries whether to copy pool entries.
047     */
048    public ArrayElementValueGen(final ArrayElementValue value, final ConstantPoolGen cpool, final boolean copyPoolEntries) {
049        super(ARRAY, cpool);
050        evalues = new ArrayList<>();
051        final ElementValue[] in = value.getElementValuesArray();
052        for (final ElementValue element : in) {
053            evalues.add(copy(element, cpool, copyPoolEntries));
054        }
055    }
056
057    /**
058     * Constructs an ArrayElementValueGen.
059     *
060     * @param cp the constant pool generator.
061     */
062    public ArrayElementValueGen(final ConstantPoolGen cp) {
063        super(ARRAY, cp);
064        evalues = new ArrayList<>();
065    }
066
067    /**
068     * Constructs an ArrayElementValueGen.
069     *
070     * @param type the type.
071     * @param elementValues the element values.
072     * @param cpool the constant pool generator.
073     */
074    public ArrayElementValueGen(final int type, final ElementValue[] elementValues, final ConstantPoolGen cpool) {
075        super(type, cpool);
076        if (type != ARRAY) {
077            throw new IllegalArgumentException("Only element values of type array can be built with this ctor - type specified: " + type);
078        }
079        this.evalues = Streams.of(elementValues).map(e -> copy(e, cpool, true)).collect(Collectors.toList());
080    }
081
082    /**
083     * Adds an element.
084     *
085     * @param gen the element value generator.
086     */
087    public void addElement(final ElementValueGen gen) {
088        evalues.add(gen);
089    }
090
091    @Override
092    public void dump(final DataOutputStream dos) throws IOException {
093        dos.writeByte(super.getElementValueType()); // u1 type of value (ARRAY == '[')
094        dos.writeShort(evalues.size());
095        for (final ElementValueGen element : evalues) {
096            element.dump(dos);
097        }
098    }
099
100    /**
101     * Return immutable variant of this ArrayElementValueGen.
102     *
103     * @return immutable variant of this ArrayElementValueGen.
104     */
105    @Override
106    public ElementValue getElementValue() {
107        final ElementValue[] immutableData = new ElementValue[evalues.size()];
108        int i = 0;
109        for (final ElementValueGen element : evalues) {
110            immutableData[i++] = element.getElementValue();
111        }
112        return new ArrayElementValue(super.getElementValueType(), immutableData, getConstantPool().getConstantPool());
113    }
114
115    /**
116     * Gets the element values.
117     *
118     * @return the element values.
119     */
120    public List<ElementValueGen> getElementValues() {
121        return evalues;
122    }
123
124    /**
125     * Gets the element values size.
126     *
127     * @return the element values size.
128     */
129    public int getElementValuesSize() {
130        return evalues.size();
131    }
132
133    @Override
134    public String stringifyValue() {
135        final StringBuilder sb = new StringBuilder();
136        sb.append("[");
137        String comma = "";
138        for (final ElementValueGen element : evalues) {
139            sb.append(comma);
140            comma = ",";
141            sb.append(element.stringifyValue());
142        }
143        sb.append("]");
144        return sb.toString();
145    }
146}