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