View Javadoc
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       * @throws IOException if an I/O error occurs.
76       */
77      protected FieldOrMethod(final DataInput file, final ConstantPool constantPool) throws IOException {
78          this(file.readUnsignedShort(), file.readUnsignedShort(), file.readUnsignedShort(), null, constantPool);
79          final int attributesCount = file.readUnsignedShort();
80          attributes = new Attribute[attributesCount];
81          for (int i = 0; i < attributesCount; i++) {
82              attributes[i] = Attribute.readAttribute(file, constantPool);
83          }
84          this.attributes_count = attributesCount; // init deprecated field
85      }
86  
87      /**
88       * Constructs object from file stream.
89       *
90       * @param file Input stream
91       * @throws IOException if an I/O error occurs.
92       * @deprecated (6.0) Use {@link #FieldOrMethod(java.io.DataInput, ConstantPool)} instead.
93       */
94      @java.lang.Deprecated
95      protected FieldOrMethod(final DataInputStream file, final ConstantPool constantPool) throws IOException {
96          this((DataInput) file, constantPool);
97      }
98  
99      /**
100      * Initialize from another object. Note that both objects use the same references (shallow copy). Use clone() for a
101      * physical copy.
102      *
103      * @param c Source to copy.
104      */
105     protected FieldOrMethod(final FieldOrMethod c) {
106         this(c.getAccessFlags(), c.getNameIndex(), c.getSignatureIndex(), c.getAttributes(), c.getConstantPool());
107     }
108 
109     /**
110      * @param accessFlags Access rights of method
111      * @param nameIndex Points to field name in constant pool
112      * @param signatureIndex Points to encoded signature
113      * @param attributes Collection of attributes
114      * @param constantPool Array of constants
115      */
116     protected FieldOrMethod(final int accessFlags, final int nameIndex, final int signatureIndex, final Attribute[] attributes,
117         final ConstantPool constantPool) {
118         super(accessFlags);
119         this.name_index = nameIndex;
120         this.signature_index = signatureIndex;
121         this.constant_pool = constantPool;
122         setAttributes(attributes);
123     }
124 
125     /**
126      * @return deep copy of this field
127      */
128     protected FieldOrMethod copy_(final ConstantPool constantPool) {
129         try {
130             final FieldOrMethod c = (FieldOrMethod) clone();
131             c.constant_pool = constantPool;
132             c.attributes = new Attribute[attributes.length];
133             c.attributes_count = attributes_count; // init deprecated field
134             Arrays.setAll(c.attributes, i -> attributes[i].copy(constantPool));
135             return c;
136         } catch (final CloneNotSupportedException e) {
137             throw new UnsupportedOperationException(e);
138         }
139     }
140 
141     /**
142      * Dump object to file stream on binary format.
143      *
144      * @param file Output file stream
145      * @throws IOException if an I/O error occurs.
146      */
147     public final void dump(final DataOutputStream file) throws IOException {
148         file.writeShort(super.getAccessFlags());
149         file.writeShort(name_index);
150         file.writeShort(signature_index);
151         file.writeShort(attributes_count);
152         for (final Attribute attribute : attributes) {
153             attribute.dump(file);
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      * Gets attribute for given tag.
171      * @return Attribute for given tag, null if not found.
172      * Refer to {@link org.apache.bcel.Const#ATTR_UNKNOWN} constants named ATTR_* for possible values.
173      * @since 6.10.0
174      */
175     @SuppressWarnings("unchecked")
176     public final <T extends Attribute> T getAttribute(final byte tag) {
177         for (final Attribute attribute : getAttributes()) {
178             if (attribute.getTag() == tag) {
179                 return (T) attribute;
180             }
181         }
182         return null;
183     }
184 
185     /**
186      * @return Collection of object attributes.
187      */
188     public final Attribute[] getAttributes() {
189         return attributes;
190     }
191 
192     /**
193      * @return Constant pool used by this object.
194      */
195     public final ConstantPool getConstantPool() {
196         return constant_pool;
197     }
198 
199     /**
200      * Hunts for a signature attribute on the member and returns its contents. So where the 'regular' signature may be
201      * (Ljava/util/Vector;)V the signature attribute may in fact say 'Ljava/lang/Vector&lt;Ljava/lang/String&gt;;' Coded for
202      * performance - searches for the attribute only when requested - only searches for it once.
203      *
204      * @since 6.0
205      */
206     public final String getGenericSignature() {
207         if (!searchedForSignatureAttribute) {
208             boolean found = false;
209             for (int i = 0; !found && i < attributes.length; i++) {
210                 if (attributes[i] instanceof Signature) {
211                     signatureAttributeString = ((Signature) attributes[i]).getSignature();
212                     found = true;
213                 }
214             }
215             searchedForSignatureAttribute = true;
216         }
217         return signatureAttributeString;
218     }
219 
220     /**
221      * @return Name of object, i.e., method name or field name
222      */
223     public final String getName() {
224         return constant_pool.getConstantUtf8(name_index).getBytes();
225     }
226 
227     /**
228      * @return Index in constant pool of object's name.
229      */
230     public final int getNameIndex() {
231         return name_index;
232     }
233 
234     /**
235      * @return String representation of object's type signature (Java style)
236      */
237     public final String getSignature() {
238         return constant_pool.getConstantUtf8(signature_index).getBytes();
239     }
240 
241     /**
242      * @return Index in constant pool of field signature.
243      */
244     public final int getSignatureIndex() {
245         return signature_index;
246     }
247 
248     /**
249      * @param attributes Collection of object attributes.
250      */
251     public final void setAttributes(final Attribute[] attributes) {
252         this.attributes = attributes != null ? attributes : Attribute.EMPTY_ARRAY;
253         this.attributes_count = this.attributes.length; // init deprecated field
254     }
255 
256     /**
257      * @param constantPool Constant pool to be used for this object.
258      */
259     public final void setConstantPool(final ConstantPool constantPool) {
260         this.constant_pool = constantPool;
261     }
262 
263     /**
264      * @param nameIndex Index in constant pool of object's name.
265      */
266     public final void setNameIndex(final int nameIndex) {
267         this.name_index = nameIndex;
268     }
269 
270     /**
271      * @param signatureIndex Index in constant pool of field signature.
272      */
273     public final void setSignatureIndex(final int signatureIndex) {
274         this.signature_index = signatureIndex;
275     }
276 }