> On Nov 14, 2015, at 7:01 AM, David M. Lloyd <david.ll...@redhat.com> wrote:
> 
> On 11/13/2015 06:07 PM, Brian Goetz wrote:
>>> I considered Optional<Class<?>>. I believe it is rare to have a JNI
>>> attached thread calling StackWalker::getCallerClass from native.  Most
>>> common cases will find a caller class.   Returning an Optional will
>>> force most common uses to handle the case if it’s absent.  It’s a
>>> tradeoff that I think it’s better to return Thread.class for the JNI
>>> attached thread calling getCallerClass in native which would rarely
>>> happen.
>> 
>> +1 on returning Thread.class in these cases.  Its a pragmatic compromise.
> 
> If you must return something non-null, maybe it'd be better to define a class 
> just for that purpose, e.g.:
> 
> public final class StackWalker {
> 
>    ...
> 
>    public static final class NoCaller {
>        private NoCaller() {}
>    }
> }
> 
> ...and use NoCaller.class as your caller when there is none.  Bonus points if 
> you can attach a protection domain with no permissions to that class.

I have been thinking what the users would do when there is no caller.

The JDK use  of getCallerClass are to:
1. find the caller's class loader for class loader hierarchy check
2. find the caller’s class loader to load something on behalf of the caller 
(visibility)
3. looking forward to work with modules, one would want to get the caller’s 
module
- to load something on behalf of the caller's module
- to add read edge to the caller’s module before accessing its type

Frameworks would likely do something similar to #2 and #3.  #1 is probably 
specific to the reflection API and how the security check is defined.

I started to think returning Thread.class isn’t the right answer as it gives an 
elevated privileged context.    Returning null or Optional.empty() would have 
the users to special case it to handle this rare case while it’s not as helpful 
as I’d like it to be.   NoCaller.class would be in a similar situation that the 
users must handle this rare case (ignoring user error).

Thread t1 = new Thread(new Runnable() {
    public void run() {
        walker.getCallerClass();
    }
});

Runnable::run or the entry point of a thread started/attached invoked is the 
first java method a thread would call and it’s the proper context for 
caller-sensitive API to look at.  

If StackWalker::getCallerClass is called from the first java method a thread 
invoked (i.e. Runnable::run, static void main, etc), it’s reasonable for 
getCallerClass to return that.  In the above example, it will return the 
anonymous class implementing Runnable.

If a caller-sensitive API (M calls getCallerClass) wants to differentiate the 
bottom frame on the stack vs the caller class calling M, it should call 
StackWalker::walk instead.

I’m inclined to have getCallerClass to return a non-null Class<?> and if the 
method calling getCallerClass method is the last frame on the stack, it will 
return that method instead.

Mandy

Reply via email to