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