On 18/11/2015 10:26 PM, Peter Levart wrote:


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

I agree with Remi. "state" doesn't have to mean fields - there are numerous existing examples in the JDK. Calling a method in a context that is invalid is an illegal state to me. IllegalThreadStateException would also work. But UnsupportedOperationException ... more of a stretch.

David
-----

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