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 027/** 028 * Abstract super class for fields and methods. 029 */ 030public abstract class FieldOrMethod extends AccessFlags implements Cloneable, Node { 031 032 /** 033 * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter. 034 */ 035 @java.lang.Deprecated 036 protected int name_index; // Points to field name in constant pool 037 038 /** 039 * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter. 040 */ 041 @java.lang.Deprecated 042 protected int signature_index; // Points to encoded signature 043 044 /** 045 * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter. 046 */ 047 @java.lang.Deprecated 048 protected Attribute[] attributes; // Collection of attributes 049 050 /** 051 * @deprecated (since 6.0) will be removed (not needed) 052 */ 053 @java.lang.Deprecated 054 protected int attributes_count; // No. of attributes 055 056 // @since 6.0 057 private AnnotationEntry[] annotationEntries; // annotations defined on the field or method 058 059 /** 060 * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter. 061 */ 062 @java.lang.Deprecated 063 protected ConstantPool constant_pool; 064 065 private String signatureAttributeString; 066 private boolean searchedForSignatureAttribute; 067 068 FieldOrMethod() { 069 } 070 071 /** 072 * Constructs object from file stream. 073 * 074 * @param file Input stream. 075 * @param constantPool the constant pool. 076 * @throws IOException if an I/O error occurs. 077 */ 078 protected FieldOrMethod(final DataInput file, final ConstantPool constantPool) throws IOException { 079 this(file.readUnsignedShort(), file.readUnsignedShort(), file.readUnsignedShort(), null, constantPool); 080 final int attributesCount = file.readUnsignedShort(); 081 attributes = new Attribute[attributesCount]; 082 for (int i = 0; i < attributesCount; i++) { 083 attributes[i] = Attribute.readAttribute(file, constantPool); 084 } 085 this.attributes_count = attributesCount; // init deprecated field 086 } 087 088 /** 089 * Constructs object from file stream. 090 * 091 * @param file Input stream. 092 * @param constantPool the constant pool. 093 * @throws IOException if an I/O error occurs. 094 * @deprecated (6.0) Use {@link #FieldOrMethod(java.io.DataInput, ConstantPool)} instead. 095 */ 096 @java.lang.Deprecated 097 protected FieldOrMethod(final DataInputStream file, final ConstantPool constantPool) throws IOException { 098 this((DataInput) file, constantPool); 099 } 100 101 /** 102 * Initialize from another object. Note that both objects use the same references (shallow copy). Use clone() for a 103 * physical copy. 104 * 105 * @param c Source to copy. 106 */ 107 protected FieldOrMethod(final FieldOrMethod c) { 108 this(c.getAccessFlags(), c.getNameIndex(), c.getSignatureIndex(), c.getAttributes(), c.getConstantPool()); 109 } 110 111 /** 112 * Constructs a FieldOrMethod. 113 * 114 * @param accessFlags Access rights of method. 115 * @param nameIndex Points to field name in constant pool. 116 * @param signatureIndex Points to encoded signature. 117 * @param attributes Collection of attributes. 118 * @param constantPool Array of constants. 119 */ 120 protected FieldOrMethod(final int accessFlags, final int nameIndex, final int signatureIndex, final Attribute[] attributes, 121 final ConstantPool constantPool) { 122 super(accessFlags); 123 this.name_index = nameIndex; 124 this.signature_index = signatureIndex; 125 this.constant_pool = constantPool; 126 setAttributes(attributes); 127 } 128 129 /** 130 * Creates a deep copy of this field. 131 * 132 * @param constantPool the constant pool. 133 * @return deep copy of this field. 134 */ 135 protected FieldOrMethod copy_(final ConstantPool constantPool) { 136 try { 137 final FieldOrMethod c = (FieldOrMethod) clone(); 138 c.constant_pool = constantPool; 139 c.attributes = new Attribute[attributes.length]; 140 c.attributes_count = attributes_count; // init deprecated field 141 Arrays.setAll(c.attributes, i -> attributes[i].copy(constantPool)); 142 return c; 143 } catch (final CloneNotSupportedException e) { 144 throw new UnsupportedOperationException(e); 145 } 146 } 147 148 /** 149 * Dumps object to file stream on binary format. 150 * 151 * @param file Output file stream. 152 * @throws IOException if an I/O error occurs. 153 */ 154 public final void dump(final DataOutputStream file) throws IOException { 155 file.writeShort(super.getAccessFlags()); 156 file.writeShort(name_index); 157 file.writeShort(signature_index); 158 file.writeShort(attributes_count); 159 for (final Attribute attribute : attributes) { 160 attribute.dump(file); 161 } 162 } 163 164 /** 165 * Gets annotations on the field or method. 166 * 167 * @return Annotations on the field or method. 168 * @since 6.0 169 */ 170 public AnnotationEntry[] getAnnotationEntries() { 171 if (annotationEntries == null) { 172 annotationEntries = AnnotationEntry.createAnnotationEntries(getAttributes()); 173 } 174 175 return annotationEntries; 176 } 177 178 /** 179 * Gets attribute for given tag. 180 * 181 * @param <T> the attribute type. 182 * @param tag the attribute tag. 183 * @return Attribute for given tag, null if not found. 184 * Refer to {@link org.apache.bcel.Const#ATTR_UNKNOWN} constants named ATTR_* for possible values. 185 * @since 6.10.0 186 */ 187 @SuppressWarnings("unchecked") 188 public final <T extends Attribute> T getAttribute(final byte tag) { 189 for (final Attribute attribute : getAttributes()) { 190 if (attribute.getTag() == tag) { 191 return (T) attribute; 192 } 193 } 194 return null; 195 } 196 197 /** 198 * Gets the collection of object attributes. 199 * 200 * @return Collection of object attributes. 201 */ 202 public final Attribute[] getAttributes() { 203 return attributes; 204 } 205 206 /** 207 * Gets the constant pool used by this object. 208 * 209 * @return Constant pool used by this object. 210 */ 211 public final ConstantPool getConstantPool() { 212 return constant_pool; 213 } 214 215 /** 216 * Hunts for a signature attribute on the member and returns its contents. So where the 'regular' signature may be 217 * (Ljava/util/Vector;)V the signature attribute may in fact say 'Ljava/lang/Vector<Ljava/lang/String>;' Coded for 218 * performance - searches for the attribute only when requested - only searches for it once. 219 * 220 * @return the generic signature. 221 * @since 6.0 222 */ 223 public final String getGenericSignature() { 224 if (!searchedForSignatureAttribute) { 225 boolean found = false; 226 for (int i = 0; !found && i < attributes.length; i++) { 227 if (attributes[i] instanceof Signature) { 228 signatureAttributeString = ((Signature) attributes[i]).getSignature(); 229 found = true; 230 } 231 } 232 searchedForSignatureAttribute = true; 233 } 234 return signatureAttributeString; 235 } 236 237 /** 238 * Gets the name of object. 239 * 240 * @return Name of object, that is, method name or field name. 241 */ 242 public final String getName() { 243 return constant_pool.getConstantUtf8(name_index).getBytes(); 244 } 245 246 /** 247 * Gets the index in constant pool of object's name. 248 * 249 * @return Index in constant pool of object's name. 250 */ 251 public final int getNameIndex() { 252 return name_index; 253 } 254 255 /** 256 * Gets the string representation of object's type signature. 257 * 258 * @return String representation of object's type signature (Java style). 259 */ 260 public final String getSignature() { 261 return constant_pool.getConstantUtf8(signature_index).getBytes(); 262 } 263 264 /** 265 * Gets the index in constant pool of field signature. 266 * 267 * @return Index in constant pool of field signature. 268 */ 269 public final int getSignatureIndex() { 270 return signature_index; 271 } 272 273 /** 274 * Sets the collection of object attributes. 275 * 276 * @param attributes Collection of object attributes. 277 */ 278 public final void setAttributes(final Attribute[] attributes) { 279 this.attributes = attributes != null ? attributes : Attribute.EMPTY_ARRAY; 280 this.attributes_count = this.attributes.length; // init deprecated field 281 } 282 283 /** 284 * Sets the constant pool to be used for this object. 285 * 286 * @param constantPool Constant pool to be used for this object. 287 */ 288 public final void setConstantPool(final ConstantPool constantPool) { 289 this.constant_pool = constantPool; 290 } 291 292 /** 293 * Sets the index in constant pool of object's name. 294 * 295 * @param nameIndex Index in constant pool of object's name. 296 */ 297 public final void setNameIndex(final int nameIndex) { 298 this.name_index = nameIndex; 299 } 300 301 /** 302 * Sets the index in constant pool of field signature. 303 * 304 * @param signatureIndex Index in constant pool of field signature. 305 */ 306 public final void setSignatureIndex(final int signatureIndex) { 307 this.signature_index = signatureIndex; 308 } 309}