Question

I have a CtMethod instance, but I don't know how to get names of parameters (not types) from it. I tried getParameterTypes, but it seems it returns only types.

I'm assuming it's possible, because libraries I'm using don't have sources, just class files and I can see names of method parameters in IDE.

Was it helpful?

Solution

It is indeed possible to retrieve arguments' names, but only if the code has been compiled with debug symbols otherwise you won't be able to do it.

To retrieve this information you have to access the method's local variable table. For further information about this data structure I suggest you to check section 4.7.13. The LocalVariableTable Attribute of the jvm spec. As I usually say, JVM spec may look bulky but it's an invaluable friend when you're working at this level!

Accessing the local variable table attribute of your ctmethod

  CtMethod method = .....;
  MethodInfo methodInfo = method.getMethodInfo();
  LocalVariableAttribute table = methodInfo.getCodeAttribute().getAttribute(javassist.bytecode.LocalVariableAttribute.tag);

You now have the the local variable attribute selected in table variable.

Detecting the number of localVariables

   int numberOfLocalVariables = table.tableLenght(); 

Now keep in mind two things regarding the number in numberOfLocalVariables:

  • 1st: local variables defined inside your method's body will also be accounted in tableLength();
  • 2nd: if you're in a non static method so will be this variable.

The order of your local variable table will be something like:

|this (if non static) | arg1 | arg2 | ... | argN | var1 | ... | varN|

Retriving the argument name

Now if you want to retrieve, for example, the arg2's name from the previous example, it's the 3rd position in the array. Hence you do the following:

 // remember it's an array so it starts in 0, meaning if you want position 3 => use index 2
 int frameWithNameAtConstantPool = table.nameIndex(2); 
 String variableName = methodInfo.getConstPool().getUtf8Info(frameAtConstantPool)

You now have your variable's name in variableName.

Side Note: I've taken you through the scenic route so you could learn a bit more about Java (and javassists) internals. But there are already tools that do this kind of operations for you, I can remember at least one by name called paranamer. You might want to give a look at that too.

Hope it helped!

OTHER TIPS

If you don't actually want the names of the parameters, but just want to be able to access them, you can use "$1, $2, ..." as seen in this tutorial.

It works with Javaassist 3.18.2 (and later, at least up to 3.19 anyway) if you cast, like so:

LocalVariableAttribute nameTable = (LocalVariableAttribute)methodInfo.getCodeAttribute().getAttribute(LocalVariableAttribute.tag);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top