1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.bcel.classfile;
18
19 import java.io.DataInput;
20 import java.io.DataInputStream;
21 import java.io.DataOutputStream;
22 import java.io.IOException;
23 import java.util.Arrays;
24
25 /**
26 * Abstract super class for fields and methods.
27 */
28 public abstract class FieldOrMethod extends AccessFlags implements Cloneable, Node {
29
30 /**
31 * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
32 */
33 @java.lang.Deprecated
34 protected int name_index; // Points to field name in constant pool
35
36 /**
37 * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
38 */
39 @java.lang.Deprecated
40 protected int signature_index; // Points to encoded signature
41
42 /**
43 * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
44 */
45 @java.lang.Deprecated
46 protected Attribute[] attributes; // Collection of attributes
47
48 /**
49 * @deprecated (since 6.0) will be removed (not needed)
50 */
51 @java.lang.Deprecated
52 protected int attributes_count; // No. of attributes
53
54 // @since 6.0
55 private AnnotationEntry[] annotationEntries; // annotations defined on the field or method
56
57 /**
58 * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
59 */
60 @java.lang.Deprecated
61 protected ConstantPool constant_pool;
62
63 private String signatureAttributeString;
64 private boolean searchedForSignatureAttribute;
65
66 FieldOrMethod() {
67 }
68
69 /**
70 * Constructs object from file stream.
71 *
72 * @param file Input stream
73 * @throws IOException if an I/O error occurs.
74 */
75 protected FieldOrMethod(final DataInput file, final ConstantPool constantPool) throws IOException {
76 this(file.readUnsignedShort(), file.readUnsignedShort(), file.readUnsignedShort(), null, constantPool);
77 final int attributesCount = file.readUnsignedShort();
78 attributes = new Attribute[attributesCount];
79 for (int i = 0; i < attributesCount; i++) {
80 attributes[i] = Attribute.readAttribute(file, constantPool);
81 }
82 this.attributes_count = attributesCount; // init deprecated field
83 }
84
85 /**
86 * Constructs object from file stream.
87 *
88 * @param file Input stream
89 * @throws IOException if an I/O error occurs.
90 * @deprecated (6.0) Use {@link #FieldOrMethod(java.io.DataInput, ConstantPool)} instead.
91 */
92 @java.lang.Deprecated
93 protected FieldOrMethod(final DataInputStream file, final ConstantPool constantPool) throws IOException {
94 this((DataInput) file, constantPool);
95 }
96
97 /**
98 * Initialize from another object. Note that both objects use the same references (shallow copy). Use clone() for a
99 * 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 * Gets attribute for given tag.
169 * @return Attribute for given tag, null if not found.
170 * Refer to {@link org.apache.bcel.Const#ATTR_UNKNOWN} constants named ATTR_* for possible values.
171 * @since 6.10.0
172 */
173 @SuppressWarnings("unchecked")
174 public final <T extends Attribute> T getAttribute(final byte tag) {
175 for (final Attribute attribute : getAttributes()) {
176 if (attribute.getTag() == tag) {
177 return (T) attribute;
178 }
179 }
180 return null;
181 }
182
183 /**
184 * @return Collection of object attributes.
185 */
186 public final Attribute[] getAttributes() {
187 return attributes;
188 }
189
190 /**
191 * @return Constant pool used by this object.
192 */
193 public final ConstantPool getConstantPool() {
194 return constant_pool;
195 }
196
197 /**
198 * Hunts for a signature attribute on the member and returns its contents. So where the 'regular' signature may be
199 * (Ljava/util/Vector;)V the signature attribute may in fact say 'Ljava/lang/Vector<Ljava/lang/String>;' Coded for
200 * performance - searches for the attribute only when requested - only searches for it once.
201 *
202 * @since 6.0
203 */
204 public final String getGenericSignature() {
205 if (!searchedForSignatureAttribute) {
206 boolean found = false;
207 for (int i = 0; !found && i < attributes.length; i++) {
208 if (attributes[i] instanceof Signature) {
209 signatureAttributeString = ((Signature) attributes[i]).getSignature();
210 found = true;
211 }
212 }
213 searchedForSignatureAttribute = true;
214 }
215 return signatureAttributeString;
216 }
217
218 /**
219 * @return Name of object, i.e., method name or field name
220 */
221 public final String getName() {
222 return constant_pool.getConstantUtf8(name_index).getBytes();
223 }
224
225 /**
226 * @return Index in constant pool of object's name.
227 */
228 public final int getNameIndex() {
229 return name_index;
230 }
231
232 /**
233 * @return String representation of object's type signature (Java style)
234 */
235 public final String getSignature() {
236 return constant_pool.getConstantUtf8(signature_index).getBytes();
237 }
238
239 /**
240 * @return Index in constant pool of field signature.
241 */
242 public final int getSignatureIndex() {
243 return signature_index;
244 }
245
246 /**
247 * @param attributes Collection of object attributes.
248 */
249 public final void setAttributes(final Attribute[] attributes) {
250 this.attributes = attributes != null ? attributes : Attribute.EMPTY_ARRAY;
251 this.attributes_count = this.attributes.length; // init deprecated field
252 }
253
254 /**
255 * @param constantPool Constant pool to be used for this object.
256 */
257 public final void setConstantPool(final ConstantPool constantPool) {
258 this.constant_pool = constantPool;
259 }
260
261 /**
262 * @param nameIndex Index in constant pool of object's name.
263 */
264 public final void setNameIndex(final int nameIndex) {
265 this.name_index = nameIndex;
266 }
267
268 /**
269 * @param signatureIndex Index in constant pool of field signature.
270 */
271 public final void setSignatureIndex(final int signatureIndex) {
272 this.signature_index = signatureIndex;
273 }
274 }