I also think IllegalStateException is better than UOE for this case as getCallerClass is inappropriate to be called where there is no caller frame.
Mandy > On Nov 18, 2015, at 5:12 AM, fo...@univ-mlv.fr wrote: > > 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 >>>>> >> >>