    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}