views:

79

answers:

3

Hello everybody. Is it possible to get information about class that invoking the other one?


class Bar{
    public Bar{}

    public String getInvokingClassInfo(){
        return "...";
    }
}

class Foo{
    public Foo(){
       Bar bar = new Bar();
       System.out.println("Invoking class is: "+bar.getInvokingClassInfo());
    }
}

How to get in the place:


System.out.println(bar.getInvokingClassInfo());

info about class that invoking (Foo) this one (Bar):

Invoking class: Foo
+7  A: 
 StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
 String callerClassName = stackTrace[index].getClassName();

This is getting the stacktrace for the current thread. As noted in the comments, there are implementation differences, so if you fear such, you can implement something like this:

  • loop through the StackTraceElement array (using a counter variable declared outside the loop)
  • whenever you encounter the current class name and the current method, break
  • get the next element of the array - it will be the invoker. (that's what index stands for in the above code)
  • if the above doesn't provide relevant information you can always fall back to new Exception().getStackTrace()
Bozho
That's not correct. The first element(s) of the array is the getStackTrace method and potentially other methods invoked internally by getStackTrace(). Different versions of Sun's VM show different behaviour here. In 1.5.0_15, the first two elements are `Thread.dumpThreads` and `Thread.getStackTrace` while in 1.5.0_18, the first element is `Thread.getStackTrace`.
jarnbjo
It's working for my purpose perfectly:<pre><code> public String getInvokingClassInfo(){ StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); return stackTrace[stackTrace.length-2].getClassName(); }</code></pre>I know it's a little bit nesty but for debugging stuff it's ok.
kospiotr
yes, updated. This results in just incrementing the index.
Bozho
Once again: The number of elements in the array before you get to the class invoking getStackTrace() is implementation specific. Using a fixed index (1 or 2) will _not_ be a portable solution.
jarnbjo
The Javadoc on `getStackTrace()` says that even an empty array may be returned. I.e. i don't know a better way to do it, but the stack trace needs more interpretation than `stackTrace[2]`
Stroboskop
@jarnbjo @Stroboskop - update with a more portable variant.
Bozho
@stroboskop: The array can only be empty if the thread you are invoking getStackTrace on is not yet started or already terminated. That is not possible for the current thread.
jarnbjo
There is no _guarantee_ that this stack trace will always be correct. If I recall correctly.
Thorbjørn Ravn Andersen
+3  A: 

The best (though contorted and ugly) solution I could think of would be to throw an exception inside Bar and catch it right away, then extract the caller info from its stack trace.

Update based on others' comments: you don't even need to throw and catch the exception, new Exception().getStackTrace() will do the trick.

Péter Török
not _that_ ugly actually - it is part (though not in the common case) of the implementation of Thread.getStackTrace()
Bozho
It's I think more proper way than the previous but imagine that many classess extend the class Bar and the extended class occurs in many places so... many try/catch clausures, many lines of new code. We could concider proxies but is it worth?
kospiotr
@kospiotr If you mean to get caller info in lots of different methods in `Bar` and its subclasses too, you can achieve that by implementing this solution in a single protected method of `Bar`, then calling it from all the other methods. Of course, then the stack trace analyser should start searching from the 3rd item in the array, not the 2nd (if there are enough elements, of course).
Péter Török
You don't actually have to throw the exception to get a stack trace. `new Exception().getStackTrace()` will do and also solve the problem with finding the correct offset in the array, which you'd have with Bozho's solution.
jarnbjo
@jarnbjo Thanks, I updated the post.
Péter Török
+2  A: 

The most robust way I can imagine is to pass "this" as an argument to B from inside A. Then B can have a look at the object, and print out its class.

Everything that fiddles with stack traces relies on things which are not guaranteed to work. The "pass-this" approach will.

Thorbjørn Ravn Andersen