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 *
017 */
018package org.apache.bcel.classfile;
019
020import java.io.DataInput;
021import java.io.DataInputStream;
022import java.io.DataOutputStream;
023import java.io.IOException;
024import java.util.Arrays;
025
026/**
027 * Abstract super class for fields and methods.
028 *
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     * Construct 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 attributes_count = file.readUnsignedShort();
080        attributes = new Attribute[attributes_count];
081        for (int i = 0; i < attributes_count; i++) {
082            attributes[i] = Attribute.readAttribute(file, constantPool);
083        }
084        this.attributes_count = attributes_count; // init deprecated field
085    }
086
087    /**
088     * Construct 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    protected FieldOrMethod(final FieldOrMethod c) {
104        this(c.getAccessFlags(), c.getNameIndex(), c.getSignatureIndex(), c.getAttributes(), c.getConstantPool());
105    }
106
107    /**
108     * @param access_flags Access rights of method
109     * @param name_index Points to field name in constant pool
110     * @param signature_index Points to encoded signature
111     * @param attributes Collection of attributes
112     * @param constant_pool Array of constants
113     */
114    protected FieldOrMethod(final int access_flags, final int name_index, final int signature_index, final Attribute[] attributes,
115        final ConstantPool constant_pool) {
116        super(access_flags);
117        this.name_index = name_index;
118        this.signature_index = signature_index;
119        this.constant_pool = constant_pool;
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 = constant_pool;
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(constant_pool));
133            return c;
134        } catch (final CloneNotSupportedException e) {
135            throw new IllegalStateException(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 constant_pool Constant pool to be used for this object.
242     */
243    public final void setConstantPool(final ConstantPool constant_pool) {
244        this.constant_pool = constant_pool;
245    }
246
247    /**
248     * @param name_index Index in constant pool of object's name.
249     */
250    public final void setNameIndex(final int name_index) {
251        this.name_index = name_index;
252    }
253
254    /**
255     * @param signature_index Index in constant pool of field signature.
256     */
257    public final void setSignatureIndex(final int signature_index) {
258        this.signature_index = signature_index;
259    }
260}