• Post Reply Bookmark Topic Watch Topic
  • New Topic

Getting the current Class name and Method name  RSS feed

 
Joseph Sweet
Ranch Hand
Posts: 327
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Friends,

I am wondering if there is a reliable way to get the current Class name and Method name.

I have seen this piece of code in an article about Annotations:



But then, in the Sun's Logger API documentation I have encountered the following comment:



For the methods that do not take an explicit source name and method name, the Logging framework will make a "best effort" to determine which class and method called into the logging method. However, it is important to realize that this automatically inferred information may only be approximate (or may even be quite wrong!). Virtual machines are allowed to do extensive optimizations when JITing and may entirely remove stack frames, making it impossible to reliably locate the calling class and method.



Hmmmm.... this means that the code above is actually not too reliable. Since the Annotation they implement in that article has to do with authorization, it can put me into a serious problem.

Any ideas?
 
Joseph Sweet
Ranch Hand
Posts: 327
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Managers: Can this post be moved to the advanced forum please?
[ September 30, 2007: Message edited by: Joseph Sweet ]
 
Jim Yingst
Wanderer
Sheriff
Posts: 18671
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hm, I didn't see this earlier. We so rarely get good Advanced posts; I guess this will have to do.

The SecurityBlanket.checkAccess() code in the article is a bit strange. The loop you show is shecking the stack trace to find where the class name "SecurityBlanket" and method name "checkAccess" can be found. Well, considering this code is in the class SecurityBlanket, in method checkAccess(), one would expect that they should be in position 0. The loop seems silly - if they're not in position 0, then you might as well throw an exception right away - the stack trace can't be trusted.

Which brings us you your main question: yes, it's possible that getStackTrace() will omit or reorder some frames of the stack. This is documented in the API for getStackTrace(). I don't really know a better way to achieve the desired effect here using standard APIs - maybe someone else will. Usually it's frowned on to try to base a method's behavior on the calling class and method; I'm not clear why it should be necessary here.

One possibility though is to use some form of bytecode engineering to modify each call to checkAccess() to include the names of the class and method that called it. For example AspectJ could probably do this at compile time using a join point around calls to checkAccess(). JoinPoint has a method getSourceLocation() that should give you all the info you need here. If you're not already familiar with AspectJ (or some other form of bytecode engineering) then this may well seem a very heavyweight solution to you. But it's the only one that comes to my mind, so far.
 
Wb Moore
Greenhorn
Posts: 11
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Originally posted by Joseph Sweet:
Hi Friends,

I am wondering if there is a reliable way to get the current Class name and Method name.


The only time I want the current class name and method name is when I want to include it in a log.
This is what I have done (its not original, nor is it cheap, because of the Exception):

Then I can use something like:


hope that helps.
[ October 04, 2007: Message edited by: Walter Moore ]
 
Jim Yingst
Wanderer
Sheriff
Posts: 18671
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Right, that was the preferred solution under JDK 1.4, since Throwable had getStacktrace() but Thread did not. Prior to 1.4, you had to do something like this:

And then write code to parse the stack trace to extract the method name. Yuck. Anyway though, these solutions all have the same problem. The documentation for getStackTrace() in Throwable says basically the same thing that it did for getStackTrace() in Thread: "Some virtual machines may, under some circumstances, omit one or more stack frames from the stack trace." They don't say that for printStackTrace(), but it's true there too - plus the format of printStackTrace() is not guaranteed, so it's hard to write a parser that can extract info from it reliably on all JVMs. Ultimately, on a modern JDK, Thread.currentTread().getStackTrace() is the best way to get this info at runtime, but it's still not guaranteed to be accurate.
 
Pat Farrell
Rancher
Posts: 4686
7
Linux Mac OS X VI Editor
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Man, those are really yucky hacks.

And so slow you don't dare do them unless you are trying to log a Level.SEVERE problem.

The object's getClass().getName() is reliable and cheap.

I tend to just use a unique string vaguely from the method's name in the error message, something like:

 
Jim Yingst
Wanderer
Sheriff
Posts: 18671
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
[Pat]: And so slow you don't dare do them unless you are trying to log a Level.SEVERE problem.

I disagree - if the logger is configured to log Level.DEBUG or lower, then I figure speed is not paramount; information is. Log4J has built-in facilities to gather class name and line number - they're part of the PatternLayout format. The key is that it's built into the logging in such a way that the stack trace info is only generated if (a) an event is actually being logged, and (b) the PatternLayout conversion pattern includes the C or L specifiers. So when you run at Level.INFO and use a pattern with no C or L, it costs nothing. If you run at Level.DEBUG and use a pattern with C and/or L, the info is included, and maybe that makes things slow - but that is what you asked for, right? Setting a logger at Level.DEBUG implies you want more info and are willing to sacrifice some speed to get it - adding the class/line info supplements that nicely.

Actually I've had several projects where I just included the C and L almost all the time, even running at Level.INFO or higher, and they never showed up as a performance problem. Because as usual for performance problems, most of the time there's a bottleneck somewhere else that's bigger than the one you're thinking about. So it's useful to remember that including the C and L specifiers could create a problem, and test it periodically to see if it is creating a problem. But unless/until it really is creating a problem, I find it can be very useful to have the info.
[ October 04, 2007: Message edited by: Jim Yingst ]
 
With a little knowledge, a cast iron skillet is non-stick and lasts a lifetime.
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!