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