17

I'm writing small and very DRY framework, which heavily relies on metadata. I'd like to know if there is a way to obtain method parameter names, i.e. given some method

public void a(int myIntParam, String theString) { ... }

get the strings "myIntParam" and "theString".

I know I could annotate parameters, but that wouldn't be nice...

public void a(
    @Param("myIntParam") int myIntParam,
    @Param("theString") String theString
) { ... }
ansgri
  • 2,126
  • 5
  • 25
  • 37

7 Answers7

16

Here is a dirty solution that needs some tweaking. Maybe someone can make it better.

Cons:

  • Requires that you know the location of compiled class file.
  • It has to be compiled with the -g flag.

Code:

import com.sun.org.apache.bcel.internal.classfile.ClassParser;
import com.sun.org.apache.bcel.internal.classfile.JavaClass;
import com.sun.org.apache.bcel.internal.classfile.LocalVariable;
import com.sun.org.apache.bcel.internal.classfile.Method;
import java.io.IOException;

public class Main {

  public static void main(String[] args) throws IOException {
      ClassParser parser = new ClassParser("Main.class");
      JavaClass clazz = parser.parse();

      for (Method m : clazz.getMethods()) {
          System.out.println("Method: " + m.getName());
          int size = m.getArgumentTypes().length;
          if (!m.isStatic()) {
            size++;
          }

          for (int i = 0; i < size; i++) {
              LocalVariable variable = m.getLocalVariableTable().getLocalVariable(i);
              System.out.println("  - Param: " + variable.getName());
          }
      }
  }

  public void a(int myIntParam, String theString) {
  }
}

Output:

$ javac -g Main.java
$ java Main
Method: <init>
- Param: this
Method: main
- Param: args
Method: a
- Param: this
- Param: myIntParam
- Param: theString

Jonny Heggheim
  • 1,423
  • 1
  • 12
  • 19
9

I could be wrong about this... but I don't think parameter names appear in a class file so I would guess that there is no way to get them via reflection.

bobwienholt
  • 17,420
  • 3
  • 40
  • 48
4

We created a custom annotation for the method that holds a String[] of parameter names. This approach felt a little easier to manage than having to annotate each individual parameter. We plan to add build-time checking that the number of annotated parameter names matches the number of arguments, since that it what we require.

dstine
  • 281
  • 1
  • 6
  • Very good idea! I'll definitely convert all those @Param to single @Params. – ansgri Mar 31 '09 at 18:50
  • Actually I prefer to annotate them individually, because this makes the annotation optional. I use these annotations to create a webpage to call methods using reflection. If I forget to annotate a parameter then the code just falls back and visualizes it as "paramX" to the end-user. On the other hand if you put all names inside one annotation, then there's no decent fallback. – bvdb May 28 '15 at 09:15
3

If you are using Spring you are in luck. Just add this to your applicationContext.xml:

<bean class="org.springframework.core.LocalVariableTableParameterNameDiscoverer"/>

Then you can inject this bean where it is needed:

@Autowired
private ParameterNameDiscoverer parameterNameDiscoverer;

Method m = ...
String[] names = parameterNameDiscoverer.getParameterNames(m);

As its name suggests, this implementation relies on classes being compiled with debug info.

David Tinker
  • 9,383
  • 9
  • 66
  • 98
3

The name of the parameters are present in the class file, when the java code was compiled with debugging information (via the -g option). The class file then contains a LocalVariableTable attribute (see http://java.sun.com/docs/books/jvms/second_edition/html/ClassFile.doc.html#5956). This contains the names of local variables and parameters are just local variables. The parameters correspond to the variable slots starting at index 1 (or index 0 for static methods).

ralfs
  • 1,984
  • 1
  • 11
  • 5
2

@bobwienholt is correct - parameter names are not compiled into java classes, and so aren't available at runtime.

Dan Vinton
  • 26,401
  • 9
  • 37
  • 79
0

Parameter names are available through apt (now part of javac).

Tom Hawtin - tackline
  • 145,806
  • 30
  • 211
  • 305
  • @Tom: do you still need to explicitly annotate classes to get apt to preprocess them? Or is a more general-purpose precompiler now? – Dan Vinton Dec 21 '08 at 16:52
  • I believe annotation processors can ask to receive all classes whether they have annotations or not. It's not really a preprocessor as the original classes are left alone, although other classes and artifacts can be created. – Tom Hawtin - tackline Dec 22 '08 at 00:47