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