001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * https://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019package org.apache.bcel.classfile; 020 021import java.io.DataInput; 022import java.io.DataInputStream; 023import java.io.DataOutputStream; 024import java.io.IOException; 025import java.util.Arrays; 026 027import org.apache.bcel.util.Args; 028 029/** 030 * Abstract superclass for fields and methods. 031 */ 032public abstract class FieldOrMethod extends AccessFlags implements Cloneable, Node { 033 034 /** 035 * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter. 036 */ 037 @java.lang.Deprecated 038 protected int name_index; // Points to field name in constant pool 039 040 /** 041 * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter. 042 */ 043 @java.lang.Deprecated 044 protected int signature_index; // Points to encoded signature 045 046 /** 047 * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter. 048 */ 049 @java.lang.Deprecated 050 protected Attribute[] attributes; // Collection of attributes 051 052 /** 053 * @deprecated (since 6.0) will be removed (not needed) 054 */ 055 @java.lang.Deprecated 056 protected int attributes_count; // No. of attributes 057 058 // @since 6.0 059 private AnnotationEntry[] annotationEntries; // annotations defined on the field or method 060 061 /** 062 * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter. 063 */ 064 @java.lang.Deprecated 065 protected ConstantPool constant_pool; 066 067 private String signatureAttributeString; 068 private boolean searchedForSignatureAttribute; 069 070 /** 071 * Constructs an empty field or method whose properties must be set before use. 072 */ 073 FieldOrMethod() { 074 } 075 076 /** 077 * Constructs a field or method from a data input using standard Code headers. 078 * 079 * @param file Input stream. 080 * @param constantPool The constant pool. 081 * @throws IOException Thrown if an I/O error occurs. 082 * @throws ClassFormatException Thrown if the field or method, or one of its attributes, is malformed. 083 */ 084 protected FieldOrMethod(final DataInput file, final ConstantPool constantPool) throws IOException { 085 this(file, constantPool, false); 086 } 087 088 /** 089 * Constructs a field or method from a data input using the selected Code header layout. 090 * 091 * @param file Input stream. 092 * @param constantPool The constant pool. 093 * @param compactCodeHeader Whether to read any Code attributes encountered with compact four-byte headers ({@code true}) 094 * or standard eight-byte headers ({@code false}). 095 * @throws IOException Thrown if an I/O error occurs. 096 * @throws ClassFormatException Thrown if the field or method, or one of its attributes, is malformed. 097 * @see Attribute#readAttribute(DataInput, ConstantPool, boolean) 098 */ 099 FieldOrMethod(final DataInput file, final ConstantPool constantPool, final boolean compactCodeHeader) throws IOException { 100 this(file.readUnsignedShort(), file.readUnsignedShort(), file.readUnsignedShort(), null, constantPool); 101 final int attributesCount = file.readUnsignedShort(); 102 attributes = new Attribute[attributesCount]; 103 for (int i = 0; i < attributesCount; i++) { 104 attributes[i] = Attribute.readAttribute(file, constantPool, compactCodeHeader); 105 } 106 this.attributes_count = attributesCount; // init deprecated field 107 } 108 109 /** 110 * Constructs a field or method from a data input stream using standard Code headers. 111 * 112 * @param file Input stream. 113 * @param constantPool The constant pool. 114 * @throws IOException Thrown if an I/O error occurs. 115 * @throws ClassFormatException Thrown if the field or method, or one of its attributes, is malformed. 116 * @deprecated (6.0) Use {@link #FieldOrMethod(java.io.DataInput, ConstantPool)} instead. 117 */ 118 @java.lang.Deprecated 119 protected FieldOrMethod(final DataInputStream file, final ConstantPool constantPool) throws IOException { 120 this((DataInput) file, constantPool); 121 } 122 123 /** 124 * Initialize from another object. Note that both objects use the same references (shallow copy). Use clone() for a 125 * physical copy. 126 * 127 * @param c Source to copy. 128 */ 129 protected FieldOrMethod(final FieldOrMethod c) { 130 this(c.getAccessFlags(), c.getNameIndex(), c.getSignatureIndex(), c.getAttributes(), c.getConstantPool()); 131 } 132 133 /** 134 * Constructs a FieldOrMethod. 135 * 136 * @param accessFlags Access rights of the field or method. 137 * @param nameIndex Points to the field or method name in the constant pool. 138 * @param signatureIndex Points to encoded signature. 139 * @param attributes Collection of attributes. 140 * @param constantPool Array of constants. 141 */ 142 protected FieldOrMethod(final int accessFlags, final int nameIndex, final int signatureIndex, final Attribute[] attributes, 143 final ConstantPool constantPool) { 144 super(accessFlags); 145 this.name_index = nameIndex; 146 this.signature_index = signatureIndex; 147 this.constant_pool = constantPool; 148 setAttributes(attributes); 149 } 150 151 /** 152 * Creates a deep copy of this field. 153 * 154 * @param constantPool The constant pool. 155 * @return deep copy of this field. 156 */ 157 protected FieldOrMethod copy_(final ConstantPool constantPool) { 158 try { 159 final FieldOrMethod c = (FieldOrMethod) clone(); 160 c.constant_pool = constantPool; 161 c.attributes = new Attribute[attributes.length]; 162 c.attributes_count = attributes_count; // init deprecated field 163 Arrays.setAll(c.attributes, i -> attributes[i].copy(constantPool)); 164 return c; 165 } catch (final CloneNotSupportedException e) { 166 throw new UnsupportedOperationException(e); 167 } 168 } 169 170 /** 171 * Dumps object to file stream on binary format. 172 * 173 * @param file Output file stream. 174 * @throws IOException Thrown if an I/O error occurs. 175 */ 176 public final void dump(final DataOutputStream file) throws IOException { 177 dump(file, attributes); 178 } 179 180 private void dump(final DataOutputStream file, final Attribute[] outputAttributes) throws IOException { 181 file.writeShort(super.getAccessFlags()); 182 file.writeShort(name_index); 183 file.writeShort(signature_index); 184 file.writeShort(Args.requireU2(attributes_count, "attributes_count")); 185 for (final Attribute attribute : outputAttributes) { 186 attribute.dump(file); 187 } 188 } 189 190 /** 191 * Dumps a member with the Code encoding selected by its enclosing class, without modifying its attributes. 192 * 193 * @param file Output stream. 194 * @param compactCodeHeader Whether to write Code attributes with compact four-byte headers ({@code true}) 195 * or standard eight-byte headers ({@code false}). 196 * @throws IOException Thrown if an I/O error occurs. 197 * @throws ClassFormatException Thrown if an attribute fails validation. 198 */ 199 final void dump(final DataOutputStream file, final boolean compactCodeHeader) throws IOException { 200 final Attribute[] sourceAttributes = getAttributes(); 201 Attribute[] outputAttributes = sourceAttributes; 202 for (int i = 0; i < sourceAttributes.length; i++) { 203 if (sourceAttributes[i] instanceof Code && ((Code) sourceAttributes[i]).isCompactCodeHeader() != compactCodeHeader) { 204 if (outputAttributes == sourceAttributes) { 205 outputAttributes = sourceAttributes.clone(); 206 } 207 final Code code = new Code((Code) sourceAttributes[i]); 208 code.setCompactCodeHeader(compactCodeHeader); 209 outputAttributes[i] = code; 210 } 211 } 212 dump(file, outputAttributes); 213 } 214 215 /** 216 * Gets annotations on the field or method. 217 * 218 * @return Annotations on the field or method. 219 * @since 6.0 220 */ 221 public AnnotationEntry[] getAnnotationEntries() { 222 if (annotationEntries == null) { 223 annotationEntries = AnnotationEntry.createAnnotationEntries(getAttributes()); 224 } 225 226 return annotationEntries; 227 } 228 229 /** 230 * Gets attribute for given tag. 231 * 232 * @param <T> The attribute type. 233 * @param tag The attribute tag. 234 * @return Attribute for given tag, null if not found. 235 * Refer to {@link org.apache.bcel.Const#ATTR_UNKNOWN} constants named ATTR_* for possible values. 236 * @since 6.10.0 237 */ 238 @SuppressWarnings("unchecked") 239 public final <T extends Attribute> T getAttribute(final byte tag) { 240 for (final Attribute attribute : getAttributes()) { 241 if (attribute.getTag() == tag) { 242 return (T) attribute; 243 } 244 } 245 return null; 246 } 247 248 /** 249 * Gets the collection of object attributes. 250 * 251 * @return Collection of object attributes. 252 */ 253 public final Attribute[] getAttributes() { 254 return attributes; 255 } 256 257 /** 258 * Gets the constant pool used by this object. 259 * 260 * @return Constant pool used by this object. 261 */ 262 public final ConstantPool getConstantPool() { 263 return constant_pool; 264 } 265 266 /** 267 * Gets the contents of the signature attribute on this member. So where the 'regular' signature may be 268 * (Ljava/util/Vector;)V the signature attribute may in fact say 'Ljava/lang/Vector<Ljava/lang/String>;' Coded for 269 * performance - searches for the attribute only when requested - only searches for it once. 270 * 271 * @return The generic signature. 272 * @since 6.0 273 */ 274 public final String getGenericSignature() { 275 if (!searchedForSignatureAttribute) { 276 boolean found = false; 277 for (int i = 0; !found && i < attributes.length; i++) { 278 if (attributes[i] instanceof Signature) { 279 signatureAttributeString = ((Signature) attributes[i]).getSignature(); 280 found = true; 281 } 282 } 283 searchedForSignatureAttribute = true; 284 } 285 return signatureAttributeString; 286 } 287 288 /** 289 * Gets the name of object. 290 * 291 * @return Name of object, that is, method name or field name. 292 */ 293 public final String getName() { 294 return constant_pool.getConstantUtf8(name_index).getBytes(); 295 } 296 297 /** 298 * Gets the index in constant pool of object's name. 299 * 300 * @return Index in constant pool of object's name. 301 */ 302 public final int getNameIndex() { 303 return name_index; 304 } 305 306 /** 307 * Gets the string representation of object's type signature. 308 * 309 * @return String representation of object's type signature (Java style). 310 */ 311 public final String getSignature() { 312 return constant_pool.getConstantUtf8(signature_index).getBytes(); 313 } 314 315 /** 316 * Gets the index in constant pool of field signature. 317 * 318 * @return Index in constant pool of field signature. 319 */ 320 public final int getSignatureIndex() { 321 return signature_index; 322 } 323 324 /** 325 * Sets the collection of object attributes. 326 * 327 * @param attributes Collection of object attributes. 328 */ 329 public final void setAttributes(final Attribute[] attributes) { 330 this.attributes = attributes != null ? attributes : Attribute.EMPTY_ARRAY; 331 this.attributes_count = this.attributes.length; // init deprecated field 332 } 333 334 /** 335 * Sets the constant pool to be used for this object. 336 * 337 * @param constantPool Constant pool to be used for this object. 338 */ 339 public final void setConstantPool(final ConstantPool constantPool) { 340 this.constant_pool = constantPool; 341 } 342 343 /** 344 * Sets the index in constant pool of object's name. 345 * 346 * @param nameIndex Index in constant pool of object's name. 347 */ 348 public final void setNameIndex(final int nameIndex) { 349 this.name_index = nameIndex; 350 } 351 352 /** 353 * Sets the index in constant pool of field signature. 354 * 355 * @param signatureIndex Index in constant pool of field signature. 356 */ 357 public final void setSignatureIndex(final int signatureIndex) { 358 this.signature_index = signatureIndex; 359 } 360}