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 *
017 */
018 package org.apache.bcel.classfile;
019
020 import java.io.DataInputStream;
021 import java.io.DataOutputStream;
022 import java.io.IOException;
023 import java.util.ArrayList;
024 import java.util.List;
025 import org.apache.bcel.Constants;
026 import org.apache.bcel.classfile.Attribute;
027 import org.apache.bcel.classfile.Signature;
028
029 /**
030 * Abstract super class for fields and methods.
031 *
032 * @version $Id: FieldOrMethod.java 1149459 2011-07-22 04:34:27Z dbrosius $
033 * @author <A HREF="mailto:m.dahm@gmx.de">M. Dahm</A>
034 */
035 public abstract class FieldOrMethod extends AccessFlags implements Cloneable, Node {
036
037 private static final long serialVersionUID = -1833306330869469714L;
038 protected int name_index; // Points to field name in constant pool
039 protected int signature_index; // Points to encoded signature
040 protected int attributes_count; // No. of attributes
041 protected Attribute[] attributes; // Collection of attributes
042 protected AnnotationEntry[] annotationEntries; // annotations defined on the field or method
043 protected ConstantPool constant_pool;
044
045 private String signatureAttributeString = null;
046 private boolean searchedForSignatureAttribute = false;
047
048
049 // Annotations are collected from certain attributes, don't do it more than necessary!
050 private boolean annotationsOutOfDate = true;
051
052 FieldOrMethod() {
053 }
054
055
056 /**
057 * Initialize from another object. Note that both objects use the same
058 * references (shallow copy). Use clone() for a physical copy.
059 */
060 protected FieldOrMethod(FieldOrMethod c) {
061 this(c.getAccessFlags(), c.getNameIndex(), c.getSignatureIndex(), c.getAttributes(), c
062 .getConstantPool());
063 }
064
065
066 /**
067 * Construct object from file stream.
068 * @param file Input stream
069 * @throws IOException
070 * @throws ClassFormatException
071 */
072 protected FieldOrMethod(DataInputStream file, ConstantPool constant_pool) throws IOException,
073 ClassFormatException {
074 this(file.readUnsignedShort(), file.readUnsignedShort(), file.readUnsignedShort(), null,
075 constant_pool);
076 attributes_count = file.readUnsignedShort();
077 attributes = new Attribute[attributes_count];
078 for (int i = 0; i < attributes_count; i++) {
079 attributes[i] = Attribute.readAttribute(file, constant_pool);
080 }
081 }
082
083
084 /**
085 * @param access_flags Access rights of method
086 * @param name_index Points to field name in constant pool
087 * @param signature_index Points to encoded signature
088 * @param attributes Collection of attributes
089 * @param constant_pool Array of constants
090 */
091 protected FieldOrMethod(int access_flags, int name_index, int signature_index,
092 Attribute[] attributes, ConstantPool constant_pool) {
093 this.access_flags = access_flags;
094 this.name_index = name_index;
095 this.signature_index = signature_index;
096 this.constant_pool = constant_pool;
097 setAttributes(attributes);
098 }
099
100
101 /**
102 * Dump object to file stream on binary format.
103 *
104 * @param file Output file stream
105 * @throws IOException
106 */
107 public final void dump( DataOutputStream file ) throws IOException {
108 file.writeShort(access_flags);
109 file.writeShort(name_index);
110 file.writeShort(signature_index);
111 file.writeShort(attributes_count);
112 for (int i = 0; i < attributes_count; i++) {
113 attributes[i].dump(file);
114 }
115 }
116
117
118 /**
119 * @return Collection of object attributes.
120 */
121 public final Attribute[] getAttributes() {
122 return attributes;
123 }
124
125
126 /**
127 * @param attributes Collection of object attributes.
128 */
129 public final void setAttributes( Attribute[] attributes ) {
130 this.attributes = attributes;
131 attributes_count = (attributes == null) ? 0 : attributes.length;
132 }
133
134
135 /**
136 * @return Constant pool used by this object.
137 */
138 public final ConstantPool getConstantPool() {
139 return constant_pool;
140 }
141
142
143 /**
144 * @param constant_pool Constant pool to be used for this object.
145 */
146 public final void setConstantPool( ConstantPool constant_pool ) {
147 this.constant_pool = constant_pool;
148 }
149
150
151 /**
152 * @return Index in constant pool of object's name.
153 */
154 public final int getNameIndex() {
155 return name_index;
156 }
157
158
159 /**
160 * @param name_index Index in constant pool of object's name.
161 */
162 public final void setNameIndex( int name_index ) {
163 this.name_index = name_index;
164 }
165
166
167 /**
168 * @return Index in constant pool of field signature.
169 */
170 public final int getSignatureIndex() {
171 return signature_index;
172 }
173
174
175 /**
176 * @param signature_index Index in constant pool of field signature.
177 */
178 public final void setSignatureIndex( int signature_index ) {
179 this.signature_index = signature_index;
180 }
181
182
183 /**
184 * @return Name of object, i.e., method name or field name
185 */
186 public final String getName() {
187 ConstantUtf8 c;
188 c = (ConstantUtf8) constant_pool.getConstant(name_index, Constants.CONSTANT_Utf8);
189 return c.getBytes();
190 }
191
192
193 /**
194 * @return String representation of object's type signature (java style)
195 */
196 public final String getSignature() {
197 ConstantUtf8 c;
198 c = (ConstantUtf8) constant_pool.getConstant(signature_index, Constants.CONSTANT_Utf8);
199 return c.getBytes();
200 }
201
202
203 /**
204 * @return deep copy of this field
205 */
206 protected FieldOrMethod copy_( ConstantPool _constant_pool ) {
207 FieldOrMethod c = null;
208
209 try {
210 c = (FieldOrMethod)clone();
211 } catch(CloneNotSupportedException e) {}
212
213 c.constant_pool = constant_pool;
214 c.attributes = new Attribute[attributes_count];
215
216 for(int i=0; i < attributes_count; i++)
217 c.attributes[i] = attributes[i].copy(constant_pool);
218
219 return c;
220 }
221
222 /**
223 * Ensure we have unpacked any attributes that contain annotations.
224 * We don't remove these annotation attributes from the attributes list, they
225 * remain there.
226 */
227 private void ensureAnnotationsUpToDate()
228 {
229 if (annotationsOutOfDate)
230 {
231 // Find attributes that contain annotation data
232 Attribute[] attrs = getAttributes();
233 List<AnnotationEntry> accumulatedAnnotations = new ArrayList<AnnotationEntry>();
234 for (int i = 0; i < attrs.length; i++)
235 {
236 Attribute attribute = attrs[i];
237 if (attribute instanceof Annotations)
238 {
239 Annotations annotations = (Annotations) attribute;
240 for (int j = 0; j < annotations.getAnnotationEntries().length; j++)
241 {
242 accumulatedAnnotations.add(annotations
243 .getAnnotationEntries()[j]);
244 }
245 }
246 }
247 annotationEntries = accumulatedAnnotations
248 .toArray(new AnnotationEntry[accumulatedAnnotations.size()]);
249 annotationsOutOfDate = false;
250 }
251 }
252
253 public AnnotationEntry[] getAnnotationEntries()
254 {
255 ensureAnnotationsUpToDate();
256 return annotationEntries;
257 }
258
259 public void addAnnotationEntry(AnnotationEntry a)
260 {
261 ensureAnnotationsUpToDate();
262 int len = annotationEntries.length;
263 AnnotationEntry[] newAnnotations = new AnnotationEntry[len + 1];
264 System.arraycopy(annotationEntries, 0, newAnnotations, 0, len);
265 newAnnotations[len] = a;
266 annotationEntries = newAnnotations;
267 }
268
269 /**
270 * Hunts for a signature attribute on the member and returns its contents. So where the 'regular' signature
271 * may be (Ljava/util/Vector;)V the signature attribute may in fact say 'Ljava/lang/Vector<Ljava/lang/String>;'
272 * Coded for performance - searches for the attribute only when requested - only searches for it once.
273 */
274 public final String getGenericSignature()
275 {
276 if (!searchedForSignatureAttribute)
277 {
278 boolean found = false;
279 for (int i = 0; !found && i < attributes_count; i++)
280 {
281 if (attributes[i] instanceof Signature)
282 {
283 signatureAttributeString = ((Signature) attributes[i])
284 .getSignature();
285 found = true;
286 }
287 }
288 searchedForSignatureAttribute = true;
289 }
290 return signatureAttributeString;
291 }
292 }