View Javadoc
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&lt;Ljava/lang/String&gt;;' 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 }