AnnotationDirectoryItem.java revision 83b80f81d311b233188c281059aad4a9f5e8b4e6
1/* 2 * [The "BSD licence"] 3 * Copyright (c) 2009 Ben Gruver 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29package org.jf.dexlib; 30 31import org.jf.dexlib.EncodedValue.AnnotationEncodedSubValue; 32import org.jf.dexlib.Util.ArrayUtils; 33import org.jf.dexlib.Util.Input; 34import org.jf.dexlib.Util.AnnotatedOutput; 35 36import java.util.ArrayList; 37import java.util.Collections; 38import java.util.List; 39 40public class AnnotationDirectoryItem extends Item<AnnotationDirectoryItem> { 41 private AnnotationSetItem classAnnotations; 42 43 private FieldIdItem[] fieldAnnotationFields; 44 private AnnotationSetItem[] fieldAnnotations; 45 46 private MethodIdItem[] methodAnnotationMethods; 47 private AnnotationSetItem[] methodAnnotations; 48 49 private MethodIdItem[] parameterAnnotationMethods; 50 private AnnotationSetRefList[] parameterAnnotations; 51 52 /** 53 * typically each AnnotationDirectoryItem will have a distinct parent. The only case that isn't true is when 54 * the AnnotationDirectoryItem *only* contains class annotations, with no other type of annotation. In that 55 * case, the same AnnotationDirectoryItem could be referenced from multiple classes. 56 * This isn't a problem though, because this field is only used in compareTo to determine the sort order, 57 * which handles it as a special case 58 */ 59 private ClassDefItem parent = null; 60 61 /** 62 * Creates a new uninitialized <code>AnnotationDirectoryItem</code> 63 * @param dexFile The <code>DexFile</code> that this item belongs to 64 */ 65 protected AnnotationDirectoryItem(DexFile dexFile) { 66 super(dexFile); 67 } 68 69 /** 70 * Creates a new <code>AnnotationDirectoryItem</code> with the given values 71 * @param dexFile The <code>DexFile</code> that this item belongs to 72 * @param classAnnotations The annotations associated with the overall class 73 * @param fieldAnnotationFields An array of <code>FieldIdItem</code> objects that the annotations in 74 * <code>fieldAnnotations</code> are associated with 75 * @param fieldAnnotations An array of <code>AnnotationSetItem</code> objects that contain the annotations for the 76 * fields in <code>fieldAnnotationFields</code> 77 * @param methodAnnotationMethods An array of <code>MethodIdItem</code> objects that the annotations in 78 * <code>methodAnnotations</code> are associated with 79 * @param methodAnnotations An array of <code>AnnotationSetItem</code> objects that contain the annotations for the 80 * methods in <code>methodAnnotationMethods</code> 81 * @param parameterAnnotationMethods An array of <code>MethodIdItem</code> objects that the annotations in 82 * <code>parameterAnnotations</code> are associated with 83 * @param parameterAnnotations An array of <code>AnnotationSetRefList</code> objects that contain the parameter 84 * annotations for the methods in <code>parameterAnnotationMethods</code> 85 */ 86 private AnnotationDirectoryItem(DexFile dexFile, AnnotationSetItem classAnnotations, 87 FieldIdItem[] fieldAnnotationFields, AnnotationSetItem[] fieldAnnotations, 88 MethodIdItem[] methodAnnotationMethods, AnnotationSetItem[] methodAnnotations, 89 MethodIdItem[] parameterAnnotationMethods, 90 AnnotationSetRefList[] parameterAnnotations) { 91 super(dexFile); 92 this.classAnnotations = classAnnotations; 93 this.fieldAnnotationFields = fieldAnnotationFields; 94 this.fieldAnnotations = fieldAnnotations; 95 this.methodAnnotationMethods = methodAnnotationMethods; 96 this.methodAnnotations = methodAnnotations; 97 this.parameterAnnotationMethods = parameterAnnotationMethods; 98 this.parameterAnnotations = parameterAnnotations; 99 } 100 101 /** 102 * Returns an <code>AnnotationDirectoryItem</code> for the given values, and that has been interned into the given 103 * <code>DexFile</code> 104 * @param dexFile The <code>DexFile</code> that this item belongs to 105 * @param classAnnotations The annotations associated with the class 106 * @param fieldAnnotationFields An array of <code>FieldIdItem</code> objects that the annotations in 107 * <code>fieldAnnotations</code> are associated with 108 * @param fieldAnnotations An array of <code>AnnotationSetItem</code> objects that contain the annotations for the 109 * fields in <code>fieldAnnotationFields</code> 110 * @param methodAnnotationMethods An array of <code>MethodIdItem</code> objects that the annotations in 111 * <code>methodAnnotations</code> are associated with 112 * @param methodAnnotations An array of <code>AnnotationSetItem</code> objects that contain the annotations for the 113 * methods in <code>methodAnnotationMethods</code> 114 * @param parameterAnnotationMethods An array of <code>MethodIdItem</code> objects that the annotations in 115 * <code>parameterAnnotations</code> are associated with 116 * @param parameterAnnotations An array of <code>AnnotationSetRefList</code> objects that contain the parameter 117 * annotations for the methods in <code>parameterAnnotationMethods</code> 118 * @return an <code>AnnotationItem</code> for the given values, and that has been interned into the given 119 * <code>DexFile</code> 120 */ 121 public static AnnotationDirectoryItem getInternedAnnotationDirectoryItem(DexFile dexFile, 122 AnnotationSetItem classAnnotations, 123 FieldIdItem[] fieldAnnotationFields, AnnotationSetItem[] fieldAnnotations, 124 MethodIdItem[] methodAnnotationMethods, AnnotationSetItem[] methodAnnotations, 125 MethodIdItem[] parameterAnnotationMethods, 126 AnnotationSetRefList[] parameterAnnotations) { 127 AnnotationDirectoryItem annotationDirectoryItem = new AnnotationDirectoryItem(dexFile, classAnnotations, 128 fieldAnnotationFields, fieldAnnotations, methodAnnotationMethods, methodAnnotations, 129 parameterAnnotationMethods, parameterAnnotations); 130 return dexFile.AnnotationDirectoriesSection.intern(annotationDirectoryItem); 131 } 132 133 /** {@inheritDoc} */ 134 protected void readItem(Input in, ReadContext readContext) { 135 readContext.getOffsettedItemByOffset(ItemType.TYPE_ANNOTATION_SET_ITEM, in.readInt()); 136 fieldAnnotationFields = new FieldIdItem[in.readInt()]; 137 fieldAnnotations = new AnnotationSetItem[fieldAnnotationFields.length]; 138 139 methodAnnotationMethods = new MethodIdItem[in.readInt()]; 140 methodAnnotations = new AnnotationSetItem[methodAnnotationMethods.length]; 141 142 parameterAnnotationMethods = new MethodIdItem[in.readInt()]; 143 parameterAnnotations = new AnnotationSetRefList[parameterAnnotationMethods.length]; 144 145 for (int i=0; i<fieldAnnotations.length; i++) { 146 fieldAnnotationFields[i] = dexFile.FieldIdsSection.getItemByIndex(in.readInt()); 147 fieldAnnotations[i] = (AnnotationSetItem)readContext.getOffsettedItemByOffset( 148 ItemType.TYPE_ANNOTATION_SET_ITEM, in.readInt()); 149 } 150 151 for (int i=0; i<methodAnnotations.length; i++) { 152 methodAnnotationMethods[i] = dexFile.MethodIdsSection.getItemByIndex(in.readInt()); 153 methodAnnotations[i] = (AnnotationSetItem)readContext.getOffsettedItemByOffset( 154 ItemType.TYPE_ANNOTATION_SET_ITEM, in.readInt()); 155 } 156 157 for (int i=0; i<parameterAnnotations.length; i++) { 158 parameterAnnotationMethods[i] = dexFile.MethodIdsSection.getItemByIndex(in.readInt()); 159 parameterAnnotations[i] = (AnnotationSetRefList)readContext.getOffsettedItemByOffset( 160 ItemType.TYPE_ANNOTATION_SET_REF_LIST, in.readInt()); 161 } 162 } 163 164 /** {@inheritDoc} */ 165 protected int placeItem(int offset) { 166 if (!dexFile.getInplace()) { 167 ArrayUtils.sortTwoArrays(fieldAnnotationFields, fieldAnnotations); 168 ArrayUtils.sortTwoArrays(methodAnnotationMethods, methodAnnotations); 169 ArrayUtils.sortTwoArrays(parameterAnnotationMethods, parameterAnnotations); 170 } 171 172 return offset + 16 + fieldAnnotations.length * 8 + methodAnnotations.length * 8 + 173 parameterAnnotations.length * 8; 174 } 175 176 /** {@inheritDoc} */ 177 protected void writeItem(AnnotatedOutput out) { 178 if (out.annotates()) { 179 out.annotate(4, "class_annotations_off"); 180 out.annotate(4, "annotated_fields_size"); 181 out.annotate(4, "annotated_methods_size"); 182 out.annotate(4, "annotated_parameters_size"); 183 184 185 for (int i=0; i<fieldAnnotations.length; i++) { 186 out.annotate(4, "field_idx"); 187 out.annotate(4, "annotations_off"); 188 } 189 190 for (int i=0; i<methodAnnotations.length; i++) { 191 out.annotate(4, "method_idx"); 192 out.annotate(4, "annotations_off"); 193 } 194 195 for (int i=0; i<parameterAnnotations.length; i++) { 196 out.annotate(4, "method_idx"); 197 out.annotate(4, "annotations_off"); 198 } 199 } 200 201 out.writeInt(classAnnotations==null?0:classAnnotations.getOffset()); 202 203 for (int i=0; i<fieldAnnotations.length; i++) { 204 out.writeInt(fieldAnnotationFields[i].getIndex()); 205 out.writeInt(fieldAnnotations[i].getOffset()); 206 } 207 208 for (int i=0; i<methodAnnotations.length; i++) { 209 out.writeInt(methodAnnotationMethods[i].getIndex()); 210 out.writeInt(methodAnnotations[i].getOffset()); 211 } 212 213 for (int i=0; i<parameterAnnotations.length; i++) { 214 out.writeInt(parameterAnnotationMethods[i].getIndex()); 215 out.writeInt(parameterAnnotations[i].getOffset()); 216 } 217 } 218 219 /** {@inheritDoc} */public ItemType getItemType() { 220 return ItemType.TYPE_ANNOTATIONS_DIRECTORY_ITEM; 221 } 222 223 /** {@inheritDoc} */ 224 public String getConciseIdentity() { 225 return "annotation_directory_item @0x" + Integer.toHexString(getOffset()); 226 } 227 228 /** {@inheritDoc} */ 229 public int compareTo(AnnotationDirectoryItem o) { 230 if (!isInternable()) { 231 if (!o.isInternable()) { 232 return parent.compareTo(o.parent); 233 } 234 return -1; 235 } 236 237 if (!o.isInternable()) { 238 return 1; 239 } 240 241 return classAnnotations.compareTo(o.classAnnotations); 242 } 243 244 /** 245 * @return The annotations associated with the class 246 */ 247 public AnnotationSetItem getClassAnnotations() { 248 return classAnnotations; 249 } 250 251 /** 252 * Iterates over the field annotations, calling delegate.processFieldAnnotations for each 253 * @param delegate the delegate to call 254 */ 255 public void iterateFieldAnnotations(FieldAnnotationIteratorDelegate delegate) { 256 for (int i=0; i<fieldAnnotationFields.length; i++) { 257 delegate.processFieldAnnotations(fieldAnnotationFields[i], fieldAnnotations[i]); 258 } 259 } 260 261 public static interface FieldAnnotationIteratorDelegate { 262 void processFieldAnnotations(FieldIdItem field, AnnotationSetItem fieldAnnotations); 263 } 264 265 /** 266 * Iterates over the method annotations, calling delegate.processMethodAnnotations for each 267 * @param delegate the delegate to call 268 */ 269 public void iterateMethodAnnotations(MethodAnnotationIteratorDelegate delegate) { 270 for (int i=0; i<methodAnnotationMethods.length; i++) { 271 delegate.processMethodAnnotations(methodAnnotationMethods[i], methodAnnotations[i]); 272 } 273 } 274 275 public static interface MethodAnnotationIteratorDelegate { 276 void processMethodAnnotations(MethodIdItem method, AnnotationSetItem methodAnnotations); 277 } 278 279 /** 280 * Iterates over the parameter annotations, calling delegate.processParameterAnnotations for each 281 * @param delegate the delegate to call 282 */ 283 public void iteratParameterAnnotations(ParameterAnnotationIteratorDelegate delegate) { 284 for (int i=0; i<parameterAnnotationMethods.length; i++) { 285 delegate.processParameterAnnotations(parameterAnnotationMethods[i], parameterAnnotations[i]); 286 } 287 } 288 289 public static interface ParameterAnnotationIteratorDelegate { 290 void processParameterAnnotations(MethodIdItem method, AnnotationSetRefList parameterAnnotations); 291 } 292 293 /** 294 * @return true if this <code>AnnotationDirectoryItem</code> is internable. It is only internable if it has 295 * only class annotations, but no field, method or parameter annotations 296 */ 297 private boolean isInternable() { 298 return classAnnotations != null && 299 fieldAnnotations.length == 0 && 300 methodAnnotations.length == 0 && 301 parameterAnnotations.length == 0; 302 } 303 304 /** 305 * Sets the <code>ClassDefItem</code> that this <code>AnnotationDirectoryItem</code> is associated with. 306 * This is only applicable if this AnnotationDirectoryItem contains only class annotations, and no field, method 307 * or parameter annotations. 308 * @param classDefItem the <code>ClassDefItem</code> that this <code>AnnotationDirectoryItem</code> is associated 309 * with 310 */ 311 protected void setParent(ClassDefItem classDefItem) { 312 this.parent = classDefItem; 313 } 314 315 @Override 316 public int hashCode() { 317 //an instance is only internable if it has only class annotations, but 318 //no other type of annotation 319 if (!isInternable()) { 320 return super.hashCode(); 321 } 322 return classAnnotations.hashCode(); 323 } 324 325 @Override 326 public boolean equals(Object o) { 327 if (this==o) { 328 return true; 329 } 330 if (o==null || !this.getClass().equals(o.getClass())) { 331 return false; 332 } 333 334 AnnotationDirectoryItem other = (AnnotationDirectoryItem)o; 335 return (this.compareTo(other) == 0); 336 } 337} 338