Reputation: 6023
I have this code:
package teste;
public class Teste {
public static void main(String[] args) {
String arroz = "abc";
Integer banana = 123;
vaiBuscar();
}
private static void vaiBuscar() {
Object[] obj = theMagicMethod();
System.out.println(((String) obj[0]));
System.out.println(((Integer) obj[1]));
}
}
And the output should be:
abc
123
Now the funny part is that the only method I can define is theMagicMethod(). So I need to go fetch all variables values that are defined in upper methods that invoked me. If there's a way to do this, probably it is through reflection.
Summing it up: If you could not edit any part of the code besides defining the method theMagicMethod(), how should this method be so that the output of this program is the one I wrote above?
Thanks!
Edit: This doesn't really need reflection to be solved. Any way will fit, it just needs to work.
Upvotes: 2
Views: 529
Reputation: 3160
Most likely it's a bad idea to use something like this in production code.
That said, I have to admit I've been looking for a way to inspect the variables on the stack trace, too :). It may be a stupid idea, but it's also an interesting one.
It can't be completely impossible. True, the byte code seems to be compiled in a way making it impossible, but every debugger manages to do it. But it's definitely impossible via reflection, and it's also impossible to access variables of the caller method without dirty hacks. If it was possible, you could escape the scope of the variables, and you'd ruin the garbage collector's day.
In any case, the variable names get lost (that's why the debugger of Eclipse often simply displays parameters as "arg1", "arg2" etc.).
You could try to write a java agent and use the instrumentation API. To get started, you may have a look at this article: http://blog.javabenchmark.org/2013/05/java-instrumentation-tutorial.html. Julien Poaletti didn't try to read variables, but I guess you could build on his example.
But again, using a custom agent is nothing a operations department should ever allow. Use at own risk!
Upvotes: 3
Reputation: 70909
Within the methods, the variable names are lost.
Java is a stack based machine, and so a method that looks like
public int add(int first, int second) {
int sum = first + second;
return sum;
}
is going to lose the naming of sum in bytecode that roughly reads as
pushInt firstParameter
pushInt secondParameter
addInt
returnInt
Note that the intermediate variable name sum
is completely destroyed in the compiling process, so there is no means to retrieve it from the run time.
However, there are many other items which must be referred to by name, so their names are not destroyed at runtime. Some of these include
names of classes
names of members
names of methods
names of enums
names of interfaces
So it is possible to get a subset of all the used names in a .java
file; but, such a subset is not going to include the internal names of any block of code.
Now, if you compile with some debugging options set (like -g
), you can improve upon the number of names accessible; however, there is no guarantee that any class you read in was compiled with debugging flags set (in fact, most classes are not compile with debugging flags set to improve loading performance).
If you can't do it for any class, you can't do it for a JVM.
Now, if you wanted to try your hand at getting all of the information that's not destroyed in the JVM, you could play around with JDWP (the debugging wire protocol) and take a peek at what is exposed; however, I would doubt it would be able to reach "everything", as it would only be able to read "everything loaded by the class loader" and (keeping in mind the above statements) only what survived compilation at that.
Upvotes: 3
Reputation: 279880
This is impossible to do. Reflection doesn't let you look at the inner implementation of methods.
There is no way in Java to look at the stack and extract variables or any values declared in stacked method stack frames.
Upvotes: 1