    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.classfile;
    020
    021import java.io.DataInput;
    022import java.io.DataInputStream;
    023import java.io.DataOutputStream;
    024import java.io.IOException;
    025import java.util.Arrays;
    026
    027/**
    028 * Abstract super class for fields and methods.
    029 */
    030public abstract class FieldOrMethod extends AccessFlags implements Cloneable, Node {
    031
    032    /**
    033     * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
    034     */
    035    @java.lang.Deprecated
    036    protected int name_index; // Points to field name in constant pool
    037
    038    /**
    039     * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
    040     */
    041    @java.lang.Deprecated
    042    protected int signature_index; // Points to encoded signature
    043
    044    /**
    045     * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
    046     */
    047    @java.lang.Deprecated
    048    protected Attribute[] attributes; // Collection of attributes
    049
    050    /**
    051     * @deprecated (since 6.0) will be removed (not needed)
    052     */
    053    @java.lang.Deprecated
    054    protected int attributes_count; // No. of attributes
    055
    056    // @since 6.0
    057    private AnnotationEntry[] annotationEntries; // annotations defined on the field or method
    058
    059    /**
    060     * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
    061     */
    062    @java.lang.Deprecated
    063    protected ConstantPool constant_pool;
    064
    065    private String signatureAttributeString;
    066    private boolean searchedForSignatureAttribute;
    067
    068    FieldOrMethod() {
    069    }
    070
    071    /**
    072     * Constructs object from file stream.
    073     *
    074     * @param file Input stream
    075     * @throws IOException if an I/O error occurs.
    076     */
    077    protected FieldOrMethod(final DataInput file, final ConstantPool constantPool) throws IOException {
    078        this(file.readUnsignedShort(), file.readUnsignedShort(), file.readUnsignedShort(), null, constantPool);
    079        final int attributesCount = file.readUnsignedShort();
    080        attributes = new Attribute[attributesCount];
    081        for (int i = 0; i < attributesCount; i++) {
    082            attributes[i] = Attribute.readAttribute(file, constantPool);
    083        }
    084        this.attributes_count = attributesCount; // init deprecated field
    085    }
    086
    087    /**
    088     * Constructs object from file stream.
    089     *
    090     * @param file Input stream
    091     * @throws IOException if an I/O error occurs.
    092     * @deprecated (6.0) Use {@link #FieldOrMethod(java.io.DataInput, ConstantPool)} instead.
    093     */
    094    @java.lang.Deprecated
    095    protected FieldOrMethod(final DataInputStream file, final ConstantPool constantPool) throws IOException {
    096        this((DataInput) file, constantPool);
    097    }
    098
    099    /**
    100     * Initialize from another object. Note that both objects use the same references (shallow copy). Use clone() for a
    101     * physical copy.
    102     *
    103     * @param c Source to copy.
    104     */
    105    protected FieldOrMethod(final FieldOrMethod c) {
    106        this(c.getAccessFlags(), c.getNameIndex(), c.getSignatureIndex(), c.getAttributes(), c.getConstantPool());
    107    }
    108
    109    /**
    110     * @param accessFlags Access rights of method
    111     * @param nameIndex Points to field name in constant pool
    112     * @param signatureIndex Points to encoded signature
    113     * @param attributes Collection of attributes
    114     * @param constantPool Array of constants
    115     */
    116    protected FieldOrMethod(final int accessFlags, final int nameIndex, final int signatureIndex, final Attribute[] attributes,
    117        final ConstantPool constantPool) {
    118        super(accessFlags);
    119        this.name_index = nameIndex;
    120        this.signature_index = signatureIndex;
    121        this.constant_pool = constantPool;
    122        setAttributes(attributes);
    123    }
    124
    125    /**
    126     * @return deep copy of this field
    127     */
    128    protected FieldOrMethod copy_(final ConstantPool constantPool) {
    129        try {
    130            final FieldOrMethod c = (FieldOrMethod) clone();
    131            c.constant_pool = constantPool;
    132            c.attributes = new Attribute[attributes.length];
    133            c.attributes_count = attributes_count; // init deprecated field
    134            Arrays.setAll(c.attributes, i -> attributes[i].copy(constantPool));
    135            return c;
    136        } catch (final CloneNotSupportedException e) {
    137            throw new UnsupportedOperationException(e);
    138        }
    139    }
    140
    141    /**
    142     * Dump object to file stream on binary format.
    143     *
    144     * @param file Output file stream
    145     * @throws IOException if an I/O error occurs.
    146     */
    147    public final void dump(final DataOutputStream file) throws IOException {
    148        file.writeShort(super.getAccessFlags());
    149        file.writeShort(name_index);
    150        file.writeShort(signature_index);
    151        file.writeShort(attributes_count);
    152        for (final Attribute attribute : attributes) {
    153            attribute.dump(file);
    154        }
    155    }
    156
    157    /**
    158     * @return Annotations on the field or method
    159     * @since 6.0
    160     */
    161    public AnnotationEntry[] getAnnotationEntries() {
    162        if (annotationEntries == null) {
    163            annotationEntries = AnnotationEntry.createAnnotationEntries(getAttributes());
    164        }
    165
    166        return annotationEntries;
    167    }
    168
    169    /**
    170     * Gets attribute for given tag.
    171     * @return Attribute for given tag, null if not found.
    172     * Refer to {@link org.apache.bcel.Const#ATTR_UNKNOWN} constants named ATTR_* for possible values.
    173     * @since 6.10.0
    174     */
    175    @SuppressWarnings("unchecked")
    176    public final <T extends Attribute> T getAttribute(final byte tag) {
    177        for (final Attribute attribute : getAttributes()) {
    178            if (attribute.getTag() == tag) {
    179                return (T) attribute;
    180            }
    181        }
    182        return null;
    183    }
    184
    185    /**
    186     * @return Collection of object attributes.
    187     */
    188    public final Attribute[] getAttributes() {
    189        return attributes;
    190    }
    191
    192    /**
    193     * @return Constant pool used by this object.
    194     */
    195    public final ConstantPool getConstantPool() {
    196        return constant_pool;
    197    }
    198
    199    /**
    200     * Hunts for a signature attribute on the member and returns its contents. So where the 'regular' signature may be
    201     * (Ljava/util/Vector;)V the signature attribute may in fact say 'Ljava/lang/Vector&lt;Ljava/lang/String&gt;;' Coded for
    202     * performance - searches for the attribute only when requested - only searches for it once.
    203     *
    204     * @since 6.0
    205     */
    206    public final String getGenericSignature() {
    207        if (!searchedForSignatureAttribute) {
    208            boolean found = false;
    209            for (int i = 0; !found && i < attributes.length; i++) {
    210                if (attributes[i] instanceof Signature) {
    211                    signatureAttributeString = ((Signature) attributes[i]).getSignature();
    212                    found = true;
    213                }
    214            }
    215            searchedForSignatureAttribute = true;
    216        }
    217        return signatureAttributeString;
    218    }
    219
    220    /**
    221     * @return Name of object, i.e., method name or field name
    222     */
    223    public final String getName() {
    224        return constant_pool.getConstantUtf8(name_index).getBytes();
    225    }
    226
    227    /**
    228     * @return Index in constant pool of object's name.
    229     */
    230    public final int getNameIndex() {
    231        return name_index;
    232    }
    233
    234    /**
    235     * @return String representation of object's type signature (Java style)
    236     */
    237    public final String getSignature() {
    238        return constant_pool.getConstantUtf8(signature_index).getBytes();
    239    }
    240
    241    /**
    242     * @return Index in constant pool of field signature.
    243     */
    244    public final int getSignatureIndex() {
    245        return signature_index;
    246    }
    247
    248    /**
    249     * @param attributes Collection of object attributes.
    250     */
    251    public final void setAttributes(final Attribute[] attributes) {
    252        this.attributes = attributes != null ? attributes : Attribute.EMPTY_ARRAY;
    253        this.attributes_count = this.attributes.length; // init deprecated field
    254    }
    255
    256    /**
    257     * @param constantPool Constant pool to be used for this object.
    258     */
    259    public final void setConstantPool(final ConstantPool constantPool) {
    260        this.constant_pool = constantPool;
    261    }
    262
    263    /**
    264     * @param nameIndex Index in constant pool of object's name.
    265     */
    266    public final void setNameIndex(final int nameIndex) {
    267        this.name_index = nameIndex;
    268    }
    269
    270    /**
    271     * @param signatureIndex Index in constant pool of field signature.
    272     */
    273    public final void setSignatureIndex(final int signatureIndex) {
    274        this.signature_index = signatureIndex;
    275    }
    276}