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}