1 /* 2 * Javassist, a Java-bytecode translator toolkit. 3 * Copyright (C) 1999- Shigeru Chiba. All Rights Reserved. 4 * 5 * The contents of this file are subject to the Mozilla Public License Version 6 * 1.1 (the "License"); you may not use this file except in compliance with 7 * the License. Alternatively, the contents of this file may be used under 8 * the terms of the GNU Lesser General Public License Version 2.1 or later, 9 * or the Apache License Version 2.0. 10 * 11 * Software distributed under the License is distributed on an "AS IS" basis, 12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 13 * for the specific language governing rights and limitations under the 14 * License. 15 */ 16 17 package javassist.bytecode; 18 19 import java.io.DataInputStream; 20 import java.io.DataOutputStream; 21 import java.io.IOException; 22 import java.util.ArrayList; 23 import java.util.List; 24 25 /** 26 * <code>field_info</code> structure. 27 * 28 * <p>The following code adds a public field <code>width</code> 29 * of <code>int</code> type: 30 * <blockquote><pre> 31 * ClassFile cf = ... 32 * FieldInfo f = new FieldInfo(cf.getConstPool(), "width", "I"); 33 * f.setAccessFlags(AccessFlag.PUBLIC); 34 * cf.addField(f); 35 * </pre></blockquote> 36 * 37 * @see javassist.CtField#getFieldInfo() 38 */ 39 public final class FieldInfo { 40 ConstPool constPool; 41 int accessFlags; 42 int name; 43 String cachedName; 44 String cachedType; 45 int descriptor; 46 List<AttributeInfo> attribute; // may be null. 47 FieldInfo(ConstPool cp)48 private FieldInfo(ConstPool cp) { 49 constPool = cp; 50 accessFlags = 0; 51 attribute = null; 52 } 53 54 /** 55 * Constructs a <code>field_info</code> structure. 56 * 57 * @param cp a constant pool table 58 * @param fieldName field name 59 * @param desc field descriptor 60 * 61 * @see Descriptor 62 */ FieldInfo(ConstPool cp, String fieldName, String desc)63 public FieldInfo(ConstPool cp, String fieldName, String desc) { 64 this(cp); 65 name = cp.addUtf8Info(fieldName); 66 cachedName = fieldName; 67 descriptor = cp.addUtf8Info(desc); 68 } 69 FieldInfo(ConstPool cp, DataInputStream in)70 FieldInfo(ConstPool cp, DataInputStream in) throws IOException { 71 this(cp); 72 read(in); 73 } 74 75 /** 76 * Returns a string representation of the object. 77 */ 78 @Override toString()79 public String toString() { 80 return getName() + " " + getDescriptor(); 81 } 82 83 /** 84 * Copies all constant pool items to a given new constant pool 85 * and replaces the original items with the new ones. 86 * This is used for garbage collecting the items of removed fields 87 * and methods. 88 * 89 * @param cp the destination 90 */ compact(ConstPool cp)91 void compact(ConstPool cp) { 92 name = cp.addUtf8Info(getName()); 93 descriptor = cp.addUtf8Info(getDescriptor()); 94 attribute = AttributeInfo.copyAll(attribute, cp); 95 constPool = cp; 96 } 97 prune(ConstPool cp)98 void prune(ConstPool cp) { 99 List<AttributeInfo> newAttributes = new ArrayList<AttributeInfo>(); 100 AttributeInfo invisibleAnnotations 101 = getAttribute(AnnotationsAttribute.invisibleTag); 102 if (invisibleAnnotations != null) { 103 invisibleAnnotations = invisibleAnnotations.copy(cp, null); 104 newAttributes.add(invisibleAnnotations); 105 } 106 107 AttributeInfo visibleAnnotations 108 = getAttribute(AnnotationsAttribute.visibleTag); 109 if (visibleAnnotations != null) { 110 visibleAnnotations = visibleAnnotations.copy(cp, null); 111 newAttributes.add(visibleAnnotations); 112 } 113 114 AttributeInfo signature 115 = getAttribute(SignatureAttribute.tag); 116 if (signature != null) { 117 signature = signature.copy(cp, null); 118 newAttributes.add(signature); 119 } 120 121 int index = getConstantValue(); 122 if (index != 0) { 123 index = constPool.copy(index, cp, null); 124 newAttributes.add(new ConstantAttribute(cp, index)); 125 } 126 127 attribute = newAttributes; 128 name = cp.addUtf8Info(getName()); 129 descriptor = cp.addUtf8Info(getDescriptor()); 130 constPool = cp; 131 } 132 133 /** 134 * Returns the constant pool table used 135 * by this <code>field_info</code>. 136 */ getConstPool()137 public ConstPool getConstPool() { 138 return constPool; 139 } 140 141 /** 142 * Returns the field name. 143 */ getName()144 public String getName() { 145 if (cachedName == null) 146 cachedName = constPool.getUtf8Info(name); 147 148 return cachedName; 149 } 150 151 /** 152 * Sets the field name. 153 */ setName(String newName)154 public void setName(String newName) { 155 name = constPool.addUtf8Info(newName); 156 cachedName = newName; 157 } 158 159 /** 160 * Returns the access flags. 161 * 162 * @see AccessFlag 163 */ getAccessFlags()164 public int getAccessFlags() { 165 return accessFlags; 166 } 167 168 /** 169 * Sets the access flags. 170 * 171 * @see AccessFlag 172 */ setAccessFlags(int acc)173 public void setAccessFlags(int acc) { 174 accessFlags = acc; 175 } 176 177 /** 178 * Returns the field descriptor. 179 * 180 * @see Descriptor 181 */ getDescriptor()182 public String getDescriptor() { 183 return constPool.getUtf8Info(descriptor); 184 } 185 186 /** 187 * Sets the field descriptor. 188 * 189 * @see Descriptor 190 */ setDescriptor(String desc)191 public void setDescriptor(String desc) { 192 if (!desc.equals(getDescriptor())) 193 descriptor = constPool.addUtf8Info(desc); 194 } 195 196 /** 197 * Finds a ConstantValue attribute and returns the index into 198 * the <code>constant_pool</code> table. 199 * 200 * @return 0 if a ConstantValue attribute is not found. 201 */ getConstantValue()202 public int getConstantValue() { 203 if ((accessFlags & AccessFlag.STATIC) == 0) 204 return 0; 205 206 ConstantAttribute attr 207 = (ConstantAttribute)getAttribute(ConstantAttribute.tag); 208 if (attr == null) 209 return 0; 210 return attr.getConstantValue(); 211 } 212 213 /** 214 * Returns all the attributes. The returned <code>List</code> object 215 * is shared with this object. If you add a new attribute to the list, 216 * the attribute is also added to the field represented by this 217 * object. If you remove an attribute from the list, it is also removed 218 * from the field. 219 * 220 * @return a list of <code>AttributeInfo</code> objects. 221 * @see AttributeInfo 222 */ getAttributes()223 public List<AttributeInfo> getAttributes() { 224 if (attribute == null) 225 attribute = new ArrayList<AttributeInfo>(); 226 227 return attribute; 228 } 229 230 /** 231 * Returns the attribute with the specified name. 232 * It returns null if the specified attribute is not found. 233 * 234 * <p>An attribute name can be obtained by, for example, 235 * {@link AnnotationsAttribute#visibleTag} or 236 * {@link AnnotationsAttribute#invisibleTag}. 237 * </p> 238 * 239 * @param name attribute name 240 * @see #getAttributes() 241 */ getAttribute(String name)242 public AttributeInfo getAttribute(String name) { 243 return AttributeInfo.lookup(attribute, name); 244 } 245 246 /** 247 * Removes an attribute with the specified name. 248 * 249 * @param name attribute name. 250 * @return the removed attribute or null. 251 * @since 3.21 252 */ removeAttribute(String name)253 public AttributeInfo removeAttribute(String name) { 254 return AttributeInfo.remove(attribute, name); 255 } 256 257 /** 258 * Appends an attribute. If there is already an attribute with 259 * the same name, the new one substitutes for it. 260 * 261 * @see #getAttributes() 262 */ addAttribute(AttributeInfo info)263 public void addAttribute(AttributeInfo info) { 264 if (attribute == null) 265 attribute = new ArrayList<AttributeInfo>(); 266 267 AttributeInfo.remove(attribute, info.getName()); 268 attribute.add(info); 269 } 270 read(DataInputStream in)271 private void read(DataInputStream in) throws IOException { 272 accessFlags = in.readUnsignedShort(); 273 name = in.readUnsignedShort(); 274 descriptor = in.readUnsignedShort(); 275 int n = in.readUnsignedShort(); 276 attribute = new ArrayList<AttributeInfo>(); 277 for (int i = 0; i < n; ++i) 278 attribute.add(AttributeInfo.read(constPool, in)); 279 } 280 write(DataOutputStream out)281 void write(DataOutputStream out) throws IOException { 282 out.writeShort(accessFlags); 283 out.writeShort(name); 284 out.writeShort(descriptor); 285 if (attribute == null) 286 out.writeShort(0); 287 else { 288 out.writeShort(attribute.size()); 289 AttributeInfo.writeAll(attribute, out); 290 } 291 } 292 } 293