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