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 */ 017package org.apache.bcel.classfile; 018 019import java.io.DataInput; 020import java.io.DataInputStream; 021import java.io.DataOutputStream; 022import java.io.IOException; 023import java.util.HashMap; 024import java.util.Map; 025 026import org.apache.bcel.Const; 027 028/** 029 * Abstract super class for <em>Attribute</em> objects. Currently the <em>ConstantValue</em>, <em>SourceFile</em>, 030 * <em>Code</em>, <em>Exceptiontable</em>, <em>LineNumberTable</em>, <em>LocalVariableTable</em>, <em>InnerClasses</em> 031 * and <em>Synthetic</em> attributes are supported. The <em>Unknown</em> attribute stands for non-standard-attributes. 032 * 033 * @see ConstantValue 034 * @see SourceFile 035 * @see Code 036 * @see Unknown 037 * @see ExceptionTable 038 * @see LineNumberTable 039 * @see LocalVariableTable 040 * @see InnerClasses 041 * @see Synthetic 042 * @see Deprecated 043 * @see Signature 044 */ 045public abstract class Attribute implements Cloneable, Node { 046 047 private static final boolean debug = Boolean.getBoolean(Attribute.class.getCanonicalName() + ".debug"); // Debugging on/off 048 049 private static final Map<String, Object> READERS = new HashMap<>(); 050 051 /** 052 * Empty array. 053 * 054 * @since 6.6.0 055 */ 056 public static final Attribute[] EMPTY_ARRAY = {}; 057 058 /** 059 * Add an Attribute reader capable of parsing (user-defined) attributes named "name". You should not add readers for the 060 * standard attributes such as "LineNumberTable", because those are handled internally. 061 * 062 * @param name the name of the attribute as stored in the class file 063 * @param attributeReader the reader object 064 * @deprecated (6.0) Use {@link #addAttributeReader(String, UnknownAttributeReader)} instead 065 */ 066 @java.lang.Deprecated 067 public static void addAttributeReader(final String name, final AttributeReader attributeReader) { 068 READERS.put(name, attributeReader); 069 } 070 071 /** 072 * Add an Attribute reader capable of parsing (user-defined) attributes named "name". You should not add readers for the 073 * standard attributes such as "LineNumberTable", because those are handled internally. 074 * 075 * @param name the name of the attribute as stored in the class file 076 * @param unknownAttributeReader the reader object 077 */ 078 public static void addAttributeReader(final String name, final UnknownAttributeReader unknownAttributeReader) { 079 READERS.put(name, unknownAttributeReader); 080 } 081 082 protected static void println(final String msg) { 083 if (debug) { 084 System.err.println(msg); 085 } 086 } 087 088 /** 089 * Class method reads one attribute from the input data stream. This method must not be accessible from the outside. It 090 * is called by the Field and Method constructor methods. 091 * 092 * @see Field 093 * @see Method 094 * 095 * @param file Input stream 096 * @param constantPool Array of constants 097 * @return Attribute 098 * @throws IOException if an I/O error occurs. 099 * @since 6.0 100 */ 101 public static Attribute readAttribute(final DataInput file, final ConstantPool constantPool) throws IOException { 102 byte tag = Const.ATTR_UNKNOWN; // Unknown attribute 103 // Get class name from constant pool via `name_index' indirection 104 final int nameIndex = file.readUnsignedShort(); 105 final String name = constantPool.getConstantUtf8(nameIndex).getBytes(); 106 107 // Length of data in bytes 108 final int length = file.readInt(); 109 110 // Compare strings to find known attribute 111 for (byte i = 0; i < Const.KNOWN_ATTRIBUTES; i++) { 112 if (name.equals(Const.getAttributeName(i))) { 113 tag = i; // found! 114 break; 115 } 116 } 117 118 // Call proper constructor, depending on `tag' 119 switch (tag) { 120 case Const.ATTR_UNKNOWN: 121 final Object r = READERS.get(name); 122 if (r instanceof UnknownAttributeReader) { 123 return ((UnknownAttributeReader) r).createAttribute(nameIndex, length, file, constantPool); 124 } 125 return new Unknown(nameIndex, length, file, constantPool); 126 case Const.ATTR_CONSTANT_VALUE: 127 return new ConstantValue(nameIndex, length, file, constantPool); 128 case Const.ATTR_SOURCE_FILE: 129 return new SourceFile(nameIndex, length, file, constantPool); 130 case Const.ATTR_CODE: 131 return new Code(nameIndex, length, file, constantPool); 132 case Const.ATTR_EXCEPTIONS: 133 return new ExceptionTable(nameIndex, length, file, constantPool); 134 case Const.ATTR_LINE_NUMBER_TABLE: 135 return new LineNumberTable(nameIndex, length, file, constantPool); 136 case Const.ATTR_LOCAL_VARIABLE_TABLE: 137 return new LocalVariableTable(nameIndex, length, file, constantPool); 138 case Const.ATTR_INNER_CLASSES: 139 return new InnerClasses(nameIndex, length, file, constantPool); 140 case Const.ATTR_SYNTHETIC: 141 return new Synthetic(nameIndex, length, file, constantPool); 142 case Const.ATTR_DEPRECATED: 143 return new Deprecated(nameIndex, length, file, constantPool); 144 case Const.ATTR_PMG: 145 return new PMGClass(nameIndex, length, file, constantPool); 146 case Const.ATTR_SIGNATURE: 147 return new Signature(nameIndex, length, file, constantPool); 148 case Const.ATTR_STACK_MAP: 149 // old style stack map: unneeded for JDK5 and below; 150 // illegal(?) for JDK6 and above. So just delete with a warning. 151 println("Warning: Obsolete StackMap attribute ignored."); 152 return new Unknown(nameIndex, length, file, constantPool); 153 case Const.ATTR_RUNTIME_VISIBLE_ANNOTATIONS: 154 return new RuntimeVisibleAnnotations(nameIndex, length, file, constantPool); 155 case Const.ATTR_RUNTIME_INVISIBLE_ANNOTATIONS: 156 return new RuntimeInvisibleAnnotations(nameIndex, length, file, constantPool); 157 case Const.ATTR_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS: 158 return new RuntimeVisibleParameterAnnotations(nameIndex, length, file, constantPool); 159 case Const.ATTR_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS: 160 return new RuntimeInvisibleParameterAnnotations(nameIndex, length, file, constantPool); 161 case Const.ATTR_ANNOTATION_DEFAULT: 162 return new AnnotationDefault(nameIndex, length, file, constantPool); 163 case Const.ATTR_LOCAL_VARIABLE_TYPE_TABLE: 164 return new LocalVariableTypeTable(nameIndex, length, file, constantPool); 165 case Const.ATTR_ENCLOSING_METHOD: 166 return new EnclosingMethod(nameIndex, length, file, constantPool); 167 case Const.ATTR_STACK_MAP_TABLE: 168 // read new style stack map: StackMapTable. The rest of the code 169 // calls this a StackMap for historical reasons. 170 return new StackMap(nameIndex, length, file, constantPool); 171 case Const.ATTR_BOOTSTRAP_METHODS: 172 return new BootstrapMethods(nameIndex, length, file, constantPool); 173 case Const.ATTR_METHOD_PARAMETERS: 174 return new MethodParameters(nameIndex, length, file, constantPool); 175 case Const.ATTR_MODULE: 176 return new Module(nameIndex, length, file, constantPool); 177 case Const.ATTR_MODULE_PACKAGES: 178 return new ModulePackages(nameIndex, length, file, constantPool); 179 case Const.ATTR_MODULE_MAIN_CLASS: 180 return new ModuleMainClass(nameIndex, length, file, constantPool); 181 case Const.ATTR_NEST_HOST: 182 return new NestHost(nameIndex, length, file, constantPool); 183 case Const.ATTR_NEST_MEMBERS: 184 return new NestMembers(nameIndex, length, file, constantPool); 185 default: 186 // Never reached 187 throw new IllegalStateException("Unrecognized attribute type tag parsed: " + tag); 188 } 189 } 190 191 /** 192 * Class method reads one attribute from the input data stream. This method must not be accessible from the outside. It 193 * is called by the Field and Method constructor methods. 194 * 195 * @see Field 196 * @see Method 197 * 198 * @param file Input stream 199 * @param constantPool Array of constants 200 * @return Attribute 201 * @throws IOException if an I/O error occurs. 202 */ 203 public static Attribute readAttribute(final DataInputStream file, final ConstantPool constantPool) throws IOException { 204 return readAttribute((DataInput) file, constantPool); 205 } 206 207 /** 208 * Remove attribute reader 209 * 210 * @param name the name of the attribute as stored in the class file 211 */ 212 public static void removeAttributeReader(final String name) { 213 READERS.remove(name); 214 } 215 216 /** 217 * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter 218 */ 219 @java.lang.Deprecated 220 protected int name_index; // Points to attribute name in constant pool TODO make private (has getter & setter) 221 222 /** 223 * @deprecated (since 6.0) (since 6.0) will be made private; do not access directly, use getter/setter 224 */ 225 @java.lang.Deprecated 226 protected int length; // Content length of attribute field TODO make private (has getter & setter) 227 228 /** 229 * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter 230 */ 231 @java.lang.Deprecated 232 protected byte tag; // Tag to distinguish subclasses TODO make private & final; supposed to be immutable 233 234 /** 235 * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter 236 */ 237 @java.lang.Deprecated 238 protected ConstantPool constant_pool; // TODO make private (has getter & setter) 239 240 protected Attribute(final byte tag, final int nameIndex, final int length, final ConstantPool constantPool) { 241 this.tag = tag; 242 this.name_index = nameIndex; 243 this.length = length; 244 this.constant_pool = constantPool; 245 } 246 247 /** 248 * Called by objects that are traversing the nodes of the tree implicitly defined by the contents of a Java class. 249 * I.e., the hierarchy of methods, fields, attributes, etc. spawns a tree of objects. 250 * 251 * @param v Visitor object 252 */ 253 @Override 254 public abstract void accept(Visitor v); 255 256 /** 257 * Use copy() if you want to have a deep copy(), i.e., with all references copied correctly. 258 * 259 * @return shallow copy of this attribute 260 */ 261 @Override 262 public Object clone() { 263 Attribute attr = null; 264 try { 265 attr = (Attribute) super.clone(); 266 } catch (final CloneNotSupportedException e) { 267 throw new Error("Clone Not Supported"); // never happens 268 } 269 return attr; 270 } 271 272 /** 273 * @return deep copy of this attribute 274 */ 275 public abstract Attribute copy(ConstantPool constantPool); 276 277 /** 278 * Dump attribute to file stream in binary format. 279 * 280 * @param file Output file stream 281 * @throws IOException if an I/O error occurs. 282 */ 283 public void dump(final DataOutputStream file) throws IOException { 284 file.writeShort(name_index); 285 file.writeInt(length); 286 } 287 288 /** 289 * @return Constant pool used by this object. 290 * @see ConstantPool 291 */ 292 public final ConstantPool getConstantPool() { 293 return constant_pool; 294 } 295 296 /** 297 * @return Length of attribute field in bytes. 298 */ 299 public final int getLength() { 300 return length; 301 } 302 303 /** 304 * @return Name of attribute 305 * @since 6.0 306 */ 307 public String getName() { 308 return constant_pool.getConstantUtf8(name_index).getBytes(); 309 } 310 311 /** 312 * @return Name index in constant pool of attribute name. 313 */ 314 public final int getNameIndex() { 315 return name_index; 316 } 317 318 /** 319 * @return Tag of attribute, i.e., its type. Value may not be altered, thus there is no setTag() method. 320 */ 321 public final byte getTag() { 322 return tag; 323 } 324 325 /** 326 * @param constantPool Constant pool to be used for this object. 327 * @see ConstantPool 328 */ 329 public final void setConstantPool(final ConstantPool constantPool) { 330 this.constant_pool = constantPool; 331 } 332 333 /** 334 * @param length length in bytes. 335 */ 336 public final void setLength(final int length) { 337 this.length = length; 338 } 339 340 /** 341 * @param nameIndex of attribute. 342 */ 343 public final void setNameIndex(final int nameIndex) { 344 this.name_index = nameIndex; 345 } 346 347 /** 348 * @return attribute name. 349 */ 350 @Override 351 public String toString() { 352 return Const.getAttributeName(tag); 353 } 354}