1 /* 2 * Copyright (c) 2012, 2014, 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 24 import java.lang.annotation.*; 25 import java.io.*; 26 import java.net.URL; 27 import java.util.List; 28 29 import com.sun.tools.classfile.*; 30 31 /** 32 * A class providing utilities for writing tests that inspect class 33 * files directly, looking for specific type annotations. 34 * 35 * Note: this framework does not currently handle repeating 36 * annotations. 37 */ 38 public class ClassfileInspector { 39 40 /** 41 * A group of expected annotations to be found in a given class. 42 * If the class name is null, then the template will be applied to 43 * every class. 44 */ 45 public static class Expected { 46 /** 47 * The name of the class. If {@code null} this template will 48 * apply to every class; otherwise, it will only be applied to 49 * the named class. 50 */ 51 public final String classname; 52 53 /** 54 * The expected class annotations. These will be checked 55 * against the class' attributes. 56 */ 57 public final ExpectedTypeAnnotation[] classAnnos; 58 59 /** 60 * The expected method annotations. These will be checked 61 * against all methods in the class. 62 */ 63 public final ExpectedMethodTypeAnnotation[] methodAnnos; 64 65 /** 66 * The expected field annotations. These will be checked 67 * against all fields in the class. 68 */ 69 public final ExpectedFieldTypeAnnotation[] fieldAnnos; 70 71 /** 72 * Create an {@code Expected} from its components. 73 * 74 * @param classname The name of the class to match, or {@code 75 * null} for all classes. 76 * @param classAnnos The expected class annotations. 77 * @param methodAnnos The expected method annotations. 78 * @param fieldAnnos The expected field annotations. 79 */ 80 public Expected(String classname, 81 ExpectedTypeAnnotation[] classAnnos, 82 ExpectedMethodTypeAnnotation[] methodAnnos, 83 ExpectedFieldTypeAnnotation[] fieldAnnos) { 84 this.classname = classname; 85 this.classAnnos = classAnnos; 86 this.methodAnnos = methodAnnos; 87 this.fieldAnnos = fieldAnnos; 88 } 89 90 public String toString() { 91 final StringBuilder sb = new StringBuilder(); 92 final String newline = System.lineSeparator(); 93 sb.append("Expected on class ").append(classname); 94 if (null != classAnnos) { 95 sb.append(newline).append("Class annotations:").append(newline); 96 for(ExpectedTypeAnnotation anno : classAnnos) { 97 sb.append(anno).append(newline); 98 } 99 } 100 if (null != methodAnnos) { 101 sb.append(newline).append("Method annotations:").append(newline); 102 for(ExpectedTypeAnnotation anno : methodAnnos) { 103 sb.append(anno).append(newline); 104 } 105 } 106 if (null != fieldAnnos) { 107 sb.append(newline).append("Field annotations:").append(newline); 108 for(ExpectedTypeAnnotation anno : fieldAnnos) { 109 sb.append(anno).append(newline); 110 } 111 } 112 return sb.toString(); 113 } 114 115 /** 116 * See if this template applies to a class. 117 * 118 * @param classname The classname to check. 119 * @return Whether or not this template should apply. 120 */ 121 public boolean matchClassName(String classname) { 122 return this.classname == null || this.classname.equals(classname); 123 } 124 125 /** 126 * After applying the template to all classes, check to see if 127 * any of the expected annotations weren't matched. 128 * 129 * @return The number of missed matches. 130 */ 131 public int check() { 132 int count = 0; 133 if (classAnnos != null) { 134 for(ExpectedTypeAnnotation expected : classAnnos) { 135 if (!expected.check()) { 136 count++; 137 } 138 } 139 } 140 if (methodAnnos != null) { 141 for(ExpectedMethodTypeAnnotation expected : methodAnnos) { 142 if (!expected.check()) { 143 count++; 144 } 145 } 146 } 147 if (fieldAnnos != null) { 148 for(ExpectedFieldTypeAnnotation expected : fieldAnnos) { 149 if (!expected.check()) { 150 count++; 151 } 152 } 153 } 154 return count; 155 } 156 } 157 158 /** 159 * An expected type annotation. This is both a superclass for 160 * method and field type annotations, as well as a class for type 161 * annotations on a class. 162 */ 163 public static class ExpectedTypeAnnotation { 164 private int count = 0; 165 protected final String expectedName; 166 protected final int expectedCount; 167 protected final TypeAnnotation.TargetType targetType; 168 protected final int bound_index; 169 protected final int parameter_index; 170 protected final int type_index; 171 protected final int exception_index; 172 protected final TypeAnnotation.Position.TypePathEntry[] typePath; 173 protected final boolean visibility; 174 175 /** 176 * Create an {@code ExpectedTypeAnnotation} from its 177 * components. It is usually a better idea to use a {@code 178 * Builder} to do this. 179 * 180 * @param expectedName The expected annotation name. 181 * @param visibility Whether this annotation should be runtime-visible. 182 * @param expectedCount The number of annotations that should 183 * be seen. If 0, this asserts that the 184 * described annotation is not present. 185 * @param targetType The expected target type. 186 * @param bound_index The expected bound index, or {@code Integer.MIN_VALUE}. 187 * @param parameter_index The expected parameter index, or 188 * {@code Integer.MIN_VALUE}. 189 * @param type_index The expected type index, or {@code Integer.MIN_VALUE}. 190 * @param exception_index The expected exception index, or 191 * {@code Integer.MIN_VALUE}. 192 * @param typePath The expected type path. 193 */ 194 public ExpectedTypeAnnotation(String expectedName, 195 boolean visibility, 196 int expectedCount, 197 TypeAnnotation.TargetType targetType, 198 int bound_index, 199 int parameter_index, 200 int type_index, 201 int exception_index, 202 TypeAnnotation.Position.TypePathEntry... typePath) { 203 this.expectedName = expectedName; 204 this.visibility = visibility; 205 this.expectedCount = expectedCount; 206 this.targetType = targetType; 207 this.bound_index = bound_index; 208 this.parameter_index = parameter_index; 209 this.type_index = type_index; 210 this.exception_index = exception_index; 211 this.typePath = typePath; 212 } 213 214 public String toString() { 215 final StringBuilder sb = new StringBuilder(); 216 sb.append("Expected "); 217 sb.append(expectedCount); 218 sb.append(" annotation "); 219 sb.append(expectedName); 220 sb.append(visibility ? ", runtime visibile " : ", runtime invisibile "); 221 sb.append(targetType); 222 sb.append(", bound_index = "); 223 sb.append(bound_index); 224 sb.append(", parameter_index = "); 225 sb.append(parameter_index); 226 sb.append(", type_index = "); 227 sb.append(type_index); 228 sb.append(", exception_index = "); 229 sb.append(exception_index); 230 sb.append(", type_path = ["); 231 for(int i = 0; i < typePath.length; i++) { 232 if (i != 0) { 233 sb.append(", "); 234 } 235 sb.append(typePath[i]); 236 } 237 sb.append("]"); 238 return sb.toString(); 239 } 240 241 /** 242 * See if this template matches the given visibility. 243 * 244 * @param Whether or not the annotation is visible at runtime. 245 * @return Whether or not this template matches the visibility. 246 */ 247 public boolean matchVisibility(boolean visibility) { 248 return this.visibility == visibility; 249 } 250 251 /** 252 * Attempty to match this template against an annotation. If 253 * it does match, then the match count for the template will 254 * be incremented. Otherwise, nothing will be done. 255 * 256 * @param anno The annotation to attempt to match. 257 */ 258 public void matchAnnotation(TypeAnnotation anno) { 259 boolean matches = true; 260 261 try { 262 matches = anno.constant_pool.getUTF8Info(anno.annotation.type_index).value.equals("L" + expectedName + ";"); 263 } catch(Exception e) { 264 matches = false; 265 } 266 267 matches = matches && anno.position.type == targetType; 268 matches = matches && anno.position.bound_index == bound_index; 269 matches = matches && anno.position.parameter_index == parameter_index; 270 matches = matches && anno.position.type_index == type_index; 271 matches = matches && anno.position.exception_index == exception_index; 272 matches = matches && anno.position.location.size() == typePath.length; 273 274 if (matches) { 275 int i = 0; 276 for(TypeAnnotation.Position.TypePathEntry entry : 277 anno.position.location) { 278 matches = matches && typePath[i++].equals(entry); 279 } 280 } 281 282 if (matches) { 283 count++; 284 } 285 } 286 287 /** 288 * After all matching, check to see if the expected number of 289 * matches equals the actual number. If not, then print a 290 * failure message and return {@code false}. 291 * 292 * @return Whether or not the expected number of matched 293 * equals the actual number. 294 */ 295 public boolean check() { 296 if (count != expectedCount) { 297 System.err.println(this + ", but saw " + count); 298 return false; 299 } else { 300 return true; 301 } 302 } 303 304 /** 305 * A builder class for creating {@code 306 * ExpectedTypeAnnotation}s in a more convenient fashion. The 307 * constructor for {@code ExpectedTypeAnnotation} takes a 308 * large number of parameters (by necessity). This class 309 * allows users to construct a {@code ExpectedTypeAnnotation}s 310 * using only the ones they need. 311 */ 312 public static class Builder { 313 protected final String expectedName; 314 protected final int expectedCount; 315 protected final TypeAnnotation.TargetType targetType; 316 protected final boolean visibility; 317 protected int bound_index = Integer.MIN_VALUE; 318 protected int parameter_index = Integer.MIN_VALUE; 319 protected int type_index = Integer.MIN_VALUE; 320 protected int exception_index = Integer.MIN_VALUE; 321 protected TypeAnnotation.Position.TypePathEntry[] typePath = 322 new TypeAnnotation.Position.TypePathEntry[0]; 323 324 /** 325 * Create a {@code Builder} from the mandatory parameters. 326 * 327 * @param expectedName The expected annotation name. 328 * @param targetType The expected target type. 329 * @param visibility Whether this annotation should be runtime-visible. 330 * @param expectedCount The number of annotations that should be seen. 331 */ 332 public Builder(String expectedName, 333 TypeAnnotation.TargetType targetType, 334 boolean visibility, 335 int expectedCount) { 336 this.expectedName = expectedName; 337 this.visibility = visibility; 338 this.expectedCount = expectedCount; 339 this.targetType = targetType; 340 } 341 342 /** 343 * Create an {@code ExpectedTypeAnnotation} from all 344 * parameters that have been provided. The default values 345 * will be used for those that have not. 346 * 347 * @return The cretaed {@code ExpectedTypeAnnotation}. 348 */ 349 public ExpectedTypeAnnotation build() { 350 return new ExpectedTypeAnnotation(expectedName, visibility, 351 expectedCount, targetType, 352 bound_index, parameter_index, 353 type_index, exception_index, 354 typePath); 355 } 356 357 /** 358 * Provide a bound index parameter. 359 * 360 * @param bound_index The bound_index value. 361 */ 362 public Builder setBoundIndex(int bound_index) { 363 this.bound_index = bound_index; 364 return this; 365 } 366 367 /** 368 * Provide a parameter index parameter. 369 * 370 * @param bound_index The parameter_index value. 371 */ 372 public Builder setParameterIndex(int parameter_index) { 373 this.parameter_index = parameter_index; 374 return this; 375 } 376 377 /** 378 * Provide a type index parameter. 379 * 380 * @param type_index The type_index value. 381 */ 382 public Builder setTypeIndex(int type_index) { 383 this.type_index = type_index; 384 return this; 385 } 386 387 /** 388 * Provide an exception index parameter. 389 * 390 * @param exception_index The exception_index value. 391 */ 392 public Builder setExceptionIndex(int exception_index) { 393 this.exception_index = exception_index; 394 return this; 395 } 396 397 /** 398 * Provide a type path parameter. 399 * 400 * @param typePath The type path value. 401 */ 402 public Builder setTypePath(TypeAnnotation.Position.TypePathEntry[] typePath) { 403 this.typePath = typePath; 404 return this; 405 } 406 } 407 } 408 409 /** 410 * A type annotation found on a method. 411 */ 412 public static class ExpectedMethodTypeAnnotation extends ExpectedTypeAnnotation { 413 private final String methodname; 414 415 /** 416 * Create an {@code ExpectedMethodTypeAnnotation} from its 417 * components. It is usually a better idea to use a {@code 418 * Builder} to do this. 419 * 420 * @param methodname The expected method name. 421 * @param expectedName The expected annotation name. 422 * @param visibility Whether this annotation should be runtime-visible. 423 * @param expectedCount The number of annotations that should be seen. 424 * @param targetType The expected target type. 425 * @param bound_index The expected bound index, or {@code Integer.MIN_VALUE}. 426 * @param parameter_index The expected parameter index, or 427 * {@code Integer.MIN_VALUE}. 428 * @param type_index The expected type index, or {@code Integer.MIN_VALUE}. 429 * @param exception_index The expected exception index, or 430 * {@code Integer.MIN_VALUE}. 431 * @param typePath The expected type path. 432 */ 433 public ExpectedMethodTypeAnnotation(String methodname, 434 String expectedName, 435 boolean visibility, 436 int expectedCount, 437 TypeAnnotation.TargetType targetType, 438 int bound_index, 439 int parameter_index, 440 int type_index, 441 int exception_index, 442 TypeAnnotation.Position.TypePathEntry... typePath) { 443 super(expectedName, visibility, expectedCount, targetType, bound_index, 444 parameter_index, type_index, exception_index, typePath); 445 this.methodname = methodname; 446 } 447 448 public String toString() { 449 final StringBuilder sb = new StringBuilder(); 450 sb.append("Expected "); 451 sb.append(expectedCount); 452 sb.append(" annotation "); 453 sb.append(expectedName); 454 sb.append(visibility ? ", runtime visibile " : ", runtime invisibile "); 455 sb.append(targetType); 456 sb.append(", bound_index = "); 457 sb.append(bound_index); 458 sb.append(", parameter_index = "); 459 sb.append(parameter_index); 460 sb.append(", type_index = "); 461 sb.append(type_index); 462 sb.append(", exception_index = "); 463 sb.append(exception_index); 464 sb.append(", type_path = ["); 465 for(int i = 0; i < typePath.length; i++) { 466 if (i != 0) { 467 sb.append(", "); 468 } 469 sb.append(typePath[i]); 470 } 471 sb.append("]"); 472 sb.append(" on method "); 473 sb.append(methodname); 474 return sb.toString(); 475 } 476 477 /** 478 * See if this template applies to a method. 479 * 480 * @param methodname The method name to check. 481 * @return Whether or not this template should apply. 482 */ 483 public boolean matchMethodName(String methodname) { 484 return this.methodname.equals(methodname); 485 } 486 487 /** 488 * A builder class for creating {@code 489 * ExpectedMethodTypeAnnotation}s in a more convenient fashion. The 490 * constructor for {@code ExpectedMethodTypeAnnotation} takes a 491 * large number of parameters (by necessity). This class 492 * allows users to construct a {@code ExpectedMethodTypeAnnotation}s 493 * using only the ones they need. 494 */ 495 public static class Builder extends ExpectedTypeAnnotation.Builder { 496 protected final String methodname; 497 498 /** 499 * Create a {@code Builder} from the mandatory parameters. 500 * 501 * @param methodname The expected method name. 502 * @param expectedName The expected annotation name. 503 * @param targetType The expected target type. 504 * @param visibility Whether this annotation should be runtime-visible. 505 * @param expectedCount The number of annotations that should be seen. 506 */ 507 public Builder(String methodname, 508 String expectedName, 509 TypeAnnotation.TargetType targetType, 510 boolean visibility, 511 int expectedCount) { 512 super(expectedName, targetType, visibility, expectedCount); 513 this.methodname = methodname; 514 } 515 516 /** 517 * Create an {@code ExpectedMethodTypeAnnotation} from all 518 * parameters that have been provided. The default values 519 * will be used for those that have not. 520 * 521 * @return The cretaed {@code ExpectedMethodTypeAnnotation}. 522 */ 523 public ExpectedMethodTypeAnnotation build() { 524 return new ExpectedMethodTypeAnnotation(methodname, expectedName, 525 visibility, expectedCount, 526 targetType, bound_index, 527 parameter_index, type_index, 528 exception_index, typePath); 529 } 530 } 531 } 532 533 /** 534 * A type annotation found on a field. 535 */ 536 public static class ExpectedFieldTypeAnnotation extends ExpectedTypeAnnotation { 537 private final String fieldname; 538 539 /** 540 * Create an {@code ExpectedFieldTypeAnnotation} from its 541 * components. It is usually a better idea to use a {@code 542 * Builder} to do this. 543 * 544 * @param fieldname The expected field name. 545 * @param expectedName The expected annotation name. 546 * @param visibility Whether this annotation should be runtime-visible. 547 * @param expectedCount The number of annotations that should be seen. 548 * @param targetType The expected target type. 549 * @param bound_index The expected bound index, or {@code Integer.MIN_VALUE}. 550 * @param parameter_index The expected parameter index, or 551 * {@code Integer.MIN_VALUE}. 552 * @param type_index The expected type index, or {@code Integer.MIN_VALUE}. 553 * @param exception_index The expected exception index, or 554 * {@code Integer.MIN_VALUE}. 555 * @param typePath The expected type path. 556 */ 557 public ExpectedFieldTypeAnnotation(String fieldname, 558 String expectedName, 559 boolean visibility, 560 int expectedCount, 561 TypeAnnotation.TargetType targetType, 562 int bound_index, 563 int parameter_index, 564 int type_index, 565 int exception_index, 566 TypeAnnotation.Position.TypePathEntry... typePath) { 567 super(expectedName, visibility, expectedCount, targetType, bound_index, 568 parameter_index, type_index, exception_index, typePath); 569 this.fieldname = fieldname; 570 } 571 572 public String toString() { 573 final StringBuilder sb = new StringBuilder(); 574 sb.append("Expected ").append(expectedCount) 575 .append(" annotation ").append(expectedName) 576 .append(visibility ? ", runtime visibile " : ", runtime invisibile ") 577 .append(targetType) 578 .append(", bound_index = ").append(bound_index) 579 .append(", parameter_index = ").append(parameter_index) 580 .append(", type_index = ").append(type_index) 581 .append(", exception_index = ").append(exception_index) 582 .append(", type_path = ["); 583 584 for(int i = 0; i < typePath.length; i++) { 585 if (i != 0) { 586 sb.append(", "); 587 } 588 sb.append(typePath[i]); 589 } 590 sb.append("]") 591 .append(" on field ").append(fieldname); 592 return sb.toString(); 593 } 594 595 /** 596 * See if this template applies to a field. 597 * 598 * @param fieldname The field name to check. 599 * @return Whether or not this template should apply. 600 */ 601 public boolean matchFieldName(String fieldname) { 602 return this.fieldname.equals(fieldname); 603 } 604 605 /** 606 * A builder class for creating {@code 607 * ExpectedFieldTypeAnnotation}s in a more convenient fashion. The 608 * constructor for {@code ExpectedFieldTypeAnnotation} takes a 609 * large number of parameters (by necessity). This class 610 * allows users to construct a {@code ExpectedFieldTypeAnnotation}s 611 * using only the ones they need. 612 */ 613 public static class Builder extends ExpectedTypeAnnotation.Builder { 614 protected final String fieldname; 615 616 /** 617 * Create a {@code Builder} from the mandatory parameters. 618 * 619 * @param fieldname The expected field name. 620 * @param expectedName The expected annotation name. 621 * @param targetType The expected target type. 622 * @param visibility Whether this annotation should be runtime-visible. 623 * @param expectedCount The number of annotations that should be seen. 624 */ 625 public Builder(String fieldname, 626 String expectedName, 627 TypeAnnotation.TargetType targetType, 628 boolean visibility, 629 int expectedCount) { 630 super(expectedName, targetType, visibility, expectedCount); 631 this.fieldname = fieldname; 632 } 633 634 /** 635 * Create an {@code ExpectedFieldTypeAnnotation} from all 636 * parameters that have been provided. The default values 637 * will be used for those that have not. 638 * 639 * @return The cretaed {@code ExpectedFieldTypeAnnotation}. 640 */ 641 public ExpectedFieldTypeAnnotation build() { 642 return new ExpectedFieldTypeAnnotation(fieldname, expectedName, 643 visibility, expectedCount, 644 targetType, bound_index, 645 parameter_index, type_index, 646 exception_index, typePath); 647 } 648 } 649 } 650 651 private void matchClassTypeAnnotation(ClassFile classfile, 652 ExpectedTypeAnnotation expected) 653 throws ConstantPoolException { 654 for(Attribute attr : classfile.attributes) { 655 attr.accept(typeAnnoMatcher, expected); 656 } 657 } 658 659 private void matchMethodTypeAnnotation(ClassFile classfile, 660 ExpectedMethodTypeAnnotation expected) 661 throws ConstantPoolException { 662 for(Method meth : classfile.methods) { 663 if (expected.matchMethodName(meth.getName(classfile.constant_pool))) { 664 for(Attribute attr : meth.attributes) { 665 attr.accept(typeAnnoMatcher, expected); 666 } 667 } 668 } 669 } 670 671 private void matchFieldTypeAnnotation(ClassFile classfile, 672 ExpectedFieldTypeAnnotation expected) 673 throws ConstantPoolException { 674 for(Field field : classfile.fields) { 675 if (expected.matchFieldName(field.getName(classfile.constant_pool))) { 676 for(Attribute attr : field.attributes) { 677 attr.accept(typeAnnoMatcher, expected); 678 } 679 } 680 } 681 } 682 683 private void matchClassTypeAnnotations(ClassFile classfile, 684 ExpectedTypeAnnotation[] expected) 685 throws ConstantPoolException { 686 for(ExpectedTypeAnnotation one : expected) { 687 matchClassTypeAnnotation(classfile, one); 688 } 689 } 690 691 private void matchMethodTypeAnnotations(ClassFile classfile, 692 ExpectedMethodTypeAnnotation[] expected) 693 throws ConstantPoolException { 694 for(ExpectedMethodTypeAnnotation one : expected) { 695 matchMethodTypeAnnotation(classfile, one); 696 } 697 } 698 699 private void matchFieldTypeAnnotations(ClassFile classfile, 700 ExpectedFieldTypeAnnotation[] expected) 701 throws ConstantPoolException { 702 for(ExpectedFieldTypeAnnotation one : expected) { 703 matchFieldTypeAnnotation(classfile, one); 704 } 705 } 706 707 /** 708 * Run a template on a single {@code ClassFile}. 709 * 710 * @param classfile The {@code ClassFile} on which to run tests. 711 * @param expected The expected annotation template. 712 */ 713 public void run(ClassFile classfile, 714 Expected... expected) 715 throws ConstantPoolException { 716 run(new ClassFile[] { classfile }, expected); 717 } 718 719 /** 720 * Run a template on multiple {@code ClassFile}s. 721 * 722 * @param classfile The {@code ClassFile}s on which to run tests. 723 * @param expected The expected annotation template. 724 */ 725 public void run(ClassFile[] classfiles, 726 Expected... expected) 727 throws ConstantPoolException { 728 for(ClassFile classfile : classfiles) { 729 for(Expected one : expected) { 730 if (one.matchClassName(classfile.getName())) { 731 if (one.classAnnos != null) 732 matchClassTypeAnnotations(classfile, one.classAnnos); 733 if (one.methodAnnos != null) 734 matchMethodTypeAnnotations(classfile, one.methodAnnos); 735 if (one.fieldAnnos != null) 736 matchFieldTypeAnnotations(classfile, one.fieldAnnos); 737 } 738 } 739 } 740 int count = 0; 741 for (Expected one : expected) { 742 count += one.check(); 743 } 744 745 if (count != 0) { 746 throw new RuntimeException(count + " errors occurred in test"); 747 } 748 } 749 750 /** 751 * Get a {@code ClassFile} from its file name. 752 * 753 * @param name The class' file name. 754 * @return The {@code ClassFile} 755 */ 756 public static ClassFile getClassFile(String name) 757 throws IOException, ConstantPoolException { 758 final URL url = ClassfileInspector.class.getResource(name); 759 final InputStream in = url.openStream(); 760 try { 761 return ClassFile.read(in); 762 } finally { 763 in.close(); 764 } 765 } 766 767 private static final Attribute.Visitor<Void, ExpectedTypeAnnotation> typeAnnoMatcher = 768 new Attribute.Visitor<Void, ExpectedTypeAnnotation>() { 769 770 @Override 771 public Void visitBootstrapMethods(BootstrapMethods_attribute attr, 772 ExpectedTypeAnnotation expected) { 773 return null; 774 } 775 776 @Override 777 public Void visitDefault(DefaultAttribute attr, 778 ExpectedTypeAnnotation expected) { 779 return null; 780 } 781 782 @Override 783 public Void visitAnnotationDefault(AnnotationDefault_attribute attr, 784 ExpectedTypeAnnotation expected) { 785 return null; 786 } 787 788 @Override 789 public Void visitCharacterRangeTable(CharacterRangeTable_attribute attr, 790 ExpectedTypeAnnotation expected) { 791 return null; 792 } 793 794 @Override 795 public Void visitCode(Code_attribute attr, 796 ExpectedTypeAnnotation expected) { 797 return null; 798 } 799 800 @Override 801 public Void visitCompilationID(CompilationID_attribute attr, 802 ExpectedTypeAnnotation expected) { 803 return null; 804 } 805 806 @Override 807 public Void visitConstantValue(ConstantValue_attribute attr, 808 ExpectedTypeAnnotation expected) { 809 return null; 810 } 811 812 @Override 813 public Void visitDeprecated(Deprecated_attribute attr, 814 ExpectedTypeAnnotation expected) { 815 return null; 816 } 817 818 @Override 819 public Void visitEnclosingMethod(EnclosingMethod_attribute attr, 820 ExpectedTypeAnnotation expected) { 821 return null; 822 } 823 824 @Override 825 public Void visitExceptions(Exceptions_attribute attr, 826 ExpectedTypeAnnotation expected) { 827 return null; 828 } 829 830 @Override 831 public Void visitInnerClasses(InnerClasses_attribute attr, 832 ExpectedTypeAnnotation expected) { 833 return null; 834 } 835 836 @Override 837 public Void visitLineNumberTable(LineNumberTable_attribute attr, 838 ExpectedTypeAnnotation expected) { 839 return null; 840 } 841 842 @Override 843 public Void visitLocalVariableTable(LocalVariableTable_attribute attr, 844 ExpectedTypeAnnotation expected) { 845 return null; 846 } 847 848 @Override 849 public Void visitLocalVariableTypeTable(LocalVariableTypeTable_attribute attr, 850 ExpectedTypeAnnotation expected) { 851 return null; 852 } 853 854 @Override 855 public Void visitMethodParameters(MethodParameters_attribute attr, 856 ExpectedTypeAnnotation expected) { 857 return null; 858 } 859 860 @Override 861 public Void visitRuntimeVisibleAnnotations(RuntimeVisibleAnnotations_attribute attr, 862 ExpectedTypeAnnotation expected) { 863 return null; 864 } 865 866 @Override 867 public Void visitRuntimeInvisibleAnnotations(RuntimeInvisibleAnnotations_attribute attr, 868 ExpectedTypeAnnotation expected) { 869 return null; 870 } 871 872 @Override 873 public Void visitRuntimeVisibleParameterAnnotations(RuntimeVisibleParameterAnnotations_attribute attr, 874 ExpectedTypeAnnotation expected) { 875 return null; 876 } 877 878 @Override 879 public Void visitRuntimeInvisibleParameterAnnotations(RuntimeInvisibleParameterAnnotations_attribute attr, 880 ExpectedTypeAnnotation expected) { 881 return null; 882 } 883 884 @Override 885 public Void visitSignature(Signature_attribute attr, 886 ExpectedTypeAnnotation expected) { 887 return null; 888 } 889 890 @Override 891 public Void visitSourceDebugExtension(SourceDebugExtension_attribute attr, 892 ExpectedTypeAnnotation expected) { 893 return null; 894 } 895 896 @Override 897 public Void visitSourceFile(SourceFile_attribute attr, 898 ExpectedTypeAnnotation expected) { 899 return null; 900 } 901 902 @Override 903 public Void visitSourceID(SourceID_attribute attr, 904 ExpectedTypeAnnotation expected) { 905 return null; 906 } 907 908 @Override 909 public Void visitStackMap(StackMap_attribute attr, 910 ExpectedTypeAnnotation expected) { 911 return null; 912 } 913 914 @Override 915 public Void visitStackMapTable(StackMapTable_attribute attr, 916 ExpectedTypeAnnotation expected) { 917 return null; 918 } 919 920 @Override 921 public Void visitSynthetic(Synthetic_attribute attr, 922 ExpectedTypeAnnotation expected) { 923 return null; 924 } 925 926 @Override 927 public Void visitRuntimeVisibleTypeAnnotations(RuntimeVisibleTypeAnnotations_attribute attr, 928 ExpectedTypeAnnotation expected) { 929 if (expected.matchVisibility(true)) { 930 for(TypeAnnotation anno : attr.annotations) { 931 expected.matchAnnotation(anno); 932 } 933 } 934 935 return null; 936 } 937 938 @Override 939 public Void visitRuntimeInvisibleTypeAnnotations(RuntimeInvisibleTypeAnnotations_attribute attr, 940 ExpectedTypeAnnotation expected) { 941 if (expected.matchVisibility(false)) { 942 for(TypeAnnotation anno : attr.annotations) { 943 expected.matchAnnotation(anno); 944 } 945 } 946 947 return null; 948 } 949 }; 950 }