Is it possible to get a reference to caller object (and recursively
all the way up the call stack)? I know about Thread.dumpStack() that
calls new Exception() internally and about sun.reflect.Reflection
class, but you can only get information about classes, method names
and lines - not reference to live objects that in turn can be
inspected using reflection for all field values etc. I know in general
it is probably possible, because this is what debuggers do when
showing stack frame.
What would it take to get this information? It does not have to be
100% compatible with all versions of JDK. Anything in reflection
internal packages? Or maybe there's a library that already does it? To
what degree it is possible without (a) running the whole jvm in
special mode - like debug mode and (b) without processing the whole
program in AspectJ or Hibernate bytecode postprocessors style, and of
course (c) without rewriting the source to pass around "this"
everywhere?
Cheers,
Piotr
Maybe. What do you mean by "caller object?" For example, in
public class Piotr {
public static void main(String[] unused) {
System.out.println(hello());
}
private static String hello() {
// What is the "caller object" here?
return "Bonjour";
}
}
> [...] I know in general
> it is probably possible, because this is what debuggers do when
> showing stack frame.
The debuggers I have used will show the method associated with
each stack frame, and the class the method belongs to, and the source
code's line number (if it's available). I have not seen a debugger
that shows anything I would term a "caller object," so again: What
do you mean? More to the point, what problem are you trying to solve?
--
Eric Sosman
eso...@ieee-dot-org.invalid
I don't think you can.
> What would it take to get this information? It does not have to be
> 100% compatible with all versions of JDK. Anything in reflection
> internal packages? Or maybe there's a library that already does it? To
> what degree it is possible without (a) running the whole jvm in
> special mode - like debug mode and (b) without processing the whole
> program in AspectJ or Hibernate bytecode postprocessors style, and of
> course (c) without rewriting the source to pass around "this"
> everywhere?
I think you need to redesign so that you don't need this feature.
Arne
"Eric Sosman" <eso...@ieee-dot-org.invalid> wrote in message
news:icp7kf$ri3$1...@news.eternal-september.org...
> On 11/26/2010 3:38 PM, puchacz wrote:
>> Hi,
>>
>> Is it possible to get a reference to caller object (and recursively
>> all the way up the call stack)? [...]
>
> Maybe. What do you mean by "caller object?" For example, in
>
> public class Piotr {
> public static void main(String[] unused) {
> System.out.println(hello());
> }
> private static String hello() {
> // What is the "caller object" here?
> return "Bonjour";
> }
> }
>
>> [...] I know in general
>> it is probably possible, because this is what debuggers do when
>> showing stack frame.
>
> The debuggers I have used will show the method associated with
> each stack frame, and the class the method belongs to, and the source
> code's line number (if it's available).
And the local variables for each frame, including "this" (if the frame has a
this.) I think the last of these is what's being asked for.
Stefan Ram wrote:
> The closest approximation to an answer to the above
> question might be »Piotr.class«.
>
> (But I do not know whether such an object is instanciated
> when the class »Piotr« is initialized or only when such
> an object is first needed.)
The class object comes into existence when the class is loaded, but not all
class initialization happens then. The 'class' attribute is an attribute of
the class object, not the class object itself. The VM loader loads and
initializes the class 'Piotr' and calls its 'main()', and thus 'Piotr',
running 'main()', is the caller of 'hello()'.
The class is loaded upon first reference to it or its members, but not
necessarily initialized right then. For example, a reference to 'Piotr.class'
will load 'Piotr' if it wasn't already, but not initialize it.
The invocation of 'main()' will cause class initialization, so that will have
happened before the call to 'hello()'.
--
Lew
Hi guys,
Thanks, but this is not what I want; I would like something like the
program below. Basically references to live objects, not class
definition objects. It is for easier troubleshooting of an existing
large production system, if something sets up a bad status, I would
like to know what caused it, we have a lot of information in JMX
already to click through, but not real stacks - and you cannot really
debug a live production system.
By debugger I mean debugger, like Eclipse debugger - you can see all
stack frames, local variables in them, and "this" local to each stack
frame, so you see values of fields in each object in stack frames,
from your breakpoint location all the way up to top level Thread.run()
or similar.
Cheers,
Piotr
class A {
int i, j;
void a() {
i = 1;
j = 2;
aa();
}
void aa() {
B b = new B();
b.b(this);
}
}
class B {
void b(Object o) {
// assuming Magic.getStackFrame(thread, nextFrame - null means we are
asking for the last frame in stack)
// getting first from stack frame
Frame frame1 = Magic.getStackFrame(Thread.currentThread(), null);
// THIS IS WHAT I WANT TO RETRIEVE, FROM HERE
assert(frame1.objectRef == o);
assert(A.class.getDeclaredField("i").get(frame1.objectRef) == 1);
assert(A.class.getDeclaredField("j").get(frame1.objectRef) == 2);
// TO HERE
// we were called from no arg method - this is retrieveable from
// Thread.dumpStack() actually
assert(frame1.method.equals(A.class.getMethod("aa", new Class[]
{Object.class})));
Frame frame2 = Magic.getStackFrame(Thread.currentThread(), frame1);
assert(frame2.objectRef == frame1.objectRef); // the same object,
also not retrievable using what I know
assert(frame2.objectRef == o);
assert(frame1.method.equals(A.class.getMethod("a", new Class[]{})));
Frame frame3 = Magic.getStackFrame(Thread.currentThread(), frame2);
assert(frame3.objectRef == null); // this method was called from
static method
assert(frame3.method.equals(C.getMethod("main"), new Class[]
{String[].class}));
Frame frame4 = Magic.getStackFrame(Thread.currentThread(), frame3);
assert(frame4 == null); // it was top level frame
// etc.
}
}
class C {
public static void main(String s[]) {
new A().a();
}
}
I don't think you'll get what you want, short of running the
code under a debugger. Perhaps the java.lang.instrument package
would help -- but using those facilities seems pretty close to (and
as intrusive as) using a debugger to begin with.
--
Eric Sosman
eso...@ieee-dot-org.invalid
>Is it possible to get a reference to caller object (and recursively
>all the way up the call stack)?
yes. You can all sorts of information.
See http://mindprod.com/jgloss/trace.html
for sample code.
--
Roedy Green Canadian Mind Products
http://mindprod.com
If you give your kitchen floor a quick steam mop every few days, you will find you never have to get out buckets and brushes for deep cleaning. Similary, if you keep your code tidy, refactoring as you go, you probably won't need major rewrites.
Two quick questions:
1) what is an object?
2) what of the code below
Throwable t = new Throwable();
StackTraceElement[] es = t.getStackTrace();
for ( int i=0; i<es.length; i++ )
{
StackTraceElement e = es[i];
System.out.println( " in class:" + e.getClassName()
+ " in source file:" + e.getFileName()
+ " in method:" + e.getMethodName()
+ " at line:" + e.getLineNumber()
+ " " + ( e.isNativeMethod() ? "native" : "" ) );
}
finds "caller object"?
Arne