1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * https://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19 package org.apache.bcel.classfile;
20
21 import java.io.DataInput;
22 import java.io.DataInputStream;
23 import java.io.DataOutputStream;
24 import java.io.IOException;
25 import java.util.Arrays;
26
27 /**
28 * Abstract super class for fields and methods.
29 */
30 public abstract class FieldOrMethod extends AccessFlags implements Cloneable, Node {
31
32 /**
33 * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter.
34 */
35 @java.lang.Deprecated
36 protected int name_index; // Points to field name in constant pool
37
38 /**
39 * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter.
40 */
41 @java.lang.Deprecated
42 protected int signature_index; // Points to encoded signature
43
44 /**
45 * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter.
46 */
47 @java.lang.Deprecated
48 protected Attribute[] attributes; // Collection of attributes
49
50 /**
51 * @deprecated (since 6.0) will be removed (not needed)
52 */
53 @java.lang.Deprecated
54 protected int attributes_count; // No. of attributes
55
56 // @since 6.0
57 private AnnotationEntry[] annotationEntries; // annotations defined on the field or method
58
59 /**
60 * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter.
61 */
62 @java.lang.Deprecated
63 protected ConstantPool constant_pool;
64
65 private String signatureAttributeString;
66 private boolean searchedForSignatureAttribute;
67
68 FieldOrMethod() {
69 }
70
71 /**
72 * Constructs object from file stream.
73 *
74 * @param file Input stream.
75 * @param constantPool the constant pool.
76 * @throws IOException if an I/O error occurs.
77 */
78 protected FieldOrMethod(final DataInput file, final ConstantPool constantPool) throws IOException {
79 this(file.readUnsignedShort(), file.readUnsignedShort(), file.readUnsignedShort(), null, constantPool);
80 final int attributesCount = file.readUnsignedShort();
81 attributes = new Attribute[attributesCount];
82 for (int i = 0; i < attributesCount; i++) {
83 attributes[i] = Attribute.readAttribute(file, constantPool);
84 }
85 this.attributes_count = attributesCount; // init deprecated field
86 }
87
88 /**
89 * Constructs object from file stream.
90 *
91 * @param file Input stream.
92 * @param constantPool the constant pool.
93 * @throws IOException if an I/O error occurs.
94 * @deprecated (6.0) Use {@link #FieldOrMethod(java.io.DataInput, ConstantPool)} instead.
95 */
96 @java.lang.Deprecated
97 protected FieldOrMethod(final DataInputStream file, final ConstantPool constantPool) throws IOException {
98 this((DataInput) file, constantPool);
99 }
100
101 /**
102 * Initialize from another object. Note that both objects use the same references (shallow copy). Use clone() for a
103 * physical copy.
104 *
105 * @param c Source to copy.
106 */
107 protected FieldOrMethod(final FieldOrMethod c) {
108 this(c.getAccessFlags(), c.getNameIndex(), c.getSignatureIndex(), c.getAttributes(), c.getConstantPool());
109 }
110
111 /**
112 * Constructs a FieldOrMethod.
113 *
114 * @param accessFlags Access rights of method.
115 * @param nameIndex Points to field name in constant pool.
116 * @param signatureIndex Points to encoded signature.
117 * @param attributes Collection of attributes.
118 * @param constantPool Array of constants.
119 */
120 protected FieldOrMethod(final int accessFlags, final int nameIndex, final int signatureIndex, final Attribute[] attributes,
121 final ConstantPool constantPool) {
122 super(accessFlags);
123 this.name_index = nameIndex;
124 this.signature_index = signatureIndex;
125 this.constant_pool = constantPool;
126 setAttributes(attributes);
127 }
128
129 /**
130 * Creates a deep copy of this field.
131 *
132 * @param constantPool the constant pool.
133 * @return deep copy of this field.
134 */
135 protected FieldOrMethod copy_(final ConstantPool constantPool) {
136 try {
137 final FieldOrMethod c = (FieldOrMethod) clone();
138 c.constant_pool = constantPool;
139 c.attributes = new Attribute[attributes.length];
140 c.attributes_count = attributes_count; // init deprecated field
141 Arrays.setAll(c.attributes, i -> attributes[i].copy(constantPool));
142 return c;
143 } catch (final CloneNotSupportedException e) {
144 throw new UnsupportedOperationException(e);
145 }
146 }
147
148 /**
149 * Dumps object to file stream on binary format.
150 *
151 * @param file Output file stream.
152 * @throws IOException if an I/O error occurs.
153 */
154 public final void dump(final DataOutputStream file) throws IOException {
155 file.writeShort(super.getAccessFlags());
156 file.writeShort(name_index);
157 file.writeShort(signature_index);
158 file.writeShort(attributes_count);
159 for (final Attribute attribute : attributes) {
160 attribute.dump(file);
161 }
162 }
163
164 /**
165 * Gets annotations on the field or method.
166 *
167 * @return Annotations on the field or method.
168 * @since 6.0
169 */
170 public AnnotationEntry[] getAnnotationEntries() {
171 if (annotationEntries == null) {
172 annotationEntries = AnnotationEntry.createAnnotationEntries(getAttributes());
173 }
174
175 return annotationEntries;
176 }
177
178 /**
179 * Gets attribute for given tag.
180 *
181 * @param <T> the attribute type.
182 * @param tag the attribute tag.
183 * @return Attribute for given tag, null if not found.
184 * Refer to {@link org.apache.bcel.Const#ATTR_UNKNOWN} constants named ATTR_* for possible values.
185 * @since 6.10.0
186 */
187 @SuppressWarnings("unchecked")
188 public final <T extends Attribute> T getAttribute(final byte tag) {
189 for (final Attribute attribute : getAttributes()) {
190 if (attribute.getTag() == tag) {
191 return (T) attribute;
192 }
193 }
194 return null;
195 }
196
197 /**
198 * Gets the collection of object attributes.
199 *
200 * @return Collection of object attributes.
201 */
202 public final Attribute[] getAttributes() {
203 return attributes;
204 }
205
206 /**
207 * Gets the constant pool used by this object.
208 *
209 * @return Constant pool used by this object.
210 */
211 public final ConstantPool getConstantPool() {
212 return constant_pool;
213 }
214
215 /**
216 * Hunts for a signature attribute on the member and returns its contents. So where the 'regular' signature may be
217 * (Ljava/util/Vector;)V the signature attribute may in fact say 'Ljava/lang/Vector<Ljava/lang/String>;' Coded for
218 * performance - searches for the attribute only when requested - only searches for it once.
219 *
220 * @return the generic signature.
221 * @since 6.0
222 */
223 public final String getGenericSignature() {
224 if (!searchedForSignatureAttribute) {
225 boolean found = false;
226 for (int i = 0; !found && i < attributes.length; i++) {
227 if (attributes[i] instanceof Signature) {
228 signatureAttributeString = ((Signature) attributes[i]).getSignature();
229 found = true;
230 }
231 }
232 searchedForSignatureAttribute = true;
233 }
234 return signatureAttributeString;
235 }
236
237 /**
238 * Gets the name of object.
239 *
240 * @return Name of object, that is, method name or field name.
241 */
242 public final String getName() {
243 return constant_pool.getConstantUtf8(name_index).getBytes();
244 }
245
246 /**
247 * Gets the index in constant pool of object's name.
248 *
249 * @return Index in constant pool of object's name.
250 */
251 public final int getNameIndex() {
252 return name_index;
253 }
254
255 /**
256 * Gets the string representation of object's type signature.
257 *
258 * @return String representation of object's type signature (Java style).
259 */
260 public final String getSignature() {
261 return constant_pool.getConstantUtf8(signature_index).getBytes();
262 }
263
264 /**
265 * Gets the index in constant pool of field signature.
266 *
267 * @return Index in constant pool of field signature.
268 */
269 public final int getSignatureIndex() {
270 return signature_index;
271 }
272
273 /**
274 * Sets the collection of object attributes.
275 *
276 * @param attributes Collection of object attributes.
277 */
278 public final void setAttributes(final Attribute[] attributes) {
279 this.attributes = attributes != null ? attributes : Attribute.EMPTY_ARRAY;
280 this.attributes_count = this.attributes.length; // init deprecated field
281 }
282
283 /**
284 * Sets the constant pool to be used for this object.
285 *
286 * @param constantPool Constant pool to be used for this object.
287 */
288 public final void setConstantPool(final ConstantPool constantPool) {
289 this.constant_pool = constantPool;
290 }
291
292 /**
293 * Sets the index in constant pool of object's name.
294 *
295 * @param nameIndex Index in constant pool of object's name.
296 */
297 public final void setNameIndex(final int nameIndex) {
298 this.name_index = nameIndex;
299 }
300
301 /**
302 * Sets the index in constant pool of field signature.
303 *
304 * @param signatureIndex Index in constant pool of field signature.
305 */
306 public final void setSignatureIndex(final int signatureIndex) {
307 this.signature_index = signatureIndex;
308 }
309 }