    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     * @param constantPool the constant pool.
    076     * @throws IOException if an I/O error occurs.
    077     */
    078    protected FieldOrMethod(final DataInput file, final ConstantPool constantPool) throws IOException {
    079        this(file.readUnsignedShort(), file.readUnsignedShort(), file.readUnsignedShort(), null, constantPool);
    080        final int attributesCount = file.readUnsignedShort();
    081        attributes = new Attribute[attributesCount];
    082        for (int i = 0; i < attributesCount; i++) {
    083            attributes[i] = Attribute.readAttribute(file, constantPool);
    084        }
    085        this.attributes_count = attributesCount; // init deprecated field
    086    }
    087
    088    /**
    089     * Constructs object from file stream.
    090     *
    091     * @param file Input stream.
    092     * @param constantPool the constant pool.
    093     * @throws IOException if an I/O error occurs.
    094     * @deprecated (6.0) Use {@link #FieldOrMethod(java.io.DataInput, ConstantPool)} instead.
    095     */
    096    @java.lang.Deprecated
    097    protected FieldOrMethod(final DataInputStream file, final ConstantPool constantPool) throws IOException {
    098        this((DataInput) file, constantPool);
    099    }
    100
    101    /**
    102     * Initialize from another object. Note that both objects use the same references (shallow copy). Use clone() for a
    103     * physical copy.
    104     *
    105     * @param c Source to copy.
    106     */
    107    protected FieldOrMethod(final FieldOrMethod c) {
    108        this(c.getAccessFlags(), c.getNameIndex(), c.getSignatureIndex(), c.getAttributes(), c.getConstantPool());
    109    }
    110
    111    /**
    112     * Constructs a FieldOrMethod.
    113     *
    114     * @param accessFlags Access rights of method.
    115     * @param nameIndex Points to field name in constant pool.
    116     * @param signatureIndex Points to encoded signature.
    117     * @param attributes Collection of attributes.
    118     * @param constantPool Array of constants.
    119     */
    120    protected FieldOrMethod(final int accessFlags, final int nameIndex, final int signatureIndex, final Attribute[] attributes,
    121        final ConstantPool constantPool) {
    122        super(accessFlags);
    123        this.name_index = nameIndex;
    124        this.signature_index = signatureIndex;
    125        this.constant_pool = constantPool;
    126        setAttributes(attributes);
    127    }
    128
    129    /**
    130     * Creates a deep copy of this field.
    131     *
    132     * @param constantPool the constant pool.
    133     * @return deep copy of this field.
    134     */
    135    protected FieldOrMethod copy_(final ConstantPool constantPool) {
    136        try {
    137            final FieldOrMethod c = (FieldOrMethod) clone();
    138            c.constant_pool = constantPool;
    139            c.attributes = new Attribute[attributes.length];
    140            c.attributes_count = attributes_count; // init deprecated field
    141            Arrays.setAll(c.attributes, i -> attributes[i].copy(constantPool));
    142            return c;
    143        } catch (final CloneNotSupportedException e) {
    144            throw new UnsupportedOperationException(e);
    145        }
    146    }
    147
    148    /**
    149     * Dumps object to file stream on binary format.
    150     *
    151     * @param file Output file stream.
    152     * @throws IOException if an I/O error occurs.
    153     */
    154    public final void dump(final DataOutputStream file) throws IOException {
    155        file.writeShort(super.getAccessFlags());
    156        file.writeShort(name_index);
    157        file.writeShort(signature_index);
    158        file.writeShort(attributes_count);
    159        for (final Attribute attribute : attributes) {
    160            attribute.dump(file);
    161        }
    162    }
    163
    164    /**
    165     * Gets annotations on the field or method.
    166     *
    167     * @return Annotations on the field or method.
    168     * @since 6.0
    169     */
    170    public AnnotationEntry[] getAnnotationEntries() {
    171        if (annotationEntries == null) {
    172            annotationEntries = AnnotationEntry.createAnnotationEntries(getAttributes());
    173        }
    174
    175        return annotationEntries;
    176    }
    177
    178    /**
    179     * Gets attribute for given tag.
    180     *
    181     * @param <T> the attribute type.
    182     * @param tag the attribute tag.
    183     * @return Attribute for given tag, null if not found.
    184     * Refer to {@link org.apache.bcel.Const#ATTR_UNKNOWN} constants named ATTR_* for possible values.
    185     * @since 6.10.0
    186     */
    187    @SuppressWarnings("unchecked")
    188    public final <T extends Attribute> T getAttribute(final byte tag) {
    189        for (final Attribute attribute : getAttributes()) {
    190            if (attribute.getTag() == tag) {
    191                return (T) attribute;
    192            }
    193        }
    194        return null;
    195    }
    196
    197    /**
    198     * Gets the collection of object attributes.
    199     *
    200     * @return Collection of object attributes.
    201     */
    202    public final Attribute[] getAttributes() {
    203        return attributes;
    204    }
    205
    206    /**
    207     * Gets the constant pool used by this object.
    208     *
    209     * @return Constant pool used by this object.
    210     */
    211    public final ConstantPool getConstantPool() {
    212        return constant_pool;
    213    }
    214
    215    /**
    216     * Hunts for a signature attribute on the member and returns its contents. So where the 'regular' signature may be
    217     * (Ljava/util/Vector;)V the signature attribute may in fact say 'Ljava/lang/Vector&lt;Ljava/lang/String&gt;;' Coded for
    218     * performance - searches for the attribute only when requested - only searches for it once.
    219     *
    220     * @return the generic signature.
    221     * @since 6.0
    222     */
    223    public final String getGenericSignature() {
    224        if (!searchedForSignatureAttribute) {
    225            boolean found = false;
    226            for (int i = 0; !found && i < attributes.length; i++) {
    227                if (attributes[i] instanceof Signature) {
    228                    signatureAttributeString = ((Signature) attributes[i]).getSignature();
    229                    found = true;
    230                }
    231            }
    232            searchedForSignatureAttribute = true;
    233        }
    234        return signatureAttributeString;
    235    }
    236
    237    /**
    238     * Gets the name of object.
    239     *
    240     * @return Name of object, that is, method name or field name.
    241     */
    242    public final String getName() {
    243        return constant_pool.getConstantUtf8(name_index).getBytes();
    244    }
    245
    246    /**
    247     * Gets the index in constant pool of object's name.
    248     *
    249     * @return Index in constant pool of object's name.
    250     */
    251    public final int getNameIndex() {
    252        return name_index;
    253    }
    254
    255    /**
    256     * Gets the string representation of object's type signature.
    257     *
    258     * @return String representation of object's type signature (Java style).
    259     */
    260    public final String getSignature() {
    261        return constant_pool.getConstantUtf8(signature_index).getBytes();
    262    }
    263
    264    /**
    265     * Gets the index in constant pool of field signature.
    266     *
    267     * @return Index in constant pool of field signature.
    268     */
    269    public final int getSignatureIndex() {
    270        return signature_index;
    271    }
    272
    273    /**
    274     * Sets the collection of object attributes.
    275     *
    276     * @param attributes Collection of object attributes.
    277     */
    278    public final void setAttributes(final Attribute[] attributes) {
    279        this.attributes = attributes != null ? attributes : Attribute.EMPTY_ARRAY;
    280        this.attributes_count = this.attributes.length; // init deprecated field
    281    }
    282
    283    /**
    284     * Sets the constant pool to be used for this object.
    285     *
    286     * @param constantPool Constant pool to be used for this object.
    287     */
    288    public final void setConstantPool(final ConstantPool constantPool) {
    289        this.constant_pool = constantPool;
    290    }
    291
    292    /**
    293     * Sets the index in constant pool of object's name.
    294     *
    295     * @param nameIndex Index in constant pool of object's name.
    296     */
    297    public final void setNameIndex(final int nameIndex) {
    298        this.name_index = nameIndex;
    299    }
    300
    301    /**
    302     * Sets the index in constant pool of field signature.
    303     *
    304     * @param signatureIndex Index in constant pool of field signature.
    305     */
    306    public final void setSignatureIndex(final int signatureIndex) {
    307        this.signature_index = signatureIndex;
    308    }
    309}