Proposed API for JEP 259: Stack-Walking API

David Holmes david.holmes at oracle.com
Wed Nov 18 07:58:56 UTC 2015


On 18/11/2015 8:42 AM, Mandy Chung wrote:
>
>> On Nov 17, 2015, at 2:09 PM, Peter Levart <peter.levart at gmail.com> wrote:
>>
>> I think that calling getCallerClass() from implementation of Runnable::run should expect it to return a system class. It may be Thread.class or ThreadPoolExecutor$Worker.class or anything actually.
>>
>
> I’m now convinced that it’s not a good idea to special case it.  getCallerClass will simply return the caller frame (i.e. top-2) on the stack and throw UOE if there is no caller frame.  The user should call StackWalker::walk instead if this special case matters.

That sounds good to me too.

David

> How does this look?
>
> /**
>   * Gets the {@code Class} object of the caller invoking the method
>   * that calls this {@code getCallerClass} method.
>   *
>   * <p> Reflection frames, {@link java.lang.invoke.MethodHandle} and
>   * hidden frames are filtered regardless of the
>   * {@link Option#SHOW_REFLECT_FRAMES SHOW_REFLECT_FRAMES}
>   * and {@link Option#SHOW_HIDDEN_FRAMES SHOW_HIDDEN_FRAMES} options
>   * if this {@code StackWalker} has been configured.
>   *
>   * <p> This method throws {@code UnsupportedOperationException} if
>   * this {@code StackWalker} is not configured with
>   * {@link Option#RETAIN_CLASS_REFERENCE RETAIN_CLASS_REFERENCE} option
>   * or this method is called from the last frame on the stack,
>   * i.e. invoked from a JNI attached thread (
>   * for example, {@code static public void main} method launched by the
>   * {@code java} launcher).
>   *
>   * @apiNote
>   * For example, {@code Util::getResourceBundle} loads a resource bundle
>   * on behalf of the caller.  It calls this {@code getCallerClass} method
>   * to find the method calling {@code Util::getResourceBundle} and use the caller's
>   * class loader to load the resource bundle. The caller class in this example
>   * is the {@code MyTool} class.
>   *
>   * <pre>{@code
>   *     class Util {
>   *         private final StackWalker walker = StackWalker.getInstance(Option.RETAIN_CLASS_REFERENCE);
>   *         public ResourceBundle getResourceBundle(String bundleName) {
>   *             Class<?> caller = walker.getCallerClass();
>   *             return ResourceBundle.getBundle(bundleName, caller.getClassLoader());
>   *         }
>   *     }
>   *
>   *     class MyTool {
>   *         private void init() {
>   *             ResourceBundle rb = Util.getResourceBundle("mybundle");
>   *         }
>   *     }
>   * }</pre>
>   *
>   * An equivalent way to find the caller class using the
>   * {@link StackWalker#walk walk} method is as follows
>   * (filtering the reflection frames, {@code MethodHandle} and hidden frames
>   * not shown below):
>   * <pre>{@code
>   *     Optional<Class<?>> caller = walker.walk(s ->
>   *         s.map(StackFrame::getDeclaringClass)
>   *          .skip(2)
>   *          .findFirst());
>   * }</pre>
>   *
>   * When the {@code getCallerClass} method is called from a method that
>   * is the last frame on the stack, i.e. invoked from a JNI attached thread,
>   * for example, {@code static public void main} method launched by the
>   * {@code java} launcher,
>   *
>   * @return {@code Class} object of the caller's caller invoking this method.
>   *
>   * @throws UnsupportedOperationException if this {@code StackWalker}
>   *         is not configured with {@link Option#RETAIN_CLASS_REFERENCE
>   *         Option.RETAIN_CLASS_REFERENCE}.
>   * @throws UnsupportedOperationException if there is no caller frame, i.e.
>   *         when this {@code getCallerClass} method is called from a method
>   *         which is the last frame on the stack.
>   */
>
> Mandy
>



More information about the core-libs-dev mailing list