448 * which is the method calling this {@code forEach} method. 449 * 450 * <p> This method is equivalent to calling 451 * <blockquote> 452 * {@code walk(s -> { s.forEach(action); return null; });} 453 * </blockquote> 454 * 455 * @param action an action to be performed on each {@code StackFrame} 456 * of the stack of the current thread 457 */ 458 @CallerSensitive 459 public void forEach(Consumer<? super StackFrame> action) { 460 Objects.requireNonNull(action); 461 StackStreamFactory.makeStackTraverser(this, s -> { 462 s.forEach(action); 463 return null; 464 }).walk(); 465 } 466 467 /** 468 * Gets the {@code Class} object of the caller invoking the method 469 * that calls this {@code getCallerClass} method. 470 * 471 * <p> Reflection frames, {@link java.lang.invoke.MethodHandle}, and 472 * hidden frames are filtered regardless of the 473 * {@link Option#SHOW_REFLECT_FRAMES SHOW_REFLECT_FRAMES} 474 * and {@link Option#SHOW_HIDDEN_FRAMES SHOW_HIDDEN_FRAMES} options 475 * this {@code StackWalker} has been configured with. 476 * 477 * <p> This method throws {@code UnsupportedOperationException} 478 * if this {@code StackWalker} is not configured with the 479 * {@link Option#RETAIN_CLASS_REFERENCE RETAIN_CLASS_REFERENCE} option. 480 * This method should be called when a caller frame is present. If 481 * it is called from the last frame on the stack, 482 * {@code IllegalStateException} will be thrown. 483 * 484 * @apiNote 485 * For example, {@code Util::getResourceBundle} loads a resource bundle 486 * on behalf of the caller. It calls this {@code getCallerClass} method 487 * to find the method calling {@code Util::getResourceBundle} and uses the caller's 488 * class loader to load the resource bundle. The caller class in this example 489 * is the {@code MyTool} class. 490 * 491 * <pre>{@code 492 * class Util { 493 * private final StackWalker walker = StackWalker.getInstance(Option.RETAIN_CLASS_REFERENCE); 494 * public ResourceBundle getResourceBundle(String bundleName) { 495 * Class<?> caller = walker.getCallerClass(); 496 * return ResourceBundle.getBundle(bundleName, Locale.getDefault(), caller.getClassLoader()); 497 * } 498 * } 499 * 500 * class MyTool { 501 * private final Util util = new Util(); 502 * private void init() { 503 * ResourceBundle rb = util.getResourceBundle("mybundle"); 504 * } 505 * } 506 * }</pre> 507 * 508 * An equivalent way to find the caller class using the 509 * {@link StackWalker#walk walk} method is as follows 510 * (filtering the reflection frames, {@code MethodHandle} and hidden frames 511 * not shown below): 512 * <pre>{@code 513 * Optional<Class<?>> caller = walker.walk(s -> 514 * s.map(StackFrame::getDeclaringClass) 515 * .skip(2) 516 * .findFirst()); 517 * }</pre> 518 * 519 * When the {@code getCallerClass} method is called from a method that 520 * is the last frame on the stack, 521 * for example, {@code static public void main} method launched by the 522 * {@code java} launcher, or a method invoked from a JNI attached thread, 523 * {@code IllegalStateException} is thrown. 524 * 525 * @return {@code Class} object of the caller's caller invoking this method. 526 * 527 * @throws UnsupportedOperationException if this {@code StackWalker} 528 * is not configured with {@link Option#RETAIN_CLASS_REFERENCE 529 * Option.RETAIN_CLASS_REFERENCE}. 530 * @throws IllegalStateException if there is no caller frame, i.e. 531 * when this {@code getCallerClass} method is called from a method 532 * which is the last frame on the stack. 533 */ 534 @CallerSensitive 535 public Class<?> getCallerClass() { 536 if (!options.contains(Option.RETAIN_CLASS_REFERENCE)) { 537 throw new UnsupportedOperationException("This stack walker " + 538 "does not have RETAIN_CLASS_REFERENCE access"); 539 } 540 541 return StackStreamFactory.makeCallerFinder(this).findCaller(); 542 } 543 544 // ---- package access ---- 545 546 static StackWalker newInstance(Set<Option> options, ExtendedOption extendedOption) { 547 EnumSet<Option> optionSet = toEnumSet(options); 548 checkPermission(optionSet); 549 return new StackWalker(optionSet, 0, extendedOption); 550 } | 448 * which is the method calling this {@code forEach} method. 449 * 450 * <p> This method is equivalent to calling 451 * <blockquote> 452 * {@code walk(s -> { s.forEach(action); return null; });} 453 * </blockquote> 454 * 455 * @param action an action to be performed on each {@code StackFrame} 456 * of the stack of the current thread 457 */ 458 @CallerSensitive 459 public void forEach(Consumer<? super StackFrame> action) { 460 Objects.requireNonNull(action); 461 StackStreamFactory.makeStackTraverser(this, s -> { 462 s.forEach(action); 463 return null; 464 }).walk(); 465 } 466 467 /** 468 * Gets the {@code Class} object of the caller who invoked the method 469 * that invoked {@code getCallerClass}. 470 * 471 * <p> Reflection frames, {@link java.lang.invoke.MethodHandle}, and 472 * hidden frames are filtered regardless of the 473 * {@link Option#SHOW_REFLECT_FRAMES SHOW_REFLECT_FRAMES} 474 * and {@link Option#SHOW_HIDDEN_FRAMES SHOW_HIDDEN_FRAMES} options 475 * this {@code StackWalker} has been configured with. 476 * 477 * <p> This method should be called when a caller frame is present. If 478 * it is called from the bottom most frame on the stack, 479 * {@code IllegalCallerException} will be thrown. 480 * 481 * <p> This method throws {@code UnsupportedOperationException} 482 * if this {@code StackWalker} is not configured with the 483 * {@link Option#RETAIN_CLASS_REFERENCE RETAIN_CLASS_REFERENCE} option. 484 * 485 * @apiNote 486 * For example, {@code Util::getResourceBundle} loads a resource bundle 487 * on behalf of the caller. It invokes {@code getCallerClass} to identify 488 * the class whose method called {@code Util::getResourceBundle}. 489 * Then, it obtains the class loader of that class, and uses 490 * the class loader to load the resource bundle. The caller class 491 * in this example is {@code MyTool}. 492 * 493 * <pre>{@code 494 * class Util { 495 * private final StackWalker walker = StackWalker.getInstance(Option.RETAIN_CLASS_REFERENCE); 496 * public ResourceBundle getResourceBundle(String bundleName) { 497 * Class<?> caller = walker.getCallerClass(); 498 * return ResourceBundle.getBundle(bundleName, Locale.getDefault(), caller.getClassLoader()); 499 * } 500 * } 501 * 502 * class MyTool { 503 * private final Util util = new Util(); 504 * private void init() { 505 * ResourceBundle rb = util.getResourceBundle("mybundle"); 506 * } 507 * } 508 * }</pre> 509 * 510 * An equivalent way to find the caller class using the 511 * {@link StackWalker#walk walk} method is as follows 512 * (filtering the reflection frames, {@code MethodHandle} and hidden frames 513 * not shown below): 514 * <pre>{@code 515 * Optional<Class<?>> caller = walker.walk(s -> 516 * s.map(StackFrame::getDeclaringClass) 517 * .skip(2) 518 * .findFirst()); 519 * }</pre> 520 * 521 * When the {@code getCallerClass} method is called from a method that 522 * is the bottom most frame on the stack, 523 * for example, {@code static public void main} method launched by the 524 * {@code java} launcher, or a method invoked from a JNI attached thread, 525 * {@code IllegalCallerException} is thrown. 526 * 527 * @return {@code Class} object of the caller's caller invoking this method. 528 * 529 * @throws UnsupportedOperationException if this {@code StackWalker} 530 * is not configured with {@link Option#RETAIN_CLASS_REFERENCE 531 * Option.RETAIN_CLASS_REFERENCE}. 532 * @throws IllegalCallerException if there is no caller frame, i.e. 533 * when this {@code getCallerClass} method is called from a method 534 * which is the last frame on the stack. 535 */ 536 @CallerSensitive 537 public Class<?> getCallerClass() { 538 if (!options.contains(Option.RETAIN_CLASS_REFERENCE)) { 539 throw new UnsupportedOperationException("This stack walker " + 540 "does not have RETAIN_CLASS_REFERENCE access"); 541 } 542 543 return StackStreamFactory.makeCallerFinder(this).findCaller(); 544 } 545 546 // ---- package access ---- 547 548 static StackWalker newInstance(Set<Option> options, ExtendedOption extendedOption) { 549 EnumSet<Option> optionSet = toEnumSet(options); 550 checkPermission(optionSet); 551 return new StackWalker(optionSet, 0, extendedOption); 552 } |