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    }