Hi Mandy,

On 11/17/2015 01:13 AM, Mandy Chung wrote:
I’d like to get the code review done by this week.

I renamed the static factory method from create to getInstance since “create” 
implies to create a new instance but the method returns a cached instance 
instead.  I also changed the spec of getCallerClass per [1].  There is not much 
change since webrev.01.

Webrev:
    http://cr.openjdk.java.net/~mchung/jdk9/jep259/webrev.02

javadoc:
    http://cr.openjdk.java.net/~mchung/jdk9/jep259/api/

Mandy
[1] 
http://mail.openjdk.java.net/pipermail/core-libs-dev/2015-November/036589.html

Just read the javadoc so-far...

There are several mistakes in getCallerClass() API Note (some probably a left-over from previous iterations of the API):

471 * <p> If this {@code getCallerClass} method is called by the entry point 472 * of a thread, the {@code Class} of the method invoked at thread's start
 473      * time will be returned.

Hm, I can't decipher that. What about something like:

If this {@code getCallerClass} method is called by the entry point of a thread - a method overriding {@link Thread#run} (that's the only possibility), the declaring class of the method overriding {@link Thread#run} will be returned.

Or, if you accept my latest suggestion:

If this {@code getCallerClass} method is called by the entry point of a thread - a method overriding {@link Thread#run},
{@link IllegalArgumentException} will be thrown.


 474      *
 475      * @apiNote
476 * For example, {@code ResourceBundleUtil::getBundle} loads a resource bundle 477 * on behalf of the caller. It calls this {@code getCallerClass} method 478 * to find the method calling {@code Util::getResourceBundle} and use the caller's 479 * class loader to load the resource bundle. The caller class in this example
 480      * is the {@code MyTool} class.
 481      *
 482      * <pre>{@code
 483      *     class ResourceBundleUtil {
484 * private final StackWalker walker = StackWalker.getInstance(Option.RETAIN_CLASS_REFERENCE);
 485      *         public ResourceBundle getBundle(String bundleName) {
 486      *             Class<?> caller = walker.getCallerClass();
487 * return ResourceBundle.getBundle(bundleName, caller.getClassLoader());
 488      *         }
 489      *     }
 490      *
 491      *     class MyTool {
 492      *         private void init() {
493 * ResourceBundle rb = Util.getResourceBundle("mybundle");
 494      *         }
 495      *     }
 496      * }</pre>

- threre's no ResourceBundle.getBundle(String, ClassLoader) method.
- Util -> ResourceBundleUtil (or ResourceBundleUtil -> Util)


 497      *
 498      * An equivalent way to find the caller class using the
 499      * {@link StackWalker#walk walk} method is as follows
500 * (filtering the reflection frames, {@code MethodHandle} and hidden frames
 501      * not shown below):
 502      * <pre>{@code
 503      *     Class<?> caller = walker.walk(s ->
 504      *         s.map(StackFrame::getDeclaringClass)
 505      *          .skip(2)
 506      *          .findFirst());
 507      * }</pre>

- Stream.findFirst() returns Optional<E>, not E.

 508      *
509 * When the {@code getCallerClass} method is invoked from thread {@code t}'s 510 * entry point, i.e. {@code PrimeRun::run}, it returns {@code PrimeRun} class 511 * that is the first stack frame below the stack frame for {@code getCallerClass}
 512      * instead.
 513      *
 514      * <pre>{@code
 515      *     class PrimeRun implements Runnable {
 516      *         public void run() {
517 * Class<?> c = StackWalker.getInstance(Option.RETAIN_CLASS_REFERENCE)
 518      *                                     .getCallerClass();
 519      *         }
 520      *     }
 521      *     Thread t = new Thread(new PrimeRun()).start();
 522      * }</pre>
 523      *
524 * Similarly, when the {@code getCallerClass} method is called from the 525 * {@code static public void main} method launched by the {@code java} launcher,
 526      * it returns the {@code Class} of the {@code main} method.
 527      *
528 * @return {@code Class} object of the caller's caller invoking this method; 529 * or the {@code Class} object of the method invoked by a thread at start time.

- In above example, t's entry point is Thread::run (not PrimeRun::run). Thread::run then delegates to PrimeRun::run:

public class Thread {
    ...
    public void run() {
        if (target != null) {
            target.run();
        }
    }


...so this example is not really suitable to describe the effect of invoking getCallerClass from thread's entry-point.

An example of that kind would be something like:

class PrimeThread extends Thread {
    @Override public void run() {
        Class<?> c = StackWalker.getInstance(Option.RETAIN_CLASS_REFERENCE)
                                    .getCallerClass();
    }
}

Thread t = new PrimeThread().start();


There are only three situations to consider:

- the method overriding Thread::run, called as thread's entry-point
- the static main method, called by java launcher
- any method called by JNI from newly attached thread

The last is special - It's not any method called by JNI. If Java calls a native method and that native method calls-back to Java via JNI, the method calling native method will be on the stack and getCallerClass() invoked from the called-back method will return it (this can be seen when observing reflection calls that go through sun.reflect.NativeMethodAccessorImpl).


Regards, Peter

Reply via email to