Proposed API for JEP 259: Stack-Walking API
Timo Kinnunen
timo.kinnunen at gmail.com
Sun Nov 15 21:37:22 UTC 2015
I hope StackWalker::getCaller would return at least as much information as invoking the MBean operation { “threadPrint”, “–l” } from com.sun.management.DiagnosticCommand directly would get, without the overheads of a full thread dump. I also noticed that many users of the original getCallerClass() are not really interested in the caller’s Class per se, rather they are interested in the caller’s ClassLoader. StackWalker::getCaller could then also include this information and other details about the calling context in effect at the time it is called.
Sent from Mail for Windows 10
From: Peter Levart
Sent: Sunday, November 15, 2015 20:15
To: Timo Kinnunen;David M. Lloyd;core-libs-dev at openjdk.java.net
Subject: Re: Proposed API for JEP 259: Stack-Walking API
On 11/15/2015 05:53 PM, Timo Kinnunen wrote:
To be pedantic, there is always a caller, but not every caller is associated with a Java Class.
StackWalker::getCallerClass can be thought as a convenience method for something like:
Class<?> callingMe = StackWalker.getCaller().getAsJavaClass();
>From this view-point we can determine that
• getCaller() will never return null as there is always a caller.
• getAsJavaClass() cannot always return a Class instance as the caller might be the OS itself or a native code frame.
• getCaller() will not return the current frame as the caller of the current frame because that’s nonsensical!
• Also, getAsJavaClass() will not return a Java Class from some other caller as that would violate its API contract.
• getAsJavaClass() will not return the current frame’s Class as the caller’s Class unless such a recursive call is actually in progress!
We can guess that the client using these methods should have some idea if it’s expected its caller is a Java Class or not. We also know the association between a caller and a Java Class (if any) won’t change unexpectedly or otherwise have some uncertainty. Together these give the following API for getCaller() and getAsJavaClass():
getCaller() always succeeds and returns non-null. The result is not guaranteed to contain information useful to clients. It returns the same caller regardless of who the callers of the caller are.
getAsJavaClass() doesn’t always succeed, and when it does is dependent on local information only. When it doesn’t, it throws an exception to signal that the association to a Class that the client expected to find doesn’t exists. The exception is not a checked exception because the association between a caller and a Class is not inherently unreliable.
The same reasoning applies to StackWalker::getCallerClass and further suggests StackWalker::getCaller should be available for clients as well.
But what would StackWalker::getCaller actually return? If it is an object that contains just getAsJavaClas() method, then it is a useless indirection (similar to Optional<Class<?>>).
Since the situation that a "caller-sensitive" method is not called by a Java method is really just a theoretical issue and even then it is an abuse made by the caller of a caller-sensitive method, I would just make getCallerClass() throw an exception in such situations.
Regards, Peter
Sent from Mail for Windows 10
From: David M. Lloyd
Sent: Saturday, November 14, 2015 16:02
To: core-libs-dev at openjdk.java.net
Subject: Re: Proposed API for JEP 259: Stack-Walking API
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.
More information about the core-libs-dev
mailing list