-1

Is there any way via Reflection or some other tool to introspect the fields within a method in Java?

So, for example:

public void someMethod() {
  int one = 1;
  int two = 2;
}

And introspecting to find the fields "one" and "two" of type int within the method "someMethod"? To my knowledge it's not possible in Reflection, but I'm hoping ASM or some other bytecode instrospecting tool is capable.

darkfrog
  • 1,053
  • 8
  • 29
  • This has been asked before, e.g. http://stackoverflow.com/questions/6816951/can-i-get-information-about-the-local-variables-using-java-reflection and http://stackoverflow.com/questions/11287933/getting-name-and-type-of-local-variables-from-a-java-program – jaco0646 Dec 05 '13 at 02:23
  • 1
    Those are local variables, not fields. – Antimony Dec 05 '13 at 02:31
  • Though the question may have been asked before, among all of those responses there isn't a single example of how to access the "local variables" even with a tool like ASM. – darkfrog Dec 05 '13 at 12:28
  • @darkfrog: stackoverflow is not to spoon-feed you. The mentioned questions have answers that tell you how. *Try it* and ask if you have a specific question. – Holger Dec 05 '13 at 15:16
  • @Holger, not looking for spoon-feeding, but like I stated already, not a single response actually gives in the answers how to accomplish this in any library. They simply vaguely allude to possibly doing it in ASM. I've dug through ASM and have yet to find anything on how to accomplish this. – darkfrog Dec 05 '13 at 18:58
  • Sorry if I sounded too harsh. But the answers already gave the hint that it is not possible regarding normal byte code but the only way is to evaluate debugging information, if present. For any byte code manipulation topic you should know [this document](http://docs.oracle.com/javase/specs/jvms/se7/html/index.html) and [there you go](http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.7.13). – Holger Dec 06 '13 at 08:49

1 Answers1

0

Fields differ from method local variables in different ways:

  • First of all, variables inside methods will not have names when represented in byte code.
  • Second, the compiler is allowed to optimize away such variables. There is no contract saying that these method local variables must be kept by the compiler. At the same time, the compiler can add as many local variables at it wants.

And there is another catch: in byte code, local variables are not specified with an explicit declaration in a similar way they are declared in Java source code. Instead, method local variables are only visible as a part of a method specific array of variables that contains all of the following variables in this order:

  • A reference to the object on which the method is called on (as long as the method is not static, then this reference is not included), this is the this reference.
  • A reference to all arguments of this method in the order as they are defined in the source code.
  • A reference to all local variables that are created in the method:

An method like m in this example:

class A {
  void m(Object arg) {
    Object o = "test";
  }
}

would therefore appear in the byte code as the following local variable array:

[Object (this), Object (arg), Object (o)]

With this knowledge, you can for example parse a class's method by using ASM and its MethodVisitor. Doing so, you could deduct:

  1. The local variable array has a size of three, hypothetically, you could have three local variables
  2. You would find out that the method is not static, therefore you can cross out the first variable and you are left with the possibility of two local variables.
  3. The method has one argument which is of type reference, you can therefore cross out another variable which leaves you with probably one local variable declaration.

Now you have to parse the method's byte code and you could find out that there is a reference of type String pushed into the third array spot. This would leave you with the finding that you declared some local variable of type String or one of its super types such as Object.

However, you can still not be sure if this local variable was added synthetically. for the reasons named above. There is not more to find out for you. (Watch out for long or double variables which take variable spots of the size of 2.)

Rafael Winterhalter
  • 42,759
  • 13
  • 108
  • 192
  • It’s worth noting that variables having disjunct scopes may share the same slot on byte code level. And a practical example for synthetic variables: the for-each loop generates such variables. – Holger Dec 05 '13 at 15:33
  • That is true, however only if they are of the same type. You could not reuse the spot of two `Object`s to store a `long` in another scope. – Rafael Winterhalter Dec 05 '13 at 15:35
  • Sorry, but you are wrong, you can reuse any variable slots, I just tried it and it works. I didn’t even hack byte code, I just compiled `{ Object o1="o1", o2="o2"; } { long l1=0L; }` using eclipse and it creates just two local vars, reusing the two slots for the `long` – Holger Dec 05 '13 at 15:48
  • Indeed, I did not know that. Might be that you cannot load two integers as a long and I am mixing that up now. I remember running into a problem like that before, but obviously, I do not remember it correctly. – Rafael Winterhalter Dec 05 '13 at 15:57
  • 1
    That’s right, you must never try to read a different type than you have stored before regarding reference type, int, float, and long/double halfs. And you are not allowed to branch in a way that could lead to such an attempt. – Holger Dec 05 '13 at 16:23
  • raphw, thanks for your response, that clarifies the situation much better. – darkfrog Dec 05 '13 at 19:01