AnnotationDirectoryItem.java revision 9ab2b45ec8531658e3acf0b96b11a214ce8d3b60
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.Util.Input; 32import org.jf.dexlib.Util.AnnotatedOutput; 33 34import java.util.Collections; 35import java.util.List; 36 37public class AnnotationDirectoryItem extends Item<AnnotationDirectoryItem> { 38 private AnnotationSetItem classAnnotations; 39 40 private FieldIdItem[] fieldAnnotationFields; 41 private AnnotationSetItem[] fieldAnnotations; 42 43 private MethodIdItem[] methodAnnotationMethods; 44 private AnnotationSetItem[] methodAnnotations; 45 46 private MethodIdItem[] parameterAnnotationMethods; 47 private AnnotationSetRefList[] parameterAnnotations; 48 49 /** 50 * typically each AnnotationDirectoryItem will have a distinct parent. The only case that isn't true is when 51 * the AnnotationDirectoryItem *only* contains class annotations, with no other type of annotation. In that 52 * case, the same AnnotationDirectoryItem could be referenced from multiple classes. 53 * This isn't a problem though, because this field is only used in compareTo to determine the sort order, 54 * which handles it as a special case 55 */ 56 private ClassDefItem parent = null; 57 58 /** 59 * Creates a new uninitialized <code>AnnotationDirectoryItem</code> 60 * @param dexFile The <code>DexFile</code> that this item belongs to 61 */ 62 protected AnnotationDirectoryItem(DexFile dexFile) { 63 super(dexFile); 64 } 65 66 /** 67 * Creates a new <code>AnnotationDirectoryItem</code> with the given values 68 * @param dexFile The <code>DexFile</code> that this item belongs to 69 * @param classAnnotations The annotations associated with the overall class 70 * @param fieldAnnotationFields An array of <code>FieldIdItem</code> objects that the annotations in 71 * <code>fieldAnnotations</code> are associated with 72 * @param fieldAnnotations An array of <code>AnnotationSetItem</code> objects that contain the annotations for the 73 * fields in <code>fieldAnnotationFields</code> 74 * @param methodAnnotationMethods An array of <code>MethodIdItem</code> objects that the annotations in 75 * <code>methodAnnotations</code> are associated with 76 * @param methodAnnotations An array of <code>AnnotationSetItem</code> objects that contain the annotations for the 77 * methods in <code>methodAnnotationMethods</code> 78 * @param parameterAnnotationMethods An array of <code>MethodIdItem</code> objects that the annotations in 79 * <code>parameterAnnotations</code> are associated with 80 * @param parameterAnnotations An array of <code>AnnotationSetRefList</code> objects that contain the parameter 81 * annotations for the methods in <code>parameterAnnotationMethods</code> 82 */ 83 private AnnotationDirectoryItem(DexFile dexFile, AnnotationSetItem classAnnotations, 84 FieldIdItem[] fieldAnnotationFields, AnnotationSetItem[] fieldAnnotations, 85 MethodIdItem[] methodAnnotationMethods, AnnotationSetItem[] methodAnnotations, 86 MethodIdItem[] parameterAnnotationMethods, 87 AnnotationSetRefList[] parameterAnnotations) { 88 super(dexFile); 89 this.classAnnotations = classAnnotations; 90 this.fieldAnnotationFields = fieldAnnotationFields; 91 this.fieldAnnotations = fieldAnnotations; 92 this.methodAnnotationMethods = methodAnnotationMethods; 93 this.methodAnnotations = methodAnnotations; 94 this.parameterAnnotationMethods = parameterAnnotationMethods; 95 this.parameterAnnotations = parameterAnnotations; 96 } 97 98 /** 99 * Returns an <code>AnnotationDirectoryItem</code> for the given values, and that has been interned into the given 100 * <code>DexFile</code> 101 * @param dexFile The <code>DexFile</code> that this item belongs to 102 * @param classAnnotations The annotations associated with the class 103 * @param fieldAnnotations A list of <code>FieldAnnotation</code> objects containing the field annotations 104 * @param methodAnnotations A list of <code>MethodAnnotation</code> objects containing the method annotations 105 * @param parameterAnnotations A list of <code>ParameterAnnotation</code> objects containin the parameter 106 * annotations 107 * @return an <code>AnnotationItem</code> for the given values, and that has been interned into the given 108 * <code>DexFile</code> 109 */ 110 public static AnnotationDirectoryItem getInternedAnnotationDirectoryItem(DexFile dexFile, 111 AnnotationSetItem classAnnotations, 112 List<FieldAnnotation> fieldAnnotations, 113 List<MethodAnnotation> methodAnnotations, 114 List<ParameterAnnotation> parameterAnnotations) { 115 FieldIdItem[] fieldAnnotationFields = null; 116 AnnotationSetItem[] fieldAnnotationsArray = null; 117 MethodIdItem[] methodAnnotationMethods = null; 118 AnnotationSetItem[] methodAnnotationsArray = null; 119 MethodIdItem[] parameterAnnotationMethods = null; 120 AnnotationSetRefList[] parameterAnnotationsArray = null; 121 122 if (fieldAnnotations != null && fieldAnnotations.size() > 0) { 123 fieldAnnotationFields = new FieldIdItem[fieldAnnotations.size()]; 124 fieldAnnotationsArray = new AnnotationSetItem[fieldAnnotations.size()]; 125 126 Collections.sort(fieldAnnotations); 127 128 int index = 0; 129 for (FieldAnnotation fieldAnnotation: fieldAnnotations) { 130 fieldAnnotationFields[index] = fieldAnnotation.field; 131 fieldAnnotationsArray[index++] = fieldAnnotation.annotationSet; 132 } 133 } 134 135 if (methodAnnotations != null && methodAnnotations.size() > 0) { 136 methodAnnotationMethods = new MethodIdItem[methodAnnotations.size()]; 137 methodAnnotationsArray = new AnnotationSetItem[methodAnnotations.size()]; 138 139 Collections.sort(methodAnnotations); 140 141 int index = 0; 142 for (MethodAnnotation methodAnnotation: methodAnnotations) { 143 methodAnnotationMethods[index] = methodAnnotation.method; 144 methodAnnotationsArray[index++] = methodAnnotation.annotationSet; 145 } 146 } 147 148 if (parameterAnnotations != null && parameterAnnotations.size() > 0) { 149 parameterAnnotationMethods = new MethodIdItem[parameterAnnotations.size()]; 150 parameterAnnotationsArray = new AnnotationSetRefList[parameterAnnotations.size()]; 151 152 Collections.sort(parameterAnnotations); 153 154 int index = 0; 155 for (ParameterAnnotation parameterAnnotation: parameterAnnotations) { 156 parameterAnnotationMethods[index] = parameterAnnotation.method; 157 parameterAnnotationsArray[index++] = parameterAnnotation.annotationSet; 158 } 159 } 160 161 AnnotationDirectoryItem annotationDirectoryItem = new AnnotationDirectoryItem(dexFile, classAnnotations, 162 fieldAnnotationFields, fieldAnnotationsArray, methodAnnotationMethods, methodAnnotationsArray, 163 parameterAnnotationMethods, parameterAnnotationsArray); 164 return dexFile.AnnotationDirectoriesSection.intern(annotationDirectoryItem); 165 } 166 167 /** {@inheritDoc} */ 168 protected void readItem(Input in, ReadContext readContext) { 169 classAnnotations = (AnnotationSetItem)readContext.getOffsettedItemByOffset(ItemType.TYPE_ANNOTATION_SET_ITEM, 170 in.readInt()); 171 fieldAnnotationFields = new FieldIdItem[in.readInt()]; 172 fieldAnnotations = new AnnotationSetItem[fieldAnnotationFields.length]; 173 174 methodAnnotationMethods = new MethodIdItem[in.readInt()]; 175 methodAnnotations = new AnnotationSetItem[methodAnnotationMethods.length]; 176 177 parameterAnnotationMethods = new MethodIdItem[in.readInt()]; 178 parameterAnnotations = new AnnotationSetRefList[parameterAnnotationMethods.length]; 179 180 for (int i=0; i<fieldAnnotations.length; i++) { 181 fieldAnnotationFields[i] = dexFile.FieldIdsSection.getItemByIndex(in.readInt()); 182 fieldAnnotations[i] = (AnnotationSetItem)readContext.getOffsettedItemByOffset( 183 ItemType.TYPE_ANNOTATION_SET_ITEM, in.readInt()); 184 } 185 186 for (int i=0; i<methodAnnotations.length; i++) { 187 methodAnnotationMethods[i] = dexFile.MethodIdsSection.getItemByIndex(in.readInt()); 188 methodAnnotations[i] = (AnnotationSetItem)readContext.getOffsettedItemByOffset( 189 ItemType.TYPE_ANNOTATION_SET_ITEM, in.readInt()); 190 } 191 192 for (int i=0; i<parameterAnnotations.length; i++) { 193 parameterAnnotationMethods[i] = dexFile.MethodIdsSection.getItemByIndex(in.readInt()); 194 parameterAnnotations[i] = (AnnotationSetRefList)readContext.getOffsettedItemByOffset( 195 ItemType.TYPE_ANNOTATION_SET_REF_LIST, in.readInt()); 196 } 197 } 198 199 /** {@inheritDoc} */ 200 protected int placeItem(int offset) { 201 return offset + 16 + ( 202 (fieldAnnotations==null?0:fieldAnnotations.length) + 203 (methodAnnotations==null?0:methodAnnotations.length) + 204 (parameterAnnotations==null?0:parameterAnnotations.length)) * 8; 205 } 206 207 /** {@inheritDoc} */ 208 protected void writeItem(AnnotatedOutput out) { 209 if (out.annotates()) { 210 if (!isInternable() && parent != null) { 211 out.annotate(0, parent.getClassType().getTypeDescriptor()); 212 } 213 if (classAnnotations != null) { 214 out.annotate(4, "class_annotations_off: 0x" + Integer.toHexString(classAnnotations.getOffset())); 215 } else { 216 out.annotate(4, "class_annotations_off:"); 217 } 218 219 int length = fieldAnnotations==null?0:fieldAnnotations.length; 220 out.annotate(4, "annotated_fields_size: 0x" + Integer.toHexString(length) + " (" + 221 length + ")"); 222 length = methodAnnotations==null?0:methodAnnotations.length; 223 out.annotate(4, "annotated_methods_size: 0x" + Integer.toHexString(length) + " (" + 224 length + ")"); 225 length = parameterAnnotations==null?0:parameterAnnotations.length; 226 out.annotate(4, "annotated_parameters_size: 0x" + Integer.toHexString(length) + " (" + 227 length + ")"); 228 229 int index; 230 if (fieldAnnotations != null) { 231 index = 0; 232 for (int i=0; i<fieldAnnotations.length; i++) { 233 out.annotate(0, "[" + index++ + "] field_annotation"); 234 235 out.indent(); 236 out.annotate(4, "field: " + fieldAnnotationFields[i].getFieldName().getStringValue() + ":" + 237 fieldAnnotationFields[i].getFieldType().getTypeDescriptor()); 238 out.annotate(4, "annotations_off: 0x" + Integer.toHexString(fieldAnnotations[i].getOffset())); 239 out.deindent(); 240 } 241 } 242 243 if (methodAnnotations != null) { 244 index = 0; 245 for (int i=0; i<methodAnnotations.length; i++) { 246 out.annotate(0, "[" + index++ + "] method_annotation"); 247 out.indent(); 248 out.annotate(4, "method: " + methodAnnotationMethods[i].getMethodString()); 249 out.annotate(4, "annotations_off: 0x" + Integer.toHexString(methodAnnotations[i].getOffset())); 250 out.deindent(); 251 } 252 } 253 254 if (parameterAnnotations != null) { 255 index = 0; 256 for (int i=0; i<parameterAnnotations.length; i++) { 257 out.annotate(0, "[" + index++ + "] parameter_annotation"); 258 out.indent(); 259 out.annotate(4, "method: " + parameterAnnotationMethods[i].getMethodString()); 260 out.annotate(4, "annotations_off: 0x" + Integer.toHexString(parameterAnnotations[i].getOffset())); 261 } 262 } 263 } 264 265 out.writeInt(classAnnotations==null?0:classAnnotations.getOffset()); 266 out.writeInt(fieldAnnotations==null?0:fieldAnnotations.length); 267 out.writeInt(methodAnnotations==null?0:methodAnnotations.length); 268 out.writeInt(parameterAnnotations==null?0:parameterAnnotations.length); 269 270 if (fieldAnnotations != null) { 271 for (int i=0; i<fieldAnnotations.length; i++) { 272 out.writeInt(fieldAnnotationFields[i].getIndex()); 273 out.writeInt(fieldAnnotations[i].getOffset()); 274 } 275 } 276 277 if (methodAnnotations != null) { 278 for (int i=0; i<methodAnnotations.length; i++) { 279 out.writeInt(methodAnnotationMethods[i].getIndex()); 280 out.writeInt(methodAnnotations[i].getOffset()); 281 } 282 } 283 284 if (parameterAnnotations != null) { 285 for (int i=0; i<parameterAnnotations.length; i++) { 286 out.writeInt(parameterAnnotationMethods[i].getIndex()); 287 out.writeInt(parameterAnnotations[i].getOffset()); 288 } 289 } 290 } 291 292 /** {@inheritDoc} */public ItemType getItemType() { 293 return ItemType.TYPE_ANNOTATIONS_DIRECTORY_ITEM; 294 } 295 296 /** {@inheritDoc} */ 297 public String getConciseIdentity() { 298 return "annotation_directory_item @0x" + Integer.toHexString(getOffset()); 299 } 300 301 /** {@inheritDoc} */ 302 public int compareTo(AnnotationDirectoryItem o) { 303 if (!isInternable()) { 304 if (!o.isInternable()) { 305 return parent.compareTo(o.parent); 306 } 307 return -1; 308 } 309 310 if (!o.isInternable()) { 311 return 1; 312 } 313 314 return classAnnotations.compareTo(o.classAnnotations); 315 } 316 317 /** 318 * @return The annotations associated with the class 319 */ 320 public AnnotationSetItem getClassAnnotations() { 321 return classAnnotations; 322 } 323 324 /** 325 * Iterates over the field annotations, calling delegate.processFieldAnnotations for each 326 * @param delegate the delegate to call 327 */ 328 public void iterateFieldAnnotations(FieldAnnotationIteratorDelegate delegate) { 329 for (int i=0; i<fieldAnnotationFields.length; i++) { 330 delegate.processFieldAnnotations(fieldAnnotationFields[i], fieldAnnotations[i]); 331 } 332 } 333 334 public static interface FieldAnnotationIteratorDelegate { 335 void processFieldAnnotations(FieldIdItem field, AnnotationSetItem fieldAnnotations); 336 } 337 338 /** 339 * @return the number of field annotations in this <code>AnnotationDirectoryItem</code> 340 */ 341 public int getFieldAnnotationCount() { 342 return fieldAnnotationFields.length; 343 } 344 345 /** 346 * Iterates over the method annotations, calling delegate.processMethodAnnotations for each 347 * @param delegate the delegate to call 348 */ 349 public void iterateMethodAnnotations(MethodAnnotationIteratorDelegate delegate) { 350 for (int i=0; i<methodAnnotationMethods.length; i++) { 351 delegate.processMethodAnnotations(methodAnnotationMethods[i], methodAnnotations[i]); 352 } 353 } 354 355 public static interface MethodAnnotationIteratorDelegate { 356 void processMethodAnnotations(MethodIdItem method, AnnotationSetItem methodAnnotations); 357 } 358 359 /** 360 * @return the number of method annotations in this <code>AnnotationDirectoryItem</code> 361 */ 362 public int getMethodAnnotationCount() { 363 return methodAnnotationMethods.length; 364 } 365 366 /** 367 * Iterates over the parameter annotations, calling delegate.processParameterAnnotations for each 368 * @param delegate the delegate to call 369 */ 370 public void iterateParameterAnnotations(ParameterAnnotationIteratorDelegate delegate) { 371 for (int i=0; i<parameterAnnotationMethods.length; i++) { 372 delegate.processParameterAnnotations(parameterAnnotationMethods[i], parameterAnnotations[i]); 373 } 374 } 375 376 public static interface ParameterAnnotationIteratorDelegate { 377 void processParameterAnnotations(MethodIdItem method, AnnotationSetRefList parameterAnnotations); 378 } 379 380 /** 381 * @return the number of parameter annotations in this <code>AnnotationDirectoryItem</code> 382 */ 383 public int getParameterAnnotationCount() { 384 return parameterAnnotationMethods.length; 385 } 386 387 /** 388 * @return true if this <code>AnnotationDirectoryItem</code> is internable. It is only internable if it has 389 * only class annotations, but no field, method or parameter annotations 390 */ 391 private boolean isInternable() { 392 return classAnnotations != null && 393 (fieldAnnotations == null || fieldAnnotations.length == 0) && 394 (methodAnnotations == null || methodAnnotations.length == 0) && 395 (parameterAnnotations == null || parameterAnnotations.length == 0); 396 } 397 398 /** 399 * Sets the <code>ClassDefItem</code> that this <code>AnnotationDirectoryItem</code> is associated with. 400 * This is only applicable if this AnnotationDirectoryItem contains only class annotations, and no field, method 401 * or parameter annotations. 402 * @param classDefItem the <code>ClassDefItem</code> that this <code>AnnotationDirectoryItem</code> is associated 403 * with 404 */ 405 protected void setParent(ClassDefItem classDefItem) { 406 this.parent = classDefItem; 407 } 408 409 @Override 410 public int hashCode() { 411 //an instance is only internable if it has only class annotations, but 412 //no other type of annotation 413 if (!isInternable()) { 414 return super.hashCode(); 415 } 416 return classAnnotations.hashCode(); 417 } 418 419 @Override 420 public boolean equals(Object o) { 421 if (this==o) { 422 return true; 423 } 424 if (o==null || !this.getClass().equals(o.getClass())) { 425 return false; 426 } 427 428 AnnotationDirectoryItem other = (AnnotationDirectoryItem)o; 429 return (this.compareTo(other) == 0); 430 } 431 432 public static class FieldAnnotation implements Comparable<FieldAnnotation> { 433 public final FieldIdItem field; 434 public final AnnotationSetItem annotationSet; 435 436 public FieldAnnotation(FieldIdItem field, AnnotationSetItem annotationSet) { 437 this.field = field; 438 this.annotationSet = annotationSet; 439 } 440 441 public int compareTo(FieldAnnotation other) { 442 return field.compareTo(other.field); 443 } 444 } 445 446 public static class MethodAnnotation implements Comparable<MethodAnnotation> { 447 public final MethodIdItem method; 448 public final AnnotationSetItem annotationSet; 449 450 public MethodAnnotation(MethodIdItem method, AnnotationSetItem annotationSet) { 451 this.method = method; 452 this.annotationSet = annotationSet; 453 } 454 455 public int compareTo(MethodAnnotation other) { 456 return method.compareTo(other.method); 457 } 458 } 459 460 public static class ParameterAnnotation implements Comparable<ParameterAnnotation> { 461 public final MethodIdItem method; 462 public final AnnotationSetRefList annotationSet; 463 464 public ParameterAnnotation(MethodIdItem method, AnnotationSetRefList annotationSet) { 465 this.method = method; 466 this.annotationSet = annotationSet; 467 } 468 469 public int compareTo(ParameterAnnotation other) { 470 return method.compareTo(other.method); 471 } 472 } 473} 474