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     * Construct 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     * Construct 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    protected FieldOrMethod(final FieldOrMethod c) {
102        this(c.getAccessFlags(), c.getNameIndex(), c.getSignatureIndex(), c.getAttributes(), c.getConstantPool());
103    }
104
105    /**
106     * @param accessFlags Access rights of method
107     * @param nameIndex Points to field name in constant pool
108     * @param signatureIndex Points to encoded signature
109     * @param attributes Collection of attributes
110     * @param constantPool Array of constants
111     */
112    protected FieldOrMethod(final int accessFlags, final int nameIndex, final int signatureIndex, final Attribute[] attributes,
113        final ConstantPool constantPool) {
114        super(accessFlags);
115        this.name_index = nameIndex;
116        this.signature_index = signatureIndex;
117        this.constant_pool = constantPool;
118        setAttributes(attributes);
119    }
120
121    /**
122     * @return deep copy of this field
123     */
124    protected FieldOrMethod copy_(final ConstantPool constantPool) {
125        try {
126            final FieldOrMethod c = (FieldOrMethod) clone();
127            c.constant_pool = constantPool;
128            c.attributes = new Attribute[attributes.length];
129            c.attributes_count = attributes_count; // init deprecated field
130            Arrays.setAll(c.attributes, i -> attributes[i].copy(constantPool));
131            return c;
132        } catch (final CloneNotSupportedException e) {
133            throw new IllegalStateException(e);
134        }
135    }
136
137    /**
138     * Dump object to file stream on binary format.
139     *
140     * @param file Output file stream
141     * @throws IOException if an I/O error occurs.
142     */
143    public final void dump(final DataOutputStream file) throws IOException {
144        file.writeShort(super.getAccessFlags());
145        file.writeShort(name_index);
146        file.writeShort(signature_index);
147        file.writeShort(attributes_count);
148        if (attributes != null) {
149            for (final Attribute attribute : attributes) {
150                attribute.dump(file);
151            }
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;
235        this.attributes_count = attributes != null ? attributes.length : 0; // 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}