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.lev...@gmail.com>
> À: "Remi Forax" <fo...@univ-mlv.fr>, "David Holmes" <david.hol...@oracle.com>
> Cc: "Mandy Chung" <mandy.ch...@oracle.com>, "OpenJDK Dev list" 
> <core-libs-dev@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.hol...@oracle.com>
> >> À: "Mandy Chung" <mandy.ch...@oracle.com>, "Peter Levart"
> >> <peter.lev...@gmail.com>
> >> Cc: "OpenJDK Dev list" <core-libs-dev@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.lev...@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
> >>>
> 
> 

Reply via email to