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        if (attributes != null) {
151            for (final Attribute attribute : attributes) {
152                attribute.dump(file);
153            }
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     * @return Collection of object attributes.
171     */
172    public final Attribute[] getAttributes() {
173        return attributes;
174    }
175
176    /**
177     * @return Constant pool used by this object.
178     */
179    public final ConstantPool getConstantPool() {
180        return constant_pool;
181    }
182
183    /**
184     * Hunts for a signature attribute on the member and returns its contents. So where the 'regular' signature may be
185     * (Ljava/util/Vector;)V the signature attribute may in fact say 'Ljava/lang/Vector&lt;Ljava/lang/String&gt;;' Coded for
186     * performance - searches for the attribute only when requested - only searches for it once.
187     *
188     * @since 6.0
189     */
190    public final String getGenericSignature() {
191        if (!searchedForSignatureAttribute) {
192            boolean found = false;
193            for (int i = 0; !found && i < attributes.length; i++) {
194                if (attributes[i] instanceof Signature) {
195                    signatureAttributeString = ((Signature) attributes[i]).getSignature();
196                    found = true;
197                }
198            }
199            searchedForSignatureAttribute = true;
200        }
201        return signatureAttributeString;
202    }
203
204    /**
205     * @return Name of object, i.e., method name or field name
206     */
207    public final String getName() {
208        return constant_pool.getConstantUtf8(name_index).getBytes();
209    }
210
211    /**
212     * @return Index in constant pool of object's name.
213     */
214    public final int getNameIndex() {
215        return name_index;
216    }
217
218    /**
219     * @return String representation of object's type signature (Java style)
220     */
221    public final String getSignature() {
222        return constant_pool.getConstantUtf8(signature_index).getBytes();
223    }
224
225    /**
226     * @return Index in constant pool of field signature.
227     */
228    public final int getSignatureIndex() {
229        return signature_index;
230    }
231
232    /**
233     * @param attributes Collection of object attributes.
234     */
235    public final void setAttributes(final Attribute[] attributes) {
236        this.attributes = attributes;
237        this.attributes_count = attributes != null ? attributes.length : 0; // init deprecated field
238    }
239
240    /**
241     * @param constantPool Constant pool to be used for this object.
242     */
243    public final void setConstantPool(final ConstantPool constantPool) {
244        this.constant_pool = constantPool;
245    }
246
247    /**
248     * @param nameIndex Index in constant pool of object's name.
249     */
250    public final void setNameIndex(final int nameIndex) {
251        this.name_index = nameIndex;
252    }
253
254    /**
255     * @param signatureIndex Index in constant pool of field signature.
256     */
257    public final void setSignatureIndex(final int signatureIndex) {
258        this.signature_index = signatureIndex;
259    }
260}