1/* 2 * Copyright (c) 2017, 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/* 25 * @test 26 * @bug 8173898 27 * @summary Basic test for checking filtering of reflection frames 28 * @run testng ReflectionFrames 29 */ 30 31import java.lang.StackWalker.StackFrame; 32import java.lang.reflect.Constructor; 33import java.lang.reflect.Method; 34import java.lang.invoke.MethodHandle; 35import java.lang.invoke.MethodHandles; 36import java.lang.invoke.MethodHandles.Lookup; 37import java.lang.invoke.MethodType; 38import java.util.EnumSet; 39import java.util.List; 40import java.util.function.Supplier; 41import java.util.stream.Collectors; 42import java.util.stream.Stream; 43import static java.lang.StackWalker.Option.*; 44 45import org.testng.annotations.DataProvider; 46import org.testng.annotations.Test; 47import static org.testng.Assert.*; 48 49public class ReflectionFrames { 50 final static boolean verbose = false; 51 52 /** 53 * This test invokes new StackInspector() directly from 54 * the caller StackInspector.Caller.create method. 55 * It checks that the caller is StackInspector.Caller. 56 * It also checks the expected frames collected 57 * by walking the stack from the default StackInspector() 58 * constructor. 59 * This is done twice, once using a default StackWalker 60 * that hides reflection frames, once using a StackWalker 61 * configured to show reflection frames. 62 */ 63 @Test 64 public static void testNewStackInspector() throws Exception { 65 // Sets the default walker which hides reflection 66 // frames. 67 StackInspector.walker.set(StackInspector.walkerHide); 68 69 // Calls the StackInspector.create method through reflection 70 // and check the frames collected in the StackInspector 71 // default constructor. 72 // The create method invokes new StackInspector() directly. 73 // No reflection frame should appear. 74 System.out.println("testNewStackInspector: create"); 75 76 StackInspector obj = ((StackInspector)StackInspector.Caller.class 77 .getMethod("create", How.class) 78 .invoke(null, How.NEW)); 79 assertEquals(obj.collectedFrames, 80 List.of(StackInspector.class.getName() 81 +"::<init>", 82 StackInspector.Caller.class.getName() 83 +"::create", 84 ReflectionFrames.class.getName() 85 +"::testNewStackInspector")); 86 assertEquals(obj.cls, StackInspector.Caller.class); 87 assertEquals(obj.filtered, 0); 88 89 // Calls the StackInspector.reflect method through reflection 90 // and check the frames collected in the StackInspector 91 // default constructor. 92 // The reflect method invokes the create method through 93 // reflection. 94 // The create method invokes new StackInspector() directly. 95 // No reflection frame should appear. 96 System.out.println("testNewStackInspector: reflect"); 97 98 obj = ((StackInspector)StackInspector.Caller.class 99 .getMethod("reflect", How.class) 100 .invoke(null, How.NEW)); 101 assertEquals(obj.collectedFrames, 102 List.of(StackInspector.class.getName() 103 +"::<init>", 104 StackInspector.Caller.class.getName() 105 +"::create", 106 StackInspector.Caller.class.getName() 107 +"::reflect", 108 ReflectionFrames.class.getName() 109 +"::testNewStackInspector")); 110 assertEquals(obj.cls, StackInspector.Caller.class); 111 assertEquals(obj.filtered, 0); 112 113 // Calls the StackInspector.handle method through reflection 114 // and check the frames collected in the StackInspector 115 // default constructor. 116 // The handle method invokes the create method using 117 // a MethodHandle. 118 // The create method invokes new StackInspector() directly. 119 // No reflection frame should appear. 120 System.out.println("testNewStackInspector: handle"); 121 122 obj = ((StackInspector)StackInspector.Caller.class 123 .getMethod("handle", How.class) 124 .invoke(null, How.NEW)); 125 assertEquals(obj.collectedFrames, 126 List.of(StackInspector.class.getName() 127 +"::<init>", 128 StackInspector.Caller.class.getName() 129 +"::create", 130 StackInspector.Caller.class.getName() 131 +"::handle", 132 ReflectionFrames.class.getName() 133 +"::testNewStackInspector")); 134 assertEquals(obj.cls, StackInspector.Caller.class); 135 assertEquals(obj.filtered, 0); 136 137 // Sets a non-default walker configured to show 138 // reflection frames 139 StackInspector.walker.set(StackInspector.walkerShow); 140 141 // Calls the StackInspector.create method through reflection 142 // and check the frames collected in the StackInspector 143 // default constructor. 144 // The create method invokes new StackInspector() directly. 145 // We should see all reflection frames, except the 146 // jdk.internal.reflect frames which we are filtering 147 // out in StackInspector::filter. 148 System.out.println("testNewStackInspector: create: show reflect"); 149 150 obj = ((StackInspector)StackInspector.Caller.class 151 .getMethod("create", How.class) 152 .invoke(null, How.NEW)); 153 assertEquals(obj.collectedFrames, 154 List.of(StackInspector.class.getName() 155 +"::<init>", 156 StackInspector.Caller.class.getName() 157 +"::create", 158 Method.class.getName() 159 +"::invoke", 160 ReflectionFrames.class.getName() 161 +"::testNewStackInspector")); 162 assertEquals(obj.cls, StackInspector.Caller.class); 163 assertNotEquals(obj.filtered, 0); 164 165 // Calls the StackInspector.reflect method through reflection 166 // and check the frames collected in the StackInspector 167 // default constructor. 168 // The reflect method invokes the create method through 169 // reflection. 170 // The create method invokes new StackInspector() directly. 171 // We should see all reflection frames, except the 172 // jdk.internal.reflect frames which we are filtering 173 // out in StackInspector::filter. 174 System.out.println("testNewStackInspector: reflect: show reflect"); 175 176 obj = ((StackInspector)StackInspector.Caller.class 177 .getMethod("reflect", How.class) 178 .invoke(null, How.NEW)); 179 assertEquals(obj.collectedFrames, 180 List.of(StackInspector.class.getName() 181 +"::<init>", 182 StackInspector.Caller.class.getName() 183 +"::create", 184 Method.class.getName() 185 +"::invoke", 186 StackInspector.Caller.class.getName() 187 +"::reflect", 188 Method.class.getName() 189 +"::invoke", 190 ReflectionFrames.class.getName() 191 +"::testNewStackInspector")); 192 assertEquals(obj.cls, StackInspector.Caller.class); 193 assertNotEquals(obj.filtered, 0); 194 195 // Calls the StackInspector.handle method through reflection 196 // and check the frames collected in the StackInspector 197 // default constructor. 198 // The handle method invokes the create method using 199 // MethodHandle. 200 // The create method invokes new StackInspector() directly. 201 // We should see all reflection frames, except the 202 // jdk.internal.reflect frames which we are filtering 203 // out in StackInspector::filter. 204 System.out.println("testNewStackInspector: handle: show reflect"); 205 206 obj = ((StackInspector)StackInspector.Caller.class 207 .getMethod("handle", How.class) 208 .invoke(null, How.NEW)); 209 assertEquals(obj.collectedFrames, 210 List.of(StackInspector.class.getName() 211 +"::<init>", 212 StackInspector.Caller.class.getName() 213 +"::create", 214 // MethodHandle::invoke remains hidden 215 StackInspector.Caller.class.getName() 216 +"::handle", 217 Method.class.getName() 218 +"::invoke", 219 ReflectionFrames.class.getName() 220 +"::testNewStackInspector")); 221 assertEquals(obj.cls, StackInspector.Caller.class); 222 assertNotEquals(obj.filtered, 0); 223 } 224 225 /** 226 * This test invokes Constructor.newInstance() from 227 * the caller StackInspector.Caller.create method. 228 * It checks that the caller is StackInspector.Caller. 229 * It also checks the expected frames collected 230 * by walking the stack from the default StackInspector() 231 * constructor. 232 * This is done twice, once using a default StackWalker 233 * that hides reflection frames, once using a StackWalker 234 * configured to show reflection frames. 235 */ 236 @Test 237 public static void testConstructor() throws Exception { 238 // Sets the default walker which hides reflection 239 // frames. 240 StackInspector.walker.set(StackInspector.walkerHide); 241 242 // Calls the StackInspector.create method through reflection 243 // and check the frames collected in the StackInspector 244 // default constructor. 245 // The create method invokes Constructor.newInstance(). 246 // No reflection frame should appear. 247 System.out.println("testConstructor: create"); 248 249 StackInspector obj = ((StackInspector)StackInspector.Caller.class 250 .getMethod("create", How.class) 251 .invoke(null, How.CONSTRUCTOR)); 252 assertEquals(obj.collectedFrames, 253 List.of(StackInspector.class.getName() 254 +"::<init>", 255 StackInspector.Caller.class.getName() 256 +"::create", 257 ReflectionFrames.class.getName() 258 +"::testConstructor")); 259 assertEquals(obj.cls, StackInspector.Caller.class); 260 assertEquals(obj.filtered, 0); 261 262 // Calls the StackInspector.reflect method through reflection 263 // and check the frames collected in the StackInspector 264 // default constructor. 265 // The reflect method invokes the create method through 266 // reflection. 267 // The create method invokes Constructor.newInstance(). 268 // No reflection frame should appear. 269 System.out.println("testConstructor: reflect"); 270 271 obj = ((StackInspector)StackInspector.Caller.class 272 .getMethod("reflect", How.class) 273 .invoke(null, How.CONSTRUCTOR)); 274 assertEquals(obj.collectedFrames, 275 List.of(StackInspector.class.getName() 276 +"::<init>", 277 StackInspector.Caller.class.getName() 278 +"::create", 279 StackInspector.Caller.class.getName() 280 +"::reflect", 281 ReflectionFrames.class.getName() 282 +"::testConstructor")); 283 assertEquals(obj.cls, StackInspector.Caller.class); 284 assertEquals(obj.filtered, 0); 285 286 // Calls the StackInspector.handle method through reflection 287 // and check the frames collected in the StackInspector 288 // default constructor. 289 // The handle method invokes the create method using 290 // MethodHandle. 291 // The create method invokes Constructor.newInstance(). 292 // No reflection frame should appear. 293 System.out.println("testConstructor: handle"); 294 295 obj = ((StackInspector)StackInspector.Caller.class 296 .getMethod("handle", How.class) 297 .invoke(null, How.CONSTRUCTOR)); 298 assertEquals(obj.collectedFrames, 299 List.of(StackInspector.class.getName() 300 +"::<init>", 301 StackInspector.Caller.class.getName() 302 +"::create", 303 StackInspector.Caller.class.getName() 304 +"::handle", 305 ReflectionFrames.class.getName() 306 +"::testConstructor")); 307 assertEquals(obj.cls, StackInspector.Caller.class); 308 assertEquals(obj.filtered, 0); 309 310 // Sets a non-default walker configured to show 311 // reflection frames 312 StackInspector.walker.set(StackInspector.walkerShow); 313 314 // Calls the StackInspector.create method through reflection 315 // and check the frames collected in the StackInspector 316 // default constructor. 317 // The create method invokes Constructor.newInstance(). 318 // We should see all reflection frames, except the 319 // jdk.internal.reflect frames which we are filtering 320 // out in StackInspector::filter. 321 System.out.println("testConstructor: create: show reflect"); 322 323 obj = ((StackInspector)StackInspector.Caller.class 324 .getMethod("create", How.class) 325 .invoke(null, How.CONSTRUCTOR)); 326 assertEquals(obj.collectedFrames, 327 List.of(StackInspector.class.getName() 328 +"::<init>", 329 Constructor.class.getName() 330 +"::newInstance", 331 StackInspector.Caller.class.getName() 332 +"::create", 333 Method.class.getName() 334 +"::invoke", 335 ReflectionFrames.class.getName() 336 +"::testConstructor")); 337 assertEquals(obj.cls, StackInspector.Caller.class); 338 assertNotEquals(obj.filtered, 0); 339 340 // Calls the StackInspector.reflect method through reflection 341 // and check the frames collected in the StackInspector 342 // default constructor. 343 // The reflect method invokes the create method through 344 // reflection. 345 // The create method invokes Constructor.newInstance(). 346 // We should see all reflection frames, except the 347 // jdk.internal.reflect frames which we are filtering 348 // out in StackInspector::filter. 349 System.out.println("testConstructor: reflect: show reflect"); 350 351 obj = ((StackInspector)StackInspector.Caller.class 352 .getMethod("reflect", How.class) 353 .invoke(null, How.CONSTRUCTOR)); 354 assertEquals(obj.collectedFrames, 355 List.of(StackInspector.class.getName() 356 +"::<init>", 357 Constructor.class.getName() 358 +"::newInstance", 359 StackInspector.Caller.class.getName() 360 +"::create", 361 Method.class.getName() 362 +"::invoke", 363 StackInspector.Caller.class.getName() 364 +"::reflect", 365 Method.class.getName() 366 +"::invoke", 367 ReflectionFrames.class.getName() 368 +"::testConstructor")); 369 assertEquals(obj.cls, StackInspector.Caller.class); 370 assertNotEquals(obj.filtered, 0); 371 372 // Calls the StackInspector.handle method through reflection 373 // and check the frames collected in the StackInspector 374 // default constructor. 375 // The handle method invokes the create method using 376 // MethodHandle. 377 // The create method invokes Constructor.newInstance(). 378 // We should see all reflection frames, except the 379 // jdk.internal.reflect frames which we are filtering 380 // out in StackInspector::filter. 381 System.out.println("testConstructor: handle: show reflect"); 382 383 obj = ((StackInspector)StackInspector.Caller.class 384 .getMethod("handle", How.class) 385 .invoke(null, How.CONSTRUCTOR)); 386 assertEquals(obj.collectedFrames, 387 List.of(StackInspector.class.getName() 388 +"::<init>", 389 Constructor.class.getName() 390 +"::newInstance", 391 StackInspector.Caller.class.getName() 392 +"::create", 393 // MethodHandle::invoke remains hidden 394 StackInspector.Caller.class.getName() 395 +"::handle", 396 Method.class.getName() 397 +"::invoke", 398 ReflectionFrames.class.getName() 399 +"::testConstructor")); 400 assertEquals(obj.cls, StackInspector.Caller.class); 401 assertNotEquals(obj.filtered, 0); 402 } 403 404 /** 405 * This test invokes StackInspector.class.newInstance() from 406 * the caller StackInspector.Caller.create method. Because 407 * Class.newInstance() is not considered as a 408 * reflection frame, the the caller returned by 409 * getCallerClass() should appear to be java.lang.Class 410 * and not StackInspector.Caller. 411 * It also checks the expected frames collected 412 * by walking the stack from the default StackInspector() 413 * constructor. 414 * This is done twice, once using a default StackWalker 415 * that hides reflection frames, once using a StackWalker 416 * configured to show reflection frames. 417 */ 418 @Test 419 public static void testNewInstance() throws Exception { 420 // Sets the default walker which hides reflection 421 // frames. 422 StackInspector.walker.set(StackInspector.walkerHide); 423 424 // Calls the StackInspector.create method through reflection 425 // and check the frames collected in the StackInspector 426 // default constructor. 427 // The create method invokes StackInspector.class.newInstance(). 428 // No reflection frame should appear, except 429 // Class::newInstance which is not considered as 430 // a reflection frame. 431 System.out.println("testNewInstance: create"); 432 433 StackInspector obj = ((StackInspector)StackInspector.Caller.class 434 .getMethod("create", How.class) 435 .invoke(null, How.CLASS)); 436 assertEquals(obj.collectedFrames, 437 List.of(StackInspector.class.getName() 438 +"::<init>", 439 Class.class.getName() 440 +"::newInstance", 441 StackInspector.Caller.class.getName() 442 +"::create", 443 ReflectionFrames.class.getName() 444 +"::testNewInstance")); 445 // Because Class.newInstance is not filtered, then the 446 // caller is Class.class 447 assertEquals(obj.cls, Class.class); 448 assertEquals(obj.filtered, 0); 449 450 // Calls the StackInspector.reflect method through reflection 451 // and check the frames collected in the StackInspector 452 // default constructor. 453 // The reflect method invokes the create method through 454 // reflection. 455 // The create method invokes StackInspector.class.newInstance(). 456 // No reflection frame should appear, except 457 // Class::newInstance which is not considered as 458 // a reflection frame. 459 System.out.println("testNewInstance: reflect"); 460 461 obj = ((StackInspector)StackInspector.Caller.class 462 .getMethod("reflect", How.class) 463 .invoke(null, How.CLASS)); 464 assertEquals(obj.collectedFrames, 465 List.of(StackInspector.class.getName() 466 +"::<init>", 467 Class.class.getName() 468 +"::newInstance", 469 StackInspector.Caller.class.getName() 470 +"::create", 471 StackInspector.Caller.class.getName() 472 +"::reflect", 473 ReflectionFrames.class.getName() 474 +"::testNewInstance")); 475 476 // Because Class.newInstance is not filtered, then the 477 // caller is Class.class 478 assertEquals(obj.cls, Class.class); 479 assertEquals(obj.filtered, 0); 480 481 // Calls the StackInspector.handle method through reflection 482 // and check the frames collected in the StackInspector 483 // default constructor. 484 // The handle method invokes the create method using 485 // reflection. 486 // The create method invokes StackInspector.class.newInstance(). 487 // No reflection frame should appear, except 488 // Class::newInstance which is not considered as 489 // a reflection frame. 490 System.out.println("testNewInstance: handle"); 491 492 obj = ((StackInspector)StackInspector.Caller.class 493 .getMethod("handle", How.class) 494 .invoke(null, How.CLASS)); 495 assertEquals(obj.collectedFrames, 496 List.of(StackInspector.class.getName() 497 +"::<init>", 498 Class.class.getName() 499 +"::newInstance", 500 StackInspector.Caller.class.getName() 501 +"::create", 502 StackInspector.Caller.class.getName() 503 +"::handle", 504 ReflectionFrames.class.getName() 505 +"::testNewInstance")); 506 507 // Because Class.newInstance is not filtered, then the 508 // caller is Class.class 509 assertEquals(obj.cls, Class.class); 510 assertEquals(obj.filtered, 0); 511 512 // Sets a non-default walker configured to show 513 // reflection frames 514 StackInspector.walker.set(StackInspector.walkerShow); 515 516 // Calls the StackInspector.create method through reflection 517 // and check the frames collected in the StackInspector 518 // default constructor. 519 // The create method invokes StackInspector.class.newInstance(). 520 // We should see all reflection frames, except the 521 // jdk.internal.reflect frames which we are filtering 522 // out in StackInspector::filter. 523 System.out.println("testNewInstance: create: show reflect"); 524 525 obj = ((StackInspector)StackInspector.Caller.class 526 .getMethod("create", How.class) 527 .invoke(null, How.CLASS)); 528 assertEquals(obj.collectedFrames, 529 List.of(StackInspector.class.getName() 530 +"::<init>", 531 Constructor.class.getName() 532 +"::newInstance", 533 Class.class.getName() 534 +"::newInstance", 535 StackInspector.Caller.class.getName() 536 +"::create", 537 Method.class.getName() 538 +"::invoke", 539 ReflectionFrames.class.getName() 540 +"::testNewInstance")); 541 // Because Class.newInstance is not filtered, then the 542 // caller is Class.class 543 assertEquals(obj.cls, Class.class); 544 assertNotEquals(obj.filtered, 0); 545 546 // Calls the StackInspector.reflect method through reflection 547 // and check the frames collected in the StackInspector 548 // default constructor. 549 // The reflect method invokes the create method through 550 // reflection. 551 // The create method invokes StackInspector.class.newInstance(). 552 // We should see all reflection frames, except the 553 // jdk.internal.reflect frames which we are filtering 554 // out in StackInspector::filter. 555 System.out.println("testNewInstance: reflect: show reflect"); 556 557 obj = ((StackInspector)StackInspector.Caller.class 558 .getMethod("reflect", How.class) 559 .invoke(null, How.CLASS)); 560 assertEquals(obj.collectedFrames, 561 List.of(StackInspector.class.getName() 562 +"::<init>", 563 Constructor.class.getName() 564 +"::newInstance", 565 Class.class.getName() 566 +"::newInstance", 567 StackInspector.Caller.class.getName() 568 +"::create", 569 Method.class.getName() 570 +"::invoke", 571 StackInspector.Caller.class.getName() 572 +"::reflect", 573 Method.class.getName() 574 +"::invoke", 575 ReflectionFrames.class.getName() 576 +"::testNewInstance")); 577 578 // Because Class.newInstance is not filtered, then the 579 // caller is Class.class 580 assertEquals(obj.cls, Class.class); 581 assertNotEquals(obj.filtered, 0); 582 583 // Calls the StackInspector.handle method through reflection 584 // and check the frames collected in the StackInspector 585 // default constructor. 586 // The handle method invokes the create method using 587 // MethodHandle. 588 // The create method invokes StackInspector.class.newInstance(). 589 // We should see all reflection frames, except the 590 // jdk.internal.reflect frames which we are filtering 591 // out in StackInspector::filter. 592 System.out.println("testNewInstance: handle: show reflect"); 593 594 obj = ((StackInspector)StackInspector.Caller.class 595 .getMethod("handle", How.class) 596 .invoke(null, How.CLASS)); 597 assertEquals(obj.collectedFrames, 598 List.of(StackInspector.class.getName() 599 +"::<init>", 600 Constructor.class.getName() 601 +"::newInstance", 602 Class.class.getName() 603 +"::newInstance", 604 StackInspector.Caller.class.getName() 605 +"::create", 606 // MethodHandle::invoke remains hidden 607 StackInspector.Caller.class.getName() 608 +"::handle", 609 Method.class.getName() 610 +"::invoke", 611 ReflectionFrames.class.getName() 612 +"::testNewInstance")); 613 614 // Because Class.newInstance is not filtered, then the 615 // caller is Class.class 616 assertEquals(obj.cls, Class.class); 617 assertNotEquals(obj.filtered, 0); 618 } 619 620 @Test 621 public static void testGetCaller() throws Exception { 622 // Sets the default walker which hides reflection 623 // frames. 624 StackInspector.walker.set(StackInspector.walkerHide); 625 626 assertEquals(StackInspector.getCaller(), ReflectionFrames.class); 627 assertEquals(StackInspector.class.getMethod("getCaller").invoke(null), 628 ReflectionFrames.class); 629 630 // Sets a non-default walker configured to show 631 // reflection frames 632 StackInspector.walker.set(StackInspector.walkerShow); 633 634 assertEquals(StackInspector.getCaller(), ReflectionFrames.class); 635 assertEquals(StackInspector.class.getMethod("getCaller").invoke(null), 636 ReflectionFrames.class); 637 } 638 639 @Test 640 public static void testReflectCaller() throws Exception { 641 // Sets the default walker which hides reflection 642 // frames. 643 StackInspector.walker.set(StackInspector.walkerHide); 644 645 assertEquals(StackInspector.reflectCaller(), ReflectionFrames.class); 646 assertEquals(StackInspector.class.getMethod("reflectCaller").invoke(null), 647 ReflectionFrames.class); 648 649 // Sets a non-default walker configured to show 650 // reflection frames 651 StackInspector.walker.set(StackInspector.walkerShow); 652 653 assertEquals(StackInspector.reflectCaller(), ReflectionFrames.class); 654 assertEquals(StackInspector.class.getMethod("reflectCaller").invoke(null), 655 ReflectionFrames.class); 656 } 657 658 @Test 659 public static void testSupplyCaller() throws Exception { 660 // Sets the default walker which hides reflection 661 // frames. 662 StackInspector.walker.set(StackInspector.walkerHide); 663 664 assertEquals(StackInspector.supplyCaller(), ReflectionFrames.class); 665 assertEquals(StackInspector.class.getMethod("supplyCaller").invoke(null), 666 ReflectionFrames.class); 667 668 // Sets a non-default walker configured to show 669 // reflection frames 670 StackInspector.walker.set(StackInspector.walkerShow); 671 672 assertEquals(StackInspector.supplyCaller(), ReflectionFrames.class); 673 assertEquals(StackInspector.class.getMethod("supplyCaller").invoke(null), 674 ReflectionFrames.class); 675 } 676 677 @Test 678 public static void testHandleCaller() throws Exception { 679 // Sets the default walker which hides reflection 680 // frames. 681 StackInspector.walker.set(StackInspector.walkerHide); 682 683 assertEquals(StackInspector.handleCaller(), ReflectionFrames.class); 684 assertEquals(StackInspector.class.getMethod("handleCaller").invoke(null), 685 ReflectionFrames.class); 686 687 // Sets a non-default walker configured to show 688 // reflection frames 689 StackInspector.walker.set(StackInspector.walkerShow); 690 691 assertEquals(StackInspector.handleCaller(), ReflectionFrames.class); 692 assertEquals(StackInspector.class.getMethod("handleCaller").invoke(null), 693 ReflectionFrames.class); 694 } 695 696 static enum How { NEW, CONSTRUCTOR, CLASS}; 697 698 /** 699 * An object that collect stack frames by walking the stack 700 * (and calling getCallerClass()) from within its constructor. 701 * For the purpose of this test, StackInspector objects are 702 * always created from the nested StackInspector.Caller class, 703 * which should therefore appear as the caller of the 704 * StackInspector constructor. 705 */ 706 static class StackInspector { 707 static final StackWalker walkerHide = 708 StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE); 709 static final StackWalker walkerShow = 710 StackWalker.getInstance(EnumSet.of( 711 StackWalker.Option.RETAIN_CLASS_REFERENCE, 712 StackWalker.Option.SHOW_REFLECT_FRAMES)); 713 final static ThreadLocal<StackWalker> walker = new ThreadLocal<>() { 714 protected StackWalker initialValue() { 715 return walkerHide; 716 } 717 }; 718 719 List<String> collectedFrames; 720 Class<?> cls = null; 721 boolean stop; 722 int filtered; 723 final boolean filterImplFrames; 724 725 public StackInspector() { 726 stop = false; 727 // if reflection frames are not hidden, we want to 728 // filter implementation frames before collecting 729 // to avoid depending on internal details. 730 filterImplFrames = walker.get() == walkerShow; 731 collectedFrames = walker.get().walk(this::parse); 732 cls = walker.get().getCallerClass(); 733 } 734 735 public List<String> collectedFrames() { 736 return collectedFrames; 737 } 738 739 // The takeWhile method arrange for stopping frame collection 740 // as soon as a frame from ReflectionFrames.class is reached. 741 // The first such frame encountered is still included in the 742 // collected frames, but collection stops right after. 743 // This makes it possible to filter out anything above the 744 // the test method frame, such as frames from the test 745 // framework. 746 public boolean takeWhile(StackFrame f) { 747 if (stop) return false; 748 if (verbose) System.out.println(" " + f); 749 stop = stop || f.getDeclaringClass() == ReflectionFrames.class; 750 return true; 751 } 752 753 // filter out implementation frames to avoid depending 754 // on implementation details. If present, Class::newInstance, 755 // Method::invoke and Constructor::newInstance will 756 // still appear in the collected frames, which is 757 // sufficient for the purpose of the test. 758 // In the case where the StackWalker itself is supposed to 759 // filter the reflection frames, then this filter will always 760 // return true. This way, if such a reflection frame appears when 761 // it sjould have been filtered by StackWalker, it will make the 762 // test fail. 763 public boolean filter(StackFrame f) { 764 if (filterImplFrames && 765 f.getClassName().startsWith("jdk.internal.reflect.")) { 766 filtered++; 767 return false; 768 } 769 if (!verbose) System.out.println(" " + f); 770 return true; 771 } 772 773 public String frame(StackFrame f) { 774 return f.getClassName() + "::" + f.getMethodName(); 775 } 776 777 List<String> parse(Stream<StackFrame> s) { 778 return s.takeWhile(this::takeWhile) 779 .filter(this::filter) 780 .map(this::frame) 781 .collect(Collectors.toList()); 782 } 783 784 /** 785 * The Caller class is used to create instances of 786 * StackInspector, either direcltly, or throug reflection. 787 */ 788 public static class Caller { 789 public static StackInspector create(How how) throws Exception { 790 switch(how) { 791 case NEW: return new StackInspector(); 792 case CONSTRUCTOR: return StackInspector.class 793 .getConstructor().newInstance(); 794 case CLASS: return StackInspector.class.newInstance(); 795 default: throw new AssertionError(String.valueOf(how)); 796 } 797 } 798 public static StackInspector reflect(How how) throws Exception { 799 return (StackInspector) Caller.class.getMethod("create", How.class) 800 .invoke(null, how); 801 } 802 public static StackInspector handle(How how) throws Exception { 803 Lookup lookup = MethodHandles.lookup(); 804 MethodHandle mh = lookup.findStatic(Caller.class, "create", 805 MethodType.methodType(StackInspector.class, How.class)); 806 try { 807 return (StackInspector) mh.invoke(how); 808 } catch (Error | Exception x) { 809 throw x; 810 } catch(Throwable t) { 811 throw new AssertionError(t); 812 } 813 } 814 } 815 816 public static Class<?> getCaller() throws Exception { 817 return walker.get().getCallerClass(); 818 } 819 820 public static Class<?> reflectCaller() throws Exception { 821 return (Class<?>)StackWalker.class.getMethod("getCallerClass") 822 .invoke(walker.get()); 823 } 824 825 public static Class<?> supplyCaller() throws Exception { 826 return ((Supplier<Class<?>>)StackInspector.walker.get()::getCallerClass).get(); 827 } 828 829 public static Class<?> handleCaller() throws Exception { 830 Lookup lookup = MethodHandles.lookup(); 831 MethodHandle mh = lookup.findVirtual(StackWalker.class, "getCallerClass", 832 MethodType.methodType(Class.class)); 833 try { 834 return (Class<?>) mh.invoke(walker.get()); 835 } catch (Error | Exception x) { 836 throw x; 837 } catch(Throwable t) { 838 throw new AssertionError(t); 839 } 840 } 841 } 842} 843