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}