Proposed API for JEP 259: Stack-Walking API
forax at univ-mlv.fr
forax at univ-mlv.fr
Wed Nov 18 13:12:43 UTC 2015
Hi peter,
Given this is a stack walker, considering the stack as a state seems natural to me.
Rémi
----- Mail original -----
> De: "Peter Levart" <peter.levart at gmail.com>
> À: "Remi Forax" <forax at univ-mlv.fr>, "David Holmes" <david.holmes at oracle.com>
> Cc: "Mandy Chung" <mandy.chung at oracle.com>, "OpenJDK Dev list" <core-libs-dev at openjdk.java.net>
> Envoyé: Mercredi 18 Novembre 2015 13:26:32
> Objet: Re: Proposed API for JEP 259: Stack-Walking API
>
>
>
> On 11/18/2015 12:22 PM, Remi Forax wrote:
> > ----- Mail original -----
> >> De: "David Holmes" <david.holmes at oracle.com>
> >> À: "Mandy Chung" <mandy.chung at oracle.com>, "Peter Levart"
> >> <peter.levart at gmail.com>
> >> Cc: "OpenJDK Dev list" <core-libs-dev at openjdk.java.net>
> >> Envoyé: Mercredi 18 Novembre 2015 08:58:56
> >> Objet: Re: Proposed API for JEP 259: Stack-Walking API
> >>
> >> 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
> > Looks good to me too if IllegalStateException is used instead of
> > UnsupportedOperationException.
> > UnsuppportedOperationException is used when the operation is not available,
> > here, the same code can work or not depending how it is called.
>
> But IllegalStateException is dependent on some state. There's no state
> involved here (in the sense "state" is characterized in Java). My 1st
> thought was an IllegalArgumentException. This requires some imagination
> to view the caller passed to the method as an implicit argument.
>
> There's an obscure java.util.EmptyStackException but that is reserved
> for java.util.Stack operations.
>
> If we consider the call stack to be part of the Thread state, then maybe
> java.lang.IllegalThreadStateException (a subclass of
> IllegalArgumentException) could be used...
>
> Regards, Peter
>
> > Runnable r = () -> System.out.println(stackWalker.getCallerClass());
> > new Thread(r).start() // throw ISE
> > r.run(); // prints main class
> >
> > Rémi
> >
> >>> 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