Proposed API for JEP 259: Stack-Walking API
Mandy Chung
mandy.chung at oracle.com
Tue Nov 17 22:42:47 UTC 2015
> 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.
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