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   */
18  package org.apache.bcel.classfile;
19  
20  import java.io.DataInput;
21  import java.io.DataInputStream;
22  import java.io.DataOutputStream;
23  import java.io.IOException;
24  import java.util.HashMap;
25  import java.util.Map;
26  
27  import org.apache.bcel.Const;
28  
29  /**
30   * Abstract super class for <em>Attribute</em> objects. Currently the
31   * <em>ConstantValue</em>, <em>SourceFile</em>, <em>Code</em>,
32   * <em>Exceptiontable</em>, <em>LineNumberTable</em>,
33   * <em>LocalVariableTable</em>, <em>InnerClasses</em> and
34   * <em>Synthetic</em> attributes are supported. The <em>Unknown</em>
35   * attribute stands for non-standard-attributes.
36   *
37   * @see ConstantValue
38   * @see SourceFile
39   * @see Code
40   * @see Unknown
41   * @see ExceptionTable
42   * @see LineNumberTable
43   * @see LocalVariableTable
44   * @see InnerClasses
45   * @see Synthetic
46   * @see Deprecated
47   * @see Signature
48   */
49  public abstract class Attribute implements Cloneable, Node {
50  
51      private static final boolean debug = Boolean.getBoolean(Attribute.class.getCanonicalName() + ".debug"); // Debugging on/off
52  
53      private static final Map<String, Object> readers = new HashMap<>();
54  
55      /**
56       * Add an Attribute reader capable of parsing (user-defined) attributes
57       * named "name". You should not add readers for the standard attributes such
58       * as "LineNumberTable", because those are handled internally.
59       *
60       * @param name the name of the attribute as stored in the class file
61       * @param r    the reader object
62       * @deprecated (6.0) Use {@link #addAttributeReader(String, UnknownAttributeReader)} instead
63       */
64      @java.lang.Deprecated
65      public static void addAttributeReader(final String name, final AttributeReader r)
66      {
67          readers.put(name, r);
68      }
69  
70      /**
71       * Add an Attribute reader capable of parsing (user-defined) attributes
72       * named "name". You should not add readers for the standard attributes such
73       * as "LineNumberTable", because those are handled internally.
74       *
75       * @param name the name of the attribute as stored in the class file
76       * @param r    the reader object
77       */
78      public static void addAttributeReader(final String name, final UnknownAttributeReader r)
79      {
80          readers.put(name, r);
81      }
82  
83      protected static void println(final String msg) {
84          if (debug) {
85              System.err.println(msg);
86          }
87      }
88  
89      /**
90       * Class method reads one attribute from the input data stream. This method
91       * must not be accessible from the outside. It is called by the Field and
92       * Method constructor methods.
93       *
94       * @see Field
95       * @see Method
96       *
97       * @param file Input stream
98       * @param constant_pool Array of constants
99       * @return Attribute
100      * @throws IOException
101      * @throws ClassFormatException
102      * @since 6.0
103      */
104     public static Attribute readAttribute(final DataInput file, final ConstantPool constant_pool)
105             throws IOException, ClassFormatException
106     {
107         byte tag = Const.ATTR_UNKNOWN; // Unknown attribute
108         // Get class name from constant pool via `name_index' indirection
109         final int name_index = file.readUnsignedShort();
110         final ConstantUtf8./../../../org/apache/bcel/classfile/ConstantUtf8.html#ConstantUtf8">ConstantUtf8 c = (ConstantUtf8) constant_pool.getConstant(name_index, Const.CONSTANT_Utf8);
111         final String name = c.getBytes();
112 
113         // Length of data in bytes
114         final int length = file.readInt();
115 
116         // Compare strings to find known attribute
117         for (byte i = 0; i < Const.KNOWN_ATTRIBUTES; i++)
118         {
119             if (name.equals(Const.getAttributeName(i)))
120             {
121                 tag = i; // found!
122                 break;
123             }
124         }
125 
126         // Call proper constructor, depending on `tag'
127         switch (tag)
128         {
129             case Const.ATTR_UNKNOWN:
130                 final Object r = readers.get(name);
131                 if (r instanceof UnknownAttributeReader)
132                 {
133                     return ((UnknownAttributeReader) r).createAttribute(name_index, length, file, constant_pool);
134                 }
135                 return new Unknown(name_index, length, file, constant_pool);
136             case Const.ATTR_CONSTANT_VALUE:
137                 return new ConstantValue(name_index, length, file, constant_pool);
138             case Const.ATTR_SOURCE_FILE:
139                 return new SourceFile(name_index, length, file, constant_pool);
140             case Const.ATTR_CODE:
141                 return new Code(name_index, length, file, constant_pool);
142             case Const.ATTR_EXCEPTIONS:
143                 return new ExceptionTable(name_index, length, file, constant_pool);
144             case Const.ATTR_LINE_NUMBER_TABLE:
145                 return new LineNumberTable(name_index, length, file, constant_pool);
146             case Const.ATTR_LOCAL_VARIABLE_TABLE:
147                 return new LocalVariableTable(name_index, length, file, constant_pool);
148             case Const.ATTR_INNER_CLASSES:
149                 return new InnerClasses(name_index, length, file, constant_pool);
150             case Const.ATTR_SYNTHETIC:
151                 return new Synthetic(name_index, length, file, constant_pool);
152             case Const.ATTR_DEPRECATED:
153                 return new Deprecated(name_index, length, file, constant_pool);
154             case Const.ATTR_PMG:
155                 return new PMGClass(name_index, length, file, constant_pool);
156             case Const.ATTR_SIGNATURE:
157                 return new Signature(name_index, length, file, constant_pool);
158             case Const.ATTR_STACK_MAP:
159                 // old style stack map: unneeded for JDK5 and below;
160                 // illegal(?) for JDK6 and above.  So just delete with a warning.
161                 println("Warning: Obsolete StackMap attribute ignored.");
162                 return new Unknown(name_index, length, file, constant_pool);
163             case Const.ATTR_RUNTIME_VISIBLE_ANNOTATIONS:
164                 return new RuntimeVisibleAnnotations(name_index, length, file, constant_pool);
165             case Const.ATTR_RUNTIME_INVISIBLE_ANNOTATIONS:
166                 return new RuntimeInvisibleAnnotations(name_index, length, file, constant_pool);
167             case Const.ATTR_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS:
168                 return new RuntimeVisibleParameterAnnotations(name_index, length, file, constant_pool);
169             case Const.ATTR_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS:
170                 return new RuntimeInvisibleParameterAnnotations(name_index, length, file, constant_pool);
171             case Const.ATTR_ANNOTATION_DEFAULT:
172                 return new AnnotationDefault(name_index, length, file, constant_pool);
173             case Const.ATTR_LOCAL_VARIABLE_TYPE_TABLE:
174                 return new LocalVariableTypeTable(name_index, length, file, constant_pool);
175             case Const.ATTR_ENCLOSING_METHOD:
176                 return new EnclosingMethod(name_index, length, file, constant_pool);
177             case Const.ATTR_STACK_MAP_TABLE:
178                 // read new style stack map: StackMapTable.  The rest of the code
179                 // calls this a StackMap for historical reasons.
180                 return new StackMap(name_index, length, file, constant_pool);
181             case Const.ATTR_BOOTSTRAP_METHODS:
182                 return new BootstrapMethods(name_index, length, file, constant_pool);
183             case Const.ATTR_METHOD_PARAMETERS:
184                 return new MethodParameters(name_index, length, file, constant_pool);
185             case Const.ATTR_MODULE:
186                 return new Module(name_index, length, file, constant_pool);
187             case Const.ATTR_MODULE_PACKAGES:
188                 return new ModulePackages(name_index, length, file, constant_pool);
189             case Const.ATTR_MODULE_MAIN_CLASS:
190                 return new ModuleMainClass(name_index, length, file, constant_pool);
191             case Const.ATTR_NEST_HOST:
192                 return new NestHost(name_index, length, file, constant_pool);
193             case Const.ATTR_NEST_MEMBERS:
194                 return new NestMembers(name_index, length, file, constant_pool);
195             default:
196                 // Never reached
197                 throw new IllegalStateException("Unrecognized attribute type tag parsed: " + tag);
198         }
199     }
200 
201     /**
202      * Class method reads one attribute from the input data stream. This method
203      * must not be accessible from the outside. It is called by the Field and
204      * Method constructor methods.
205      *
206      * @see Field
207      * @see Method
208      *
209      * @param file Input stream
210      * @param constant_pool Array of constants
211      * @return Attribute
212      * @throws IOException
213      * @throws ClassFormatException
214      */
215     public static Attribute readAttribute(final DataInputStream file, final ConstantPool constant_pool)
216             throws IOException, ClassFormatException
217     {
218         return readAttribute((DataInput) file, constant_pool);
219     }
220 
221     /**
222      * Remove attribute reader
223      *
224      * @param name the name of the attribute as stored in the class file
225      */
226     public static void removeAttributeReader(final String name)
227     {
228         readers.remove(name);
229     }
230 
231     /**
232      * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
233      */
234     @java.lang.Deprecated
235     protected int name_index; // Points to attribute name in constant pool TODO make private (has getter & setter)
236 
237     /**
238      * @deprecated (since 6.0) (since 6.0) will be made private; do not access directly, use getter/setter
239      */
240     @java.lang.Deprecated
241     protected int length; // Content length of attribute field TODO make private (has getter & setter)
242 
243     /**
244      * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
245      */
246     @java.lang.Deprecated
247     protected byte tag; // Tag to distinguish subclasses TODO make private & final; supposed to be immutable
248 
249     /**
250      * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
251      */
252     @java.lang.Deprecated
253     protected ConstantPool constant_pool; // TODO make private (has getter & setter)
254 
255     protected Attribute(final byte tag, final int name_index, final int length, final ConstantPool constant_pool)
256     {
257         this.tag = tag;
258         this.name_index = name_index;
259         this.length = length;
260         this.constant_pool = constant_pool;
261     }
262 
263     /**
264      * Called by objects that are traversing the nodes of the tree implicitely
265      * defined by the contents of a Java class. I.e., the hierarchy of methods,
266      * fields, attributes, etc. spawns a tree of objects.
267      *
268      * @param v
269      *            Visitor object
270      */
271     @Override
272     public abstract void accept(Visitor v);
273 
274     /**
275      * Use copy() if you want to have a deep copy(), i.e., with all references
276      * copied correctly.
277      *
278      * @return shallow copy of this attribute
279      */
280     @Override
281     public Object clone()
282     {
283         Attribute attr = null;
284         try
285         {
286             attr = (Attribute) super.clone();
287         }
288         catch (final CloneNotSupportedException e)
289         {
290             throw new Error("Clone Not Supported"); // never happens
291         }
292         return attr;
293     }
294 
295     /**
296      * @return deep copy of this attribute
297      */
298     public abstract Attribute copy(ConstantPool _constant_pool);
299 
300     /**
301      * Dump attribute to file stream in binary format.
302      *
303      * @param file
304      *            Output file stream
305      * @throws IOException
306      */
307     public void dump(final DataOutputStream file) throws IOException
308     {
309         file.writeShort(name_index);
310         file.writeInt(length);
311     }
312 
313     /**
314      * @return Constant pool used by this object.
315      * @see ConstantPool
316      */
317     public final ConstantPool getConstantPool()
318     {
319         return constant_pool;
320     }
321 
322     /**
323      * @return Length of attribute field in bytes.
324      */
325     public final int getLength()
326     {
327         return length;
328     }
329 
330     /**
331      * @return Name of attribute
332      * @since 6.0
333      */
334     public String getName()
335     {
336         final ConstantUtf8./../../../org/apache/bcel/classfile/ConstantUtf8.html#ConstantUtf8">ConstantUtf8 c = (ConstantUtf8) constant_pool.getConstant(name_index, Const.CONSTANT_Utf8);
337         return c.getBytes();
338     }
339 
340     /**
341      * @return Name index in constant pool of attribute name.
342      */
343     public final int getNameIndex()
344     {
345         return name_index;
346     }
347 
348     /**
349      * @return Tag of attribute, i.e., its type. Value may not be altered, thus there is no setTag() method.
350      */
351     public final byte getTag()
352     {
353         return tag;
354     }
355 
356     /**
357      * @param constant_pool Constant pool to be used for this object.
358      * @see ConstantPool
359      */
360     public final void setConstantPool(final ConstantPool constant_pool)
361     {
362         this.constant_pool = constant_pool;
363     }
364 
365     /**
366      * @param length length in bytes.
367      */
368     public final void setLength(final int length)
369     {
370         this.length = length;
371     }
372 
373     /**
374      * @param name_index of attribute.
375      */
376     public final void setNameIndex(final int name_index)
377     {
378         this.name_index = name_index;
379     }
380 
381     /**
382      * @return attribute name.
383      */
384     @Override
385     public String toString()
386     {
387         return Const.getAttributeName(tag);
388     }
389 }