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.DataInputStream;
21  import java.io.DataOutputStream;
22  import java.io.IOException;
23  import java.io.Serializable;
24  import java.util.HashMap;
25  import java.util.Map;
26  import org.apache.bcel.Constants;
27  import org.apache.bcel.classfile.ConstantUtf8;
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   * @version $Id: Attribute.java 1152072 2011-07-29 01:54:05Z dbrosius $
38   * @author <A HREF="mailto:m.dahm@gmx.de">M. Dahm</A>
39   * @see ConstantValue
40   * @see SourceFile
41   * @see Code
42   * @see Unknown
43   * @see ExceptionTable
44   * @see LineNumberTable
45   * @see LocalVariableTable
46   * @see InnerClasses
47   * @see Synthetic
48   * @see Deprecated
49   * @see Signature
50   */
51  public abstract class Attribute implements Cloneable, Node, Serializable
52  {
53  	private static final long serialVersionUID = -1707826820310002955L;
54  
55      protected int name_index; // Points to attribute name in constant pool
56  
57  	protected int length; // Content length of attribute field
58  
59  	protected byte tag; // Tag to distiguish subclasses
60  
61  	protected ConstantPool constant_pool;
62  
63  	protected Attribute(byte tag, int name_index, int length,
64  			ConstantPool constant_pool)
65  	{
66  		this.tag = tag;
67  		this.name_index = name_index;
68  		this.length = length;
69  		this.constant_pool = constant_pool;
70  	}
71  
72  	/**
73  	 * Called by objects that are traversing the nodes of the tree implicitely
74  	 * defined by the contents of a Java class. I.e., the hierarchy of methods,
75  	 * fields, attributes, etc. spawns a tree of objects.
76  	 * 
77  	 * @param v
78  	 *            Visitor object
79  	 */
80  	public abstract void accept(Visitor v);
81  
82  	/**
83  	 * Dump attribute to file stream in binary format.
84  	 * 
85  	 * @param file
86  	 *            Output file stream
87  	 * @throws IOException
88  	 */
89  	public void dump(DataOutputStream file) throws IOException
90  	{
91  		file.writeShort(name_index);
92  		file.writeInt(length);
93  	}
94  
95  	private static final Map<String, AttributeReader> readers = new HashMap<String, AttributeReader>();
96  
97  	/**
98  	 * Add an Attribute reader capable of parsing (user-defined) attributes
99  	 * named "name". You should not add readers for the standard attributes such
100 	 * as "LineNumberTable", because those are handled internally.
101 	 * 
102 	 * @param name
103 	 *            the name of the attribute as stored in the class file
104 	 * @param r
105 	 *            the reader object
106 	 */
107 	public static void addAttributeReader(String name, AttributeReader r)
108 	{
109 		readers.put(name, r);
110 	}
111 
112 	/**
113 	 * Remove attribute reader
114 	 * 
115 	 * @param name
116 	 *            the name of the attribute as stored in the class file
117 	 */
118 	public static void removeAttributeReader(String name)
119 	{
120 		readers.remove(name);
121 	}
122 
123 	/*
124 	 * Class method reads one attribute from the input data stream. This method
125 	 * must not be accessible from the outside. It is called by the Field and
126 	 * Method constructor methods.
127 	 * 
128 	 * @see Field
129 	 * @see Method @param file Input stream @param constant_pool Array of
130 	 *      constants @return Attribute @throws IOException @throws
131 	 *      ClassFormatException
132 	 */
133 	public static final Attribute readAttribute(DataInputStream file,
134 			ConstantPool constant_pool) throws IOException,
135 			ClassFormatException
136 	{
137 		ConstantUtf8 c;
138 		String name;
139 		int name_index;
140 		int length;
141 		byte tag = Constants.ATTR_UNKNOWN; // Unknown attribute
142 		// Get class name from constant pool via `name_index' indirection
143 		name_index = file.readUnsignedShort();
144 		c = (ConstantUtf8) constant_pool.getConstant(name_index,
145 				Constants.CONSTANT_Utf8);
146 		name = c.getBytes();
147 		// Length of data in bytes
148 		length = file.readInt();
149 		// Compare strings to find known attribute
150 		// System.out.println(name);
151 		for (byte i = 0; i < Constants.KNOWN_ATTRIBUTES; i++)
152 		{
153 			if (name.equals(Constants.ATTRIBUTE_NAMES[i]))
154 			{
155 				tag = i; // found!
156 				break;
157 			}
158 		}
159 		// Call proper constructor, depending on `tag'
160 		switch (tag)
161 		{
162 		case Constants.ATTR_UNKNOWN:
163 			AttributeReader r = readers.get(name);
164 			if (r != null)
165 			{
166 				return r.createAttribute(name_index, length, file,
167 						constant_pool);
168 			}
169 			return new Unknown(name_index, length, file, constant_pool);
170 		case Constants.ATTR_CONSTANT_VALUE:
171 			return new ConstantValue(name_index, length, file, constant_pool);
172 		case Constants.ATTR_SOURCE_FILE:
173 			return new SourceFile(name_index, length, file, constant_pool);
174 		case Constants.ATTR_CODE:
175 			return new Code(name_index, length, file, constant_pool);
176 		case Constants.ATTR_EXCEPTIONS:
177 			return new ExceptionTable(name_index, length, file, constant_pool);
178 		case Constants.ATTR_LINE_NUMBER_TABLE:
179 			return new LineNumberTable(name_index, length, file, constant_pool);
180 		case Constants.ATTR_LOCAL_VARIABLE_TABLE:
181 			return new LocalVariableTable(name_index, length, file,
182 					constant_pool);
183 		case Constants.ATTR_INNER_CLASSES:
184 			return new InnerClasses(name_index, length, file, constant_pool);
185 		case Constants.ATTR_SYNTHETIC:
186 			return new Synthetic(name_index, length, file, constant_pool);
187 		case Constants.ATTR_DEPRECATED:
188 			return new Deprecated(name_index, length, file, constant_pool);
189 		case Constants.ATTR_PMG:
190 			return new PMGClass(name_index, length, file, constant_pool);
191 		case Constants.ATTR_SIGNATURE:
192 			return new Signature(name_index, length, file, constant_pool);
193 		case Constants.ATTR_STACK_MAP:
194 			return new StackMap(name_index, length, file, constant_pool);
195 		case Constants.ATTR_RUNTIME_VISIBLE_ANNOTATIONS:
196 			return new RuntimeVisibleAnnotations(name_index, length, file,
197 					constant_pool);
198 		case Constants.ATTR_RUNTIMEIN_VISIBLE_ANNOTATIONS:
199 			return new RuntimeInvisibleAnnotations(name_index, length, file,
200 					constant_pool);
201 		case Constants.ATTR_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS:
202 			return new RuntimeVisibleParameterAnnotations(name_index, length,
203 					file, constant_pool);
204 		case Constants.ATTR_RUNTIMEIN_VISIBLE_PARAMETER_ANNOTATIONS:
205 			return new RuntimeInvisibleParameterAnnotations(name_index, length,
206 					file, constant_pool);
207 		case Constants.ATTR_ANNOTATION_DEFAULT:
208 			return new AnnotationDefault(name_index, length, file,
209 					constant_pool);
210 		case Constants.ATTR_LOCAL_VARIABLE_TYPE_TABLE:
211 			return new LocalVariableTypeTable(name_index, length, file,
212 					constant_pool);
213 		case Constants.ATTR_ENCLOSING_METHOD:
214 			return new EnclosingMethod(name_index, length, file, constant_pool);
215 		case Constants.ATTR_STACK_MAP_TABLE:
216 			return new StackMapTable(name_index, length, file, constant_pool);
217 		default: // Never reached
218 			throw new IllegalStateException("Unrecognized attribute type tag parsed: " + tag);
219 		}
220 	}
221 
222 	/**
223 	 * @return Name of attribute
224 	 */
225 	public String getName()
226 	{
227 		ConstantUtf8 c = (ConstantUtf8) constant_pool.getConstant(name_index,
228 				Constants.CONSTANT_Utf8);
229 		return c.getBytes();
230 	}
231 
232 	/**
233 	 * @return Length of attribute field in bytes.
234 	 */
235 	public final int getLength()
236 	{
237 		return length;
238 	}
239 
240 	/**
241 	 * @param length
242 	 *            length in bytes.
243 	 */
244 	public final void setLength(int length)
245 	{
246 		this.length = length;
247 	}
248 
249 	/**
250 	 * @param name_index
251 	 *            of attribute.
252 	 */
253 	public final void setNameIndex(int name_index)
254 	{
255 		this.name_index = name_index;
256 	}
257 
258 	/**
259 	 * @return Name index in constant pool of attribute name.
260 	 */
261 	public final int getNameIndex()
262 	{
263 		return name_index;
264 	}
265 
266 	/**
267 	 * @return Tag of attribute, i.e., its type. Value may not be altered, thus
268 	 *         there is no setTag() method.
269 	 */
270 	public final byte getTag()
271 	{
272 		return tag;
273 	}
274 
275 	/**
276 	 * @return Constant pool used by this object.
277 	 * @see ConstantPool
278 	 */
279 	public final ConstantPool getConstantPool()
280 	{
281 		return constant_pool;
282 	}
283 
284 	/**
285 	 * @param constant_pool
286 	 *            Constant pool to be used for this object.
287 	 * @see ConstantPool
288 	 */
289 	public final void setConstantPool(ConstantPool constant_pool)
290 	{
291 		this.constant_pool = constant_pool;
292 	}
293 
294 	/**
295 	 * Use copy() if you want to have a deep copy(), i.e., with all references
296 	 * copied correctly.
297 	 * 
298 	 * @return shallow copy of this attribute
299 	 */
300 	@Override
301     public Object clone()
302 	{
303 		Object o = null;
304 		try
305 		{
306 			o = super.clone();
307 		}
308 		catch (CloneNotSupportedException e)
309 		{
310 			e.printStackTrace(); // Never occurs
311 		}
312 		return o;
313 	}
314 
315 	/**
316 	 * @return deep copy of this attribute
317 	 */
318 	public abstract Attribute copy(ConstantPool _constant_pool);
319 
320 	/**
321 	 * @return attribute name.
322 	 */
323 	@Override
324     public String toString()
325 	{
326 		return Constants.ATTRIBUTE_NAMES[tag];
327 	}
328 }