ClassfileInspector.java revision 3294:9adfb22ff08f
1/* 2 * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24package annotations.classfile; 25 26import java.io.*; 27import java.net.URL; 28 29import com.sun.tools.classfile.*; 30import com.sun.tools.classfile.ConstantPool.InvalidIndex; 31import com.sun.tools.classfile.ConstantPool.UnexpectedEntry; 32 33/** 34 * A class providing utilities for writing tests that inspect class 35 * files directly, looking for specific type annotations. 36 * 37 * Note: this framework does not currently handle repeating 38 * annotations. 39 */ 40public class ClassfileInspector { 41 42 /** 43 * A group of expected annotations to be found in a given class. 44 * If the class name is null, then the template will be applied to 45 * every class. 46 */ 47 public static class Expected { 48 /** 49 * The name of the class. If {@code null} this template will 50 * apply to every class; otherwise, it will only be applied to 51 * the named class. 52 */ 53 public final String classname; 54 55 /** 56 * The expected class annotations. These will be checked 57 * against the class' attributes. 58 */ 59 public final ExpectedAnnotation[] classAnnos; 60 61 /** 62 * The expected method annotations. These will be checked 63 * against all methods in the class. 64 */ 65 public final ExpectedMethodAnnotation[] methodAnnos; 66 67 /** 68 * The expected method parameter annotations. These will be checked 69 * against all methods in the class. 70 */ 71 public final ExpectedParameterAnnotation[] methodParamAnnos; 72 73 /** 74 * The expected field type annotations. These will be checked 75 * against all fields in the class. 76 */ 77 public final ExpectedFieldAnnotation[] fieldAnnos; 78 79 /** 80 * The expected class type annotations. These will be checked 81 * against the class' attributes. 82 */ 83 public final ExpectedTypeAnnotation[] classTypeAnnos; 84 85 /** 86 * The expected method type annotations. These will be checked 87 * against all methods in the class. 88 */ 89 public final ExpectedMethodTypeAnnotation[] methodTypeAnnos; 90 91 /** 92 * The expected field type annotations. These will be checked 93 * against all fields in the class. 94 */ 95 public final ExpectedFieldTypeAnnotation[] fieldTypeAnnos; 96 97 /** 98 * Create an {@code Expected} from all components. 99 * 100 * @param classname The name of the class to match, or {@code 101 * null} for all classes. 102 * @param classAnnos The expected class annotations. 103 * @param methodAnnos The expected method annotations. 104 * @param methodParamAnnos The expected method parameter annotations. 105 * @param fieldAnnos The expected field annotations. 106 * @param classTypeAnnos The expected class type annotations. 107 * @param methodTypeAnnos The expected method type annotations. 108 * @param fieldTypeAnnos The expected field type annotations. 109 */ 110 public Expected(String classname, 111 ExpectedAnnotation[] classAnnos, 112 ExpectedMethodAnnotation[] methodAnnos, 113 ExpectedParameterAnnotation[] methodParamAnnos, 114 ExpectedFieldAnnotation[] fieldAnnos, 115 ExpectedTypeAnnotation[] classTypeAnnos, 116 ExpectedMethodTypeAnnotation[] methodTypeAnnos, 117 ExpectedFieldTypeAnnotation[] fieldTypeAnnos) { 118 this.classname = classname; 119 this.classAnnos = classAnnos; 120 this.methodAnnos = methodAnnos; 121 this.methodParamAnnos = methodParamAnnos; 122 this.fieldAnnos = fieldAnnos; 123 this.classTypeAnnos = classTypeAnnos; 124 this.methodTypeAnnos = methodTypeAnnos; 125 this.fieldTypeAnnos = fieldTypeAnnos; 126 } 127 128 /** 129 * Create an {@code Expected} from regular annotation components. 130 * 131 * @param classname The name of the class to match, or {@code 132 * null} for all classes. 133 * @param classAnnos The expected class annotations. 134 * @param methodAnnos The expected method annotations. 135 * @param methodParamAnnos The expected method parameter annotations. 136 * @param fieldAnnos The expected field annotations. 137 */ 138 public Expected(String classname, 139 ExpectedAnnotation[] classAnnos, 140 ExpectedMethodAnnotation[] methodAnnos, 141 ExpectedParameterAnnotation[] methodParamAnnos, 142 ExpectedFieldAnnotation[] fieldAnnos) { 143 this(classname, classAnnos, methodAnnos, methodParamAnnos, 144 fieldAnnos, null, null, null); 145 } 146 147 /** 148 * Create an {@code Expected} from type annotation components. 149 * 150 * @param classname The name of the class to match, or {@code 151 * null} for all classes. 152 * @param classTypeAnnos The expected class type annotations. 153 * @param methodTypeAnnos The expected method type annotations. 154 * @param fieldTypeAnnos The expected field type annotations. 155 */ 156 public Expected(String classname, 157 ExpectedTypeAnnotation[] classTypeAnnos, 158 ExpectedMethodTypeAnnotation[] methodTypeAnnos, 159 ExpectedFieldTypeAnnotation[] fieldTypeAnnos) { 160 this(classname, null, null, null, null, 161 classTypeAnnos, methodTypeAnnos, fieldTypeAnnos); 162 } 163 164 @Override 165 public String toString() { 166 final StringBuilder sb = new StringBuilder(); 167 final String newline = System.lineSeparator(); 168 sb.append("Expected on class ").append(classname); 169 if (null != classAnnos) { 170 sb.append(newline).append("Class annotations:").append(newline); 171 for(ExpectedAnnotation anno : classAnnos) { 172 sb.append(anno).append(newline); 173 } 174 } 175 if (null != methodAnnos) { 176 sb.append(newline).append("Method annotations:").append(newline); 177 for(ExpectedAnnotation anno : methodAnnos) { 178 sb.append(anno).append(newline); 179 } 180 } 181 if (null != methodParamAnnos) { 182 sb.append(newline).append("Method param annotations:").append(newline); 183 for(ExpectedAnnotation anno : methodParamAnnos) { 184 sb.append(anno).append(newline); 185 } 186 } 187 if (null != fieldAnnos) { 188 sb.append(newline).append("Field annotations:").append(newline); 189 for(ExpectedAnnotation anno : fieldAnnos) { 190 sb.append(anno).append(newline); 191 } 192 } 193 if (null != classTypeAnnos) { 194 sb.append(newline).append("Class type annotations:").append(newline); 195 for(ExpectedAnnotation anno : classTypeAnnos) { 196 sb.append(anno).append(newline); 197 } 198 } 199 if (null != methodTypeAnnos) { 200 sb.append(newline).append("Method type annotations:").append(newline); 201 for(ExpectedAnnotation anno : methodTypeAnnos) { 202 sb.append(anno).append(newline); 203 } 204 } 205 if (null != fieldTypeAnnos) { 206 sb.append(newline).append("Field type annotations:").append(newline); 207 for(ExpectedAnnotation anno : fieldTypeAnnos) { 208 sb.append(anno).append(newline); 209 } 210 } 211 return sb.toString(); 212 } 213 214 /** 215 * See if this template applies to a class. 216 * 217 * @param classname The classname to check. 218 * @return Whether or not this template should apply. 219 */ 220 public boolean matchClassName(String classname) { 221 return this.classname == null || this.classname.equals(classname); 222 } 223 224 /** 225 * After applying the template to all classes, check to see if 226 * any of the expected annotations weren't matched. 227 * 228 * @return The number of missed matches. 229 */ 230 public int check() { 231 int count = 0; 232 if (classAnnos != null) { 233 for(ExpectedAnnotation expected : classAnnos) { 234 if (!expected.check()) { 235 count++; 236 } 237 } 238 } 239 if (methodAnnos != null) { 240 for(ExpectedAnnotation expected : methodAnnos) { 241 if (!expected.check()) { 242 count++; 243 } 244 } 245 } 246 if (methodParamAnnos != null) { 247 for(ExpectedAnnotation expected : methodParamAnnos) { 248 if (!expected.check()) { 249 count++; 250 } 251 } 252 } 253 if (fieldAnnos != null) { 254 for(ExpectedAnnotation expected : fieldAnnos) { 255 if (!expected.check()) { 256 count++; 257 } 258 } 259 } 260 if (classTypeAnnos != null) { 261 for(ExpectedAnnotation expected : classTypeAnnos) { 262 if (!expected.check()) { 263 count++; 264 } 265 } 266 } 267 if (methodTypeAnnos != null) { 268 for(ExpectedAnnotation expected : methodTypeAnnos) { 269 if (!expected.check()) { 270 count++; 271 } 272 } 273 } 274 if (fieldTypeAnnos != null) { 275 for(ExpectedAnnotation expected : fieldTypeAnnos) { 276 if (!expected.check()) { 277 count++; 278 } 279 } 280 } 281 return count; 282 } 283 } 284 285 /** 286 * An expected annotation. This is both a superclass for 287 * method, field, and type annotations, as well as a class for 288 * annotations on a class. 289 */ 290 public static class ExpectedAnnotation { 291 protected int count = 0; 292 protected final String expectedName; 293 protected final int expectedCount; 294 protected final boolean visibility; 295 296 /** 297 * Create an {@code ExpectedAnnotation} from its 298 * components. It is usually a better idea to use a {@code 299 * Builder} to do this. 300 * 301 * @param expectedName The expected annotation name. 302 * @param visibility Whether this annotation should be runtime-visible. 303 * @param expectedCount The number of annotations that should 304 * be seen. If 0, this asserts that the 305 * described annotation is not present. 306 */ 307 public ExpectedAnnotation(String expectedName, 308 boolean visibility, 309 int expectedCount) { 310 this.expectedName = expectedName; 311 this.visibility = visibility; 312 this.expectedCount = expectedCount; 313 } 314 315 @Override 316 public String toString() { 317 final StringBuilder sb = new StringBuilder(); 318 sb.append("Expected "); 319 sb.append(expectedCount); 320 sb.append(" annotation "); 321 sb.append(expectedName); 322 sb.append(visibility ? ", runtime visibile " : ", runtime invisibile "); 323 return sb.toString(); 324 } 325 326 /** 327 * See if this template matches the given visibility. 328 * 329 * @param Whether or not the annotation is visible at runtime. 330 * @return Whether or not this template matches the visibility. 331 */ 332 public boolean matchVisibility(boolean visibility) { 333 return this.visibility == visibility; 334 } 335 336 /** 337 * Attempty to match this template against an annotation. If 338 * it does match, then the match count for the template will 339 * be incremented. Otherwise, nothing will be done. 340 * 341 * @param anno The annotation to attempt to match. 342 */ 343 public void matchAnnotation(ConstantPool cpool, 344 Annotation anno) { 345 if (checkMatch(cpool, anno)) { 346 count++; 347 } 348 } 349 350 /** 351 * Indicate whether an annotation matches this expected 352 * annotation. 353 * 354 * @param ConstantPool The constant pool to use. 355 * @param anno The annotation to check. 356 * @return Whether the annotation matches. 357 */ 358 protected boolean checkMatch(ConstantPool cpool, 359 Annotation anno) { 360 try { 361 return cpool.getUTF8Info(anno.type_index).value.equals("L" + expectedName + ";"); 362 } catch (InvalidIndex | UnexpectedEntry e) { 363 return false; 364 } 365 } 366 367 /** 368 * After all matching, check to see if the expected number of 369 * matches equals the actual number. If not, then print a 370 * failure message and return {@code false}. 371 * 372 * @return Whether or not the expected number of matched 373 * equals the actual number. 374 */ 375 public boolean check() { 376 if (count != expectedCount) { 377 System.err.println(this + ", but saw " + count); 378 return false; 379 } else { 380 return true; 381 } 382 } 383 } 384 385 /** 386 * An annotation found on a method. 387 */ 388 public static class ExpectedMethodAnnotation extends ExpectedAnnotation { 389 protected final String methodname; 390 391 /** 392 * Create an {@code ExpectedMethodAnnotation} from its 393 * components. It is usually a better idea to use a {@code 394 * Builder} to do this. 395 * 396 * @param methodname The expected method name. 397 * @param expectedName The expected annotation name. 398 * @param visibility Whether this annotation should be runtime-visible. 399 * @param expectedCount The number of annotations that should be seen. 400 */ 401 public ExpectedMethodAnnotation(String methodname, 402 String expectedName, 403 boolean visibility, 404 int expectedCount) { 405 super(expectedName, visibility, expectedCount); 406 this.methodname = methodname; 407 } 408 409 @Override 410 public String toString() { 411 final StringBuilder sb = new StringBuilder(); 412 sb.append("Expected "); 413 sb.append(expectedCount); 414 sb.append(" annotation "); 415 sb.append(expectedName); 416 sb.append(visibility ? ", runtime visibile " : ", runtime invisibile "); 417 sb.append(" on method "); 418 sb.append(methodname); 419 return sb.toString(); 420 } 421 422 /** 423 * See if this template applies to a method. 424 * 425 * @param methodname The method name to check. 426 * @return Whether or not this template should apply. 427 */ 428 public boolean matchMethodName(String methodname) { 429 return this.methodname.equals(methodname); 430 } 431 432 } 433 434 /** 435 * An annotation found on a method parameter. 436 */ 437 public static class ExpectedParameterAnnotation 438 extends ExpectedMethodAnnotation { 439 protected final int index; 440 441 /** 442 * Create an {@code ExpectedParameterAnnotation} from its 443 * components. It is usually a better idea to use a {@code 444 * Builder} to do this. 445 * 446 * @param methodname The expected method name. 447 * @param index The parameter index. 448 * @param expectedName The expected annotation name. 449 * @param visibility Whether this annotation should be runtime-visible. 450 * @param expectedCount The number of annotations that should be seen. 451 */ 452 public ExpectedParameterAnnotation(String methodname, 453 int index, 454 String expectedName, 455 boolean visibility, 456 int expectedCount) { 457 super(methodname, expectedName, visibility, expectedCount); 458 this.index = index; 459 } 460 461 @Override 462 public String toString() { 463 final StringBuilder sb = new StringBuilder(); 464 sb.append("Expected "); 465 sb.append(expectedCount); 466 sb.append(" annotation "); 467 sb.append(expectedName); 468 sb.append(visibility ? ", runtime visibile " : ", runtime invisibile "); 469 sb.append(" on method "); 470 sb.append(methodname); 471 sb.append(" parameter "); 472 sb.append(index); 473 return sb.toString(); 474 } 475 476 } 477 478 /** 479 * An annotation found on a field. 480 */ 481 public static class ExpectedFieldAnnotation extends ExpectedAnnotation { 482 private final String fieldname; 483 484 /** 485 * Create an {@code ExpectedFieldAnnotation} from its 486 * components. It is usually a better idea to use a {@code 487 * Builder} to do this. 488 * 489 * @param fieldname The expected field name. 490 * @param expectedName The expected annotation name. 491 * @param visibility Whether this annotation should be runtime-visible. 492 * @param expectedCount The number of annotations that should be seen. 493 */ 494 public ExpectedFieldAnnotation(String fieldname, 495 String expectedName, 496 boolean visibility, 497 int expectedCount) { 498 super(expectedName, visibility, expectedCount); 499 this.fieldname = fieldname; 500 } 501 502 @Override 503 public String toString() { 504 final StringBuilder sb = new StringBuilder(); 505 sb.append("Expected ").append(expectedCount) 506 .append(" annotation ").append(expectedName) 507 .append(visibility ? ", runtime visibile " : ", runtime invisibile ") 508 .append(" on field ").append(fieldname); 509 return sb.toString(); 510 } 511 512 /** 513 * See if this template applies to a field. 514 * 515 * @param fieldname The field name to check. 516 * @return Whether or not this template should apply. 517 */ 518 public boolean matchFieldName(String fieldname) { 519 return this.fieldname.equals(fieldname); 520 } 521 522 } 523 524 /** 525 * An expected type annotation. This is both a superclass for 526 * method and field type annotations, as well as a class for type 527 * annotations on a class. 528 */ 529 public static class ExpectedTypeAnnotation extends ExpectedAnnotation { 530 protected final TypeAnnotation.TargetType targetType; 531 protected final int bound_index; 532 protected final int parameter_index; 533 protected final int type_index; 534 protected final int exception_index; 535 protected final TypeAnnotation.Position.TypePathEntry[] typePath; 536 537 /** 538 * Create an {@code ExpectedTypeAnnotation} from its 539 * components. It is usually a better idea to use a {@code 540 * Builder} to do this. 541 * 542 * @param expectedName The expected annotation name. 543 * @param visibility Whether this annotation should be runtime-visible. 544 * @param expectedCount The number of annotations that should 545 * be seen. If 0, this asserts that the 546 * described annotation is not present. 547 * @param targetType The expected target type. 548 * @param bound_index The expected bound index, or {@code Integer.MIN_VALUE}. 549 * @param parameter_index The expected parameter index, or 550 * {@code Integer.MIN_VALUE}. 551 * @param type_index The expected type index, or {@code Integer.MIN_VALUE}. 552 * @param exception_index The expected exception index, or 553 * {@code Integer.MIN_VALUE}. 554 * @param typePath The expected type path. 555 */ 556 public ExpectedTypeAnnotation(String expectedName, 557 boolean visibility, 558 int expectedCount, 559 TypeAnnotation.TargetType targetType, 560 int bound_index, 561 int parameter_index, 562 int type_index, 563 int exception_index, 564 TypeAnnotation.Position.TypePathEntry... typePath) { 565 super(expectedName, visibility, expectedCount); 566 this.targetType = targetType; 567 this.bound_index = bound_index; 568 this.parameter_index = parameter_index; 569 this.type_index = type_index; 570 this.exception_index = exception_index; 571 this.typePath = typePath; 572 } 573 574 @Override 575 public String toString() { 576 final StringBuilder sb = new StringBuilder(); 577 sb.append("Expected "); 578 sb.append(expectedCount); 579 sb.append(" annotation "); 580 sb.append(expectedName); 581 sb.append(visibility ? ", runtime visibile " : ", runtime invisibile "); 582 sb.append(targetType); 583 sb.append(", bound_index = "); 584 sb.append(bound_index); 585 sb.append(", parameter_index = "); 586 sb.append(parameter_index); 587 sb.append(", type_index = "); 588 sb.append(type_index); 589 sb.append(", exception_index = "); 590 sb.append(exception_index); 591 sb.append(", type_path = ["); 592 for(int i = 0; i < typePath.length; i++) { 593 if (i != 0) { 594 sb.append(", "); 595 } 596 sb.append(typePath[i]); 597 } 598 sb.append("]"); 599 return sb.toString(); 600 } 601 602 @Override 603 public void matchAnnotation(ConstantPool cpool, 604 Annotation anno) {} 605 606 public void matchAnnotation(TypeAnnotation anno) { 607 if (checkMatch(anno)) { 608 count++; 609 } 610 } 611 612 public boolean checkMatch(TypeAnnotation anno) { 613 boolean matches = checkMatch(anno.constant_pool, anno.annotation); 614 615 matches = matches && anno.position.type == targetType; 616 matches = matches && anno.position.bound_index == bound_index; 617 matches = matches && anno.position.parameter_index == parameter_index; 618 matches = matches && anno.position.type_index == type_index; 619 matches = matches && anno.position.exception_index == exception_index; 620 matches = matches && anno.position.location.size() == typePath.length; 621 622 if (matches) { 623 int i = 0; 624 for(TypeAnnotation.Position.TypePathEntry entry : 625 anno.position.location) { 626 matches = matches && typePath[i++].equals(entry); 627 } 628 } 629 630 return matches; 631 } 632 633 /** 634 * A builder class for creating {@code 635 * ExpectedTypeAnnotation}s in a more convenient fashion. The 636 * constructor for {@code ExpectedTypeAnnotation} takes a 637 * large number of parameters (by necessity). This class 638 * allows users to construct a {@code ExpectedTypeAnnotation}s 639 * using only the ones they need. 640 */ 641 public static class Builder { 642 protected final String expectedName; 643 protected final boolean visibility; 644 protected final int expectedCount; 645 protected final TypeAnnotation.TargetType targetType; 646 protected int bound_index = Integer.MIN_VALUE; 647 protected int parameter_index = Integer.MIN_VALUE; 648 protected int type_index = Integer.MIN_VALUE; 649 protected int exception_index = Integer.MIN_VALUE; 650 protected TypeAnnotation.Position.TypePathEntry[] typePath = 651 new TypeAnnotation.Position.TypePathEntry[0]; 652 653 /** 654 * Create a {@code Builder} from the mandatory parameters. 655 * 656 * @param expectedName The expected annotation name. 657 * @param targetType The expected target type. 658 * @param visibility Whether this annotation should be runtime-visible. 659 * @param expectedCount The number of annotations that should be seen. 660 */ 661 public Builder(String expectedName, 662 TypeAnnotation.TargetType targetType, 663 boolean visibility, 664 int expectedCount) { 665 this.expectedName = expectedName; 666 this.visibility = visibility; 667 this.expectedCount = expectedCount; 668 this.targetType = targetType; 669 } 670 671 /** 672 * Create an {@code ExpectedTypeAnnotation} from all 673 * parameters that have been provided. The default values 674 * will be used for those that have not. 675 * 676 * @return The cretaed {@code ExpectedTypeAnnotation}. 677 */ 678 public ExpectedTypeAnnotation build() { 679 return new ExpectedTypeAnnotation(expectedName, visibility, 680 expectedCount, targetType, 681 bound_index, parameter_index, 682 type_index, exception_index, 683 typePath); 684 } 685 686 /** 687 * Provide a bound index parameter. 688 * 689 * @param bound_index The bound_index value. 690 */ 691 public Builder setBoundIndex(int bound_index) { 692 this.bound_index = bound_index; 693 return this; 694 } 695 696 /** 697 * Provide a parameter index parameter. 698 * 699 * @param bound_index The parameter_index value. 700 */ 701 public Builder setParameterIndex(int parameter_index) { 702 this.parameter_index = parameter_index; 703 return this; 704 } 705 706 /** 707 * Provide a type index parameter. 708 * 709 * @param type_index The type_index value. 710 */ 711 public Builder setTypeIndex(int type_index) { 712 this.type_index = type_index; 713 return this; 714 } 715 716 /** 717 * Provide an exception index parameter. 718 * 719 * @param exception_index The exception_index value. 720 */ 721 public Builder setExceptionIndex(int exception_index) { 722 this.exception_index = exception_index; 723 return this; 724 } 725 726 /** 727 * Provide a type path parameter. 728 * 729 * @param typePath The type path value. 730 */ 731 public Builder setTypePath(TypeAnnotation.Position.TypePathEntry[] typePath) { 732 this.typePath = typePath; 733 return this; 734 } 735 } 736 } 737 738 /** 739 * A type annotation found on a method. 740 */ 741 public static class ExpectedMethodTypeAnnotation extends ExpectedTypeAnnotation { 742 private final String methodname; 743 744 /** 745 * Create an {@code ExpectedMethodTypeAnnotation} from its 746 * components. It is usually a better idea to use a {@code 747 * Builder} to do this. 748 * 749 * @param methodname The expected method name. 750 * @param expectedName The expected annotation name. 751 * @param visibility Whether this annotation should be runtime-visible. 752 * @param expectedCount The number of annotations that should be seen. 753 * @param targetType The expected target type. 754 * @param bound_index The expected bound index, or {@code Integer.MIN_VALUE}. 755 * @param parameter_index The expected parameter index, or 756 * {@code Integer.MIN_VALUE}. 757 * @param type_index The expected type index, or {@code Integer.MIN_VALUE}. 758 * @param exception_index The expected exception index, or 759 * {@code Integer.MIN_VALUE}. 760 * @param typePath The expected type path. 761 */ 762 public ExpectedMethodTypeAnnotation(String methodname, 763 String expectedName, 764 boolean visibility, 765 int expectedCount, 766 TypeAnnotation.TargetType targetType, 767 int bound_index, 768 int parameter_index, 769 int type_index, 770 int exception_index, 771 TypeAnnotation.Position.TypePathEntry... typePath) { 772 super(expectedName, visibility, expectedCount, targetType, bound_index, 773 parameter_index, type_index, exception_index, typePath); 774 this.methodname = methodname; 775 } 776 777 @Override 778 public String toString() { 779 final StringBuilder sb = new StringBuilder(); 780 sb.append("Expected "); 781 sb.append(expectedCount); 782 sb.append(" annotation "); 783 sb.append(expectedName); 784 sb.append(visibility ? ", runtime visibile " : ", runtime invisibile "); 785 sb.append(targetType); 786 sb.append(", bound_index = "); 787 sb.append(bound_index); 788 sb.append(", parameter_index = "); 789 sb.append(parameter_index); 790 sb.append(", type_index = "); 791 sb.append(type_index); 792 sb.append(", exception_index = "); 793 sb.append(exception_index); 794 sb.append(", type_path = ["); 795 for(int i = 0; i < typePath.length; i++) { 796 if (i != 0) { 797 sb.append(", "); 798 } 799 sb.append(typePath[i]); 800 } 801 sb.append("]"); 802 sb.append(" on method "); 803 sb.append(methodname); 804 return sb.toString(); 805 } 806 807 /** 808 * See if this template applies to a method. 809 * 810 * @param methodname The method name to check. 811 * @return Whether or not this template should apply. 812 */ 813 public boolean matchMethodName(String methodname) { 814 return this.methodname.equals(methodname); 815 } 816 817 /** 818 * A builder class for creating {@code 819 * ExpectedMethodTypeAnnotation}s in a more convenient fashion. The 820 * constructor for {@code ExpectedMethodTypeAnnotation} takes a 821 * large number of parameters (by necessity). This class 822 * allows users to construct a {@code ExpectedMethodTypeAnnotation}s 823 * using only the ones they need. 824 */ 825 public static class Builder extends ExpectedTypeAnnotation.Builder { 826 protected final String methodname; 827 828 /** 829 * Create a {@code Builder} from the mandatory parameters. 830 * 831 * @param methodname The expected method name. 832 * @param expectedName The expected annotation name. 833 * @param targetType The expected target type. 834 * @param visibility Whether this annotation should be runtime-visible. 835 * @param expectedCount The number of annotations that should be seen. 836 */ 837 public Builder(String methodname, 838 String expectedName, 839 TypeAnnotation.TargetType targetType, 840 boolean visibility, 841 int expectedCount) { 842 super(expectedName, targetType, visibility, expectedCount); 843 this.methodname = methodname; 844 } 845 846 /** 847 * Create an {@code ExpectedMethodTypeAnnotation} from all 848 * parameters that have been provided. The default values 849 * will be used for those that have not. 850 * 851 * @return The created {@code ExpectedMethodTypeAnnotation}. 852 */ 853 @Override 854 public ExpectedMethodTypeAnnotation build() { 855 return new ExpectedMethodTypeAnnotation(methodname, expectedName, 856 visibility, expectedCount, 857 targetType, bound_index, 858 parameter_index, type_index, 859 exception_index, typePath); 860 } 861 } 862 } 863 864 /** 865 * A type annotation found on a field. 866 */ 867 public static class ExpectedFieldTypeAnnotation extends ExpectedTypeAnnotation { 868 private final String fieldname; 869 870 /** 871 * Create an {@code ExpectedFieldTypeAnnotation} from its 872 * components. It is usually a better idea to use a {@code 873 * Builder} to do this. 874 * 875 * @param fieldname The expected field name. 876 * @param expectedName The expected annotation name. 877 * @param visibility Whether this annotation should be runtime-visible. 878 * @param expectedCount The number of annotations that should be seen. 879 * @param targetType The expected target type. 880 * @param bound_index The expected bound index, or {@code Integer.MIN_VALUE}. 881 * @param parameter_index The expected parameter index, or 882 * {@code Integer.MIN_VALUE}. 883 * @param type_index The expected type index, or {@code Integer.MIN_VALUE}. 884 * @param exception_index The expected exception index, or 885 * {@code Integer.MIN_VALUE}. 886 * @param typePath The expected type path. 887 */ 888 public ExpectedFieldTypeAnnotation(String fieldname, 889 String expectedName, 890 boolean visibility, 891 int expectedCount, 892 TypeAnnotation.TargetType targetType, 893 int bound_index, 894 int parameter_index, 895 int type_index, 896 int exception_index, 897 TypeAnnotation.Position.TypePathEntry... typePath) { 898 super(expectedName, visibility, expectedCount, targetType, bound_index, 899 parameter_index, type_index, exception_index, typePath); 900 this.fieldname = fieldname; 901 } 902 903 @Override 904 public String toString() { 905 final StringBuilder sb = new StringBuilder(); 906 sb.append("Expected ").append(expectedCount) 907 .append(" annotation ").append(expectedName) 908 .append(visibility ? ", runtime visibile " : ", runtime invisibile ") 909 .append(targetType) 910 .append(", bound_index = ").append(bound_index) 911 .append(", parameter_index = ").append(parameter_index) 912 .append(", type_index = ").append(type_index) 913 .append(", exception_index = ").append(exception_index) 914 .append(", type_path = ["); 915 916 for(int i = 0; i < typePath.length; i++) { 917 if (i != 0) { 918 sb.append(", "); 919 } 920 sb.append(typePath[i]); 921 } 922 sb.append("]") 923 .append(" on field ").append(fieldname); 924 return sb.toString(); 925 } 926 927 /** 928 * See if this template applies to a field. 929 * 930 * @param fieldname The field name to check. 931 * @return Whether or not this template should apply. 932 */ 933 public boolean matchFieldName(String fieldname) { 934 return this.fieldname.equals(fieldname); 935 } 936 937 /** 938 * A builder class for creating {@code 939 * ExpectedFieldTypeAnnotation}s in a more convenient fashion. The 940 * constructor for {@code ExpectedFieldTypeAnnotation} takes a 941 * large number of parameters (by necessity). This class 942 * allows users to construct a {@code ExpectedFieldTypeAnnotation}s 943 * using only the ones they need. 944 */ 945 public static class Builder extends ExpectedTypeAnnotation.Builder { 946 protected final String fieldname; 947 948 /** 949 * Create a {@code Builder} from the mandatory parameters. 950 * 951 * @param fieldname The expected field name. 952 * @param expectedName The expected annotation name. 953 * @param targetType The expected target type. 954 * @param visibility Whether this annotation should be runtime-visible. 955 * @param expectedCount The number of annotations that should be seen. 956 */ 957 public Builder(String fieldname, 958 String expectedName, 959 TypeAnnotation.TargetType targetType, 960 boolean visibility, 961 int expectedCount) { 962 super(expectedName, targetType, visibility, expectedCount); 963 this.fieldname = fieldname; 964 } 965 966 /** 967 * Create an {@code ExpectedFieldTypeAnnotation} from all 968 * parameters that have been provided. The default values 969 * will be used for those that have not. 970 * 971 * @return The created {@code ExpectedFieldTypeAnnotation}. 972 */ 973 @Override 974 public ExpectedFieldTypeAnnotation build() { 975 return new ExpectedFieldTypeAnnotation(fieldname, expectedName, 976 visibility, expectedCount, 977 targetType, bound_index, 978 parameter_index, type_index, 979 exception_index, typePath); 980 } 981 } 982 } 983 984 private void matchClassAnnotation(ClassFile classfile, 985 ExpectedAnnotation expected) 986 throws ConstantPoolException { 987 for(Attribute attr : classfile.attributes) { 988 attr.accept(annoMatcher(classfile.constant_pool), expected); 989 } 990 } 991 992 private void matchMethodAnnotation(ClassFile classfile, 993 ExpectedMethodAnnotation expected) 994 throws ConstantPoolException { 995 for(Method meth : classfile.methods) { 996 if (expected.matchMethodName(meth.getName(classfile.constant_pool))) { 997 for(Attribute attr : meth.attributes) { 998 attr.accept(annoMatcher(classfile.constant_pool), expected); 999 } 1000 } 1001 } 1002 } 1003 1004 private void matchParameterAnnotation(ClassFile classfile, 1005 ExpectedParameterAnnotation expected) 1006 throws ConstantPoolException { 1007 for(Method meth : classfile.methods) { 1008 if (expected.matchMethodName(meth.getName(classfile.constant_pool))) { 1009 for(Attribute attr : meth.attributes) { 1010 attr.accept(paramMatcher(classfile.constant_pool), expected); 1011 } 1012 } 1013 } 1014 } 1015 1016 private void matchFieldAnnotation(ClassFile classfile, 1017 ExpectedFieldAnnotation expected) 1018 throws ConstantPoolException { 1019 for(Field field : classfile.fields) { 1020 if (expected.matchFieldName(field.getName(classfile.constant_pool))) { 1021 for(Attribute attr : field.attributes) { 1022 attr.accept(annoMatcher(classfile.constant_pool), expected); 1023 } 1024 } 1025 } 1026 } 1027 1028 private void matchClassTypeAnnotation(ClassFile classfile, 1029 ExpectedTypeAnnotation expected) 1030 throws ConstantPoolException { 1031 for(Attribute attr : classfile.attributes) { 1032 attr.accept(typeAnnoMatcher, expected); 1033 } 1034 } 1035 1036 private void matchMethodTypeAnnotation(ClassFile classfile, 1037 ExpectedMethodTypeAnnotation expected) 1038 throws ConstantPoolException { 1039 for(Method meth : classfile.methods) { 1040 if (expected.matchMethodName(meth.getName(classfile.constant_pool))) { 1041 for(Attribute attr : meth.attributes) { 1042 attr.accept(typeAnnoMatcher, expected); 1043 } 1044 } 1045 } 1046 } 1047 1048 private void matchFieldTypeAnnotation(ClassFile classfile, 1049 ExpectedFieldTypeAnnotation expected) 1050 throws ConstantPoolException { 1051 for(Field field : classfile.fields) { 1052 if (expected.matchFieldName(field.getName(classfile.constant_pool))) { 1053 for(Attribute attr : field.attributes) { 1054 attr.accept(typeAnnoMatcher, expected); 1055 } 1056 } 1057 } 1058 } 1059 1060 private void matchClassAnnotations(ClassFile classfile, 1061 ExpectedAnnotation[] expected) 1062 throws ConstantPoolException { 1063 for(ExpectedAnnotation one : expected) { 1064 matchClassAnnotation(classfile, one); 1065 } 1066 } 1067 1068 private void matchMethodAnnotations(ClassFile classfile, 1069 ExpectedMethodAnnotation[] expected) 1070 throws ConstantPoolException { 1071 for(ExpectedMethodAnnotation one : expected) { 1072 matchMethodAnnotation(classfile, one); 1073 } 1074 } 1075 1076 private void matchParameterAnnotations(ClassFile classfile, 1077 ExpectedParameterAnnotation[] expected) 1078 throws ConstantPoolException { 1079 for(ExpectedParameterAnnotation one : expected) { 1080 matchParameterAnnotation(classfile, one); 1081 } 1082 } 1083 1084 private void matchFieldAnnotations(ClassFile classfile, 1085 ExpectedFieldAnnotation[] expected) 1086 throws ConstantPoolException { 1087 for(ExpectedFieldAnnotation one : expected) { 1088 matchFieldAnnotation(classfile, one); 1089 } 1090 } 1091 1092 private void matchClassTypeAnnotations(ClassFile classfile, 1093 ExpectedTypeAnnotation[] expected) 1094 throws ConstantPoolException { 1095 for(ExpectedTypeAnnotation one : expected) { 1096 matchClassTypeAnnotation(classfile, one); 1097 } 1098 } 1099 1100 private void matchMethodTypeAnnotations(ClassFile classfile, 1101 ExpectedMethodTypeAnnotation[] expected) 1102 throws ConstantPoolException { 1103 for(ExpectedMethodTypeAnnotation one : expected) { 1104 matchMethodTypeAnnotation(classfile, one); 1105 } 1106 } 1107 1108 private void matchFieldTypeAnnotations(ClassFile classfile, 1109 ExpectedFieldTypeAnnotation[] expected) 1110 throws ConstantPoolException { 1111 for(ExpectedFieldTypeAnnotation one : expected) { 1112 matchFieldTypeAnnotation(classfile, one); 1113 } 1114 } 1115 1116 /** 1117 * Run a template on a single {@code ClassFile}. 1118 * 1119 * @param classfile The {@code ClassFile} on which to run tests. 1120 * @param expected The expected annotation template. 1121 */ 1122 public void run(ClassFile classfile, 1123 Expected... expected) 1124 throws ConstantPoolException { 1125 run(new ClassFile[] { classfile }, expected); 1126 } 1127 1128 /** 1129 * Run a template on multiple {@code ClassFile}s. 1130 * 1131 * @param classfile The {@code ClassFile}s on which to run tests. 1132 * @param expected The expected annotation template. 1133 */ 1134 public void run(ClassFile[] classfiles, 1135 Expected... expected) 1136 throws ConstantPoolException { 1137 for(ClassFile classfile : classfiles) { 1138 for(Expected one : expected) { 1139 if (one.matchClassName(classfile.getName())) { 1140 if (one.classAnnos != null) 1141 matchClassAnnotations(classfile, one.classAnnos); 1142 if (one.methodAnnos != null) 1143 matchMethodAnnotations(classfile, one.methodAnnos); 1144 if (one.methodParamAnnos != null) 1145 matchParameterAnnotations(classfile, one.methodParamAnnos); 1146 if (one.fieldAnnos != null) 1147 matchFieldAnnotations(classfile, one.fieldAnnos); 1148 if (one.classTypeAnnos != null) 1149 matchClassTypeAnnotations(classfile, one.classTypeAnnos); 1150 if (one.methodTypeAnnos != null) 1151 matchMethodTypeAnnotations(classfile, one.methodTypeAnnos); 1152 if (one.fieldTypeAnnos != null) 1153 matchFieldTypeAnnotations(classfile, one.fieldTypeAnnos); 1154 } 1155 } 1156 } 1157 int count = 0; 1158 for (Expected one : expected) { 1159 count += one.check(); 1160 } 1161 1162 if (count != 0) { 1163 throw new RuntimeException(count + " errors occurred in test"); 1164 } 1165 } 1166 1167 /** 1168 * Get a {@code ClassFile} from its file name. 1169 * 1170 * @param name The class' file name. 1171 * @param host A class in the same package. 1172 * @return The {@code ClassFile} 1173 */ 1174 public static ClassFile getClassFile(String name, 1175 Class<?> host) 1176 throws IOException, ConstantPoolException { 1177 final URL url = host.getResource(name); 1178 try (InputStream in = url.openStream()) { 1179 return ClassFile.read(in); 1180 } 1181 } 1182 1183 private static class AbstractAttributeVisitor<T> implements Attribute.Visitor<Void, T> { 1184 1185 @Override 1186 public Void visitBootstrapMethods(BootstrapMethods_attribute attr, T p) { 1187 return null; 1188 } 1189 1190 @Override 1191 public Void visitConcealedPackages(ConcealedPackages_attribute attr, T p) { 1192 return null; 1193 } 1194 1195 @Override 1196 public Void visitDefault(DefaultAttribute attr, T p) { 1197 return null; 1198 } 1199 1200 @Override 1201 public Void visitAnnotationDefault(AnnotationDefault_attribute attr, T p) { 1202 return null; 1203 } 1204 1205 @Override 1206 public Void visitCharacterRangeTable(CharacterRangeTable_attribute attr, T p) { 1207 return null; 1208 } 1209 1210 @Override 1211 public Void visitCode(Code_attribute attr, T p) { 1212 return null; 1213 } 1214 1215 @Override 1216 public Void visitCompilationID(CompilationID_attribute attr, T p) { 1217 return null; 1218 } 1219 1220 @Override 1221 public Void visitConstantValue(ConstantValue_attribute attr, T p) { 1222 return null; 1223 } 1224 1225 @Override 1226 public Void visitDeprecated(Deprecated_attribute attr, T p) { 1227 return null; 1228 } 1229 1230 @Override 1231 public Void visitEnclosingMethod(EnclosingMethod_attribute attr, T p) { 1232 return null; 1233 } 1234 1235 @Override 1236 public Void visitExceptions(Exceptions_attribute attr, T p) { 1237 return null; 1238 } 1239 1240 @Override 1241 public Void visitHashes(Hashes_attribute attr, T p) { 1242 return null; 1243 } 1244 1245 @Override 1246 public Void visitInnerClasses(InnerClasses_attribute attr, T p) { 1247 return null; 1248 } 1249 1250 @Override 1251 public Void visitLineNumberTable(LineNumberTable_attribute attr, T p) { 1252 return null; 1253 } 1254 1255 @Override 1256 public Void visitLocalVariableTable(LocalVariableTable_attribute attr, T p) { 1257 return null; 1258 } 1259 1260 @Override 1261 public Void visitLocalVariableTypeTable(LocalVariableTypeTable_attribute attr, T p) { 1262 return null; 1263 } 1264 1265 @Override 1266 public Void visitMainClass(MainClass_attribute attr, T p) { 1267 return null; 1268 } 1269 1270 @Override 1271 public Void visitMethodParameters(MethodParameters_attribute attr, T p) { 1272 return null; 1273 } 1274 1275 @Override 1276 public Void visitModule(Module_attribute attr, T p) { 1277 return null; 1278 } 1279 1280 @Override 1281 public Void visitRuntimeVisibleAnnotations(RuntimeVisibleAnnotations_attribute attr, T p) { 1282 return null; 1283 } 1284 1285 @Override 1286 public Void visitRuntimeInvisibleAnnotations(RuntimeInvisibleAnnotations_attribute attr, T p) { 1287 return null; 1288 } 1289 1290 @Override 1291 public Void visitRuntimeVisibleParameterAnnotations(RuntimeVisibleParameterAnnotations_attribute attr, T p) { 1292 return null; 1293 } 1294 1295 @Override 1296 public Void visitRuntimeInvisibleParameterAnnotations(RuntimeInvisibleParameterAnnotations_attribute attr, T p) { 1297 return null; 1298 } 1299 1300 @Override 1301 public Void visitRuntimeVisibleTypeAnnotations(RuntimeVisibleTypeAnnotations_attribute attr, T p) { 1302 return null; 1303 } 1304 1305 @Override 1306 public Void visitRuntimeInvisibleTypeAnnotations(RuntimeInvisibleTypeAnnotations_attribute attr, T p) { 1307 return null; 1308 } 1309 1310 @Override 1311 public Void visitSignature(Signature_attribute attr, T p) { 1312 return null; 1313 } 1314 1315 @Override 1316 public Void visitSourceDebugExtension(SourceDebugExtension_attribute attr, T p) { 1317 return null; 1318 } 1319 1320 @Override 1321 public Void visitSourceFile(SourceFile_attribute attr, T p) { 1322 return null; 1323 } 1324 1325 @Override 1326 public Void visitSourceID(SourceID_attribute attr, T p) { 1327 return null; 1328 } 1329 1330 @Override 1331 public Void visitStackMap(StackMap_attribute attr, T p) { 1332 return null; 1333 } 1334 1335 @Override 1336 public Void visitStackMapTable(StackMapTable_attribute attr, T p) { 1337 return null; 1338 } 1339 1340 @Override 1341 public Void visitSynthetic(Synthetic_attribute attr, T p) { 1342 return null; 1343 } 1344 1345 @Override 1346 public Void visitTargetPlatform(TargetPlatform_attribute attr, T p) { 1347 return null; 1348 } 1349 1350 @Override 1351 public Void visitVersion(Version_attribute attr, T p) { 1352 return null; 1353 } 1354 1355 } 1356 1357 private static final Attribute.Visitor<Void, ExpectedTypeAnnotation> typeAnnoMatcher 1358 = new AbstractAttributeVisitor<ExpectedTypeAnnotation>() { 1359 1360 @Override 1361 public Void visitRuntimeVisibleTypeAnnotations(RuntimeVisibleTypeAnnotations_attribute attr, 1362 ExpectedTypeAnnotation expected) { 1363 if (expected.matchVisibility(true)) { 1364 for (TypeAnnotation anno : attr.annotations) { 1365 expected.matchAnnotation(anno); 1366 } 1367 } 1368 1369 return null; 1370 } 1371 1372 @Override 1373 public Void visitRuntimeInvisibleTypeAnnotations(RuntimeInvisibleTypeAnnotations_attribute attr, 1374 ExpectedTypeAnnotation expected) { 1375 if (expected.matchVisibility(false)) { 1376 for (TypeAnnotation anno : attr.annotations) { 1377 expected.matchAnnotation(anno); 1378 } 1379 } 1380 1381 return null; 1382 } 1383 }; 1384 1385 private static Attribute.Visitor<Void, ExpectedAnnotation> annoMatcher(ConstantPool cpool) { 1386 return new AbstractAttributeVisitor<ExpectedAnnotation>() { 1387 1388 @Override 1389 public Void visitRuntimeVisibleAnnotations(RuntimeVisibleAnnotations_attribute attr, 1390 ExpectedAnnotation expected) { 1391 if (expected.matchVisibility(true)) { 1392 for(Annotation anno : attr.annotations) { 1393 expected.matchAnnotation(cpool, anno); 1394 } 1395 } 1396 1397 return null; 1398 } 1399 1400 @Override 1401 public Void visitRuntimeInvisibleAnnotations(RuntimeInvisibleAnnotations_attribute attr, 1402 ExpectedAnnotation expected) { 1403 if (expected.matchVisibility(false)) { 1404 for(Annotation anno : attr.annotations) { 1405 expected.matchAnnotation(cpool, anno); 1406 } 1407 } 1408 1409 return null; 1410 } 1411 }; 1412 } 1413 1414 private static Attribute.Visitor<Void, ExpectedParameterAnnotation> paramMatcher(ConstantPool cpool) { 1415 return new AbstractAttributeVisitor<ExpectedParameterAnnotation>() { 1416 1417 @Override 1418 public Void visitRuntimeVisibleParameterAnnotations(RuntimeVisibleParameterAnnotations_attribute attr, 1419 ExpectedParameterAnnotation expected) { 1420 if (expected.matchVisibility(true)) { 1421 if (expected.index < attr.parameter_annotations.length) { 1422 for(Annotation anno : 1423 attr.parameter_annotations[expected.index]) { 1424 expected.matchAnnotation(cpool, anno); 1425 } 1426 } 1427 } 1428 1429 return null; 1430 } 1431 1432 @Override 1433 public Void visitRuntimeInvisibleParameterAnnotations(RuntimeInvisibleParameterAnnotations_attribute attr, 1434 ExpectedParameterAnnotation expected) { 1435 if (expected.matchVisibility(false)) { 1436 if (expected.index < attr.parameter_annotations.length) { 1437 for(Annotation anno : 1438 attr.parameter_annotations[expected.index]) { 1439 expected.matchAnnotation(cpool, anno); 1440 } 1441 } 1442 } 1443 1444 return null; 1445 } 1446 }; 1447 } 1448} 1449