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