How to get the parameter names of an object’s constructors (reflection)? [duplicate]
This is already giving me a good summary of the constructor, for example a constructor public Test(String paramName) is shown as public Test(java.lang.String) Instead of giving me the class type however, I want to get the name of the parameter.. in this case «paramName». How would I do that? I tried the following without success:
if (constructors.length > 0) < for (int iCon = 0; iCon < constructors.length; iCon++) < Class[] params = constructors[iCon].getParameterTypes(); if (params.length >0) < for (int iPar = 0; iPar < params.length; iPar++) < Field fields[] = params[iPar].getDeclaredFields(); for (int iFields = 0; iFields < fields.length; iFields++) < String fieldName = fields[i].getName(); System.out.println(fieldName); >> > > >
Unfortunately, this is not giving me the expected result. Could anyone tell me how I should do this or what I am doing wrong? Thanks!
This is possible via reflection in Java 8, see this SO answer — found by reading the documentation on paranamer from Duncan McGregor’s answer below.
3 Answers 3
As mentioned in the comments on Roman’s answer, the parameter names can be retrieved if the compiler included debugging symbols, though not through the standard Java Reflection API. Below is an example illustrating how you could obtain parameter names via the debugging symbols using the ASM bytecode library:
/** * Returns a list containing one parameter name for each argument accepted * by the given constructor. If the class was compiled with debugging * symbols, the parameter names will match those provided in the Java source * code. Otherwise, a generic "arg" parameter name is generated ("arg0" for * the first argument, "arg1" for the second. ). * * This method relies on the constructor's class loader to locate the * bytecode resource that defined its class. * * @param constructor * @return * @throws IOException */ public static List getParameterNames(Constructor constructor) throws IOException < ClassdeclaringClass = constructor.getDeclaringClass(); ClassLoader declaringClassLoader = declaringClass.getClassLoader(); Type declaringType = Type.getType(declaringClass); String constructorDescriptor = Type.getConstructorDescriptor(constructor); String url = declaringType.getInternalName() + ".class"; InputStream classFileInputStream = declaringClassLoader.getResourceAsStream(url); if (classFileInputStream == null) < throw new IllegalArgumentException("The constructor's class loader cannot find the bytecode that defined the constructor's class (URL: " + url + ")"); >ClassNode classNode; try < classNode = new ClassNode(); ClassReader classReader = new ClassReader(classFileInputStream); classReader.accept(classNode, 0); >finally < classFileInputStream.close(); >@SuppressWarnings("unchecked") List methods = classNode.methods; for (MethodNode method : methods) < if (method.name.equals("") && method.desc.equals(constructorDescriptor)) < Type[] argumentTypes = Type.getArgumentTypes(method.desc); ListparameterNames = new ArrayList(argumentTypes.length); @SuppressWarnings("unchecked") List localVariables = method.localVariables; for (int i = 0; i < argumentTypes.length; i++) < // The first local variable actually represents the "this" object parameterNames.add(localVariables.get(i + 1).name); >return parameterNames; > > return null; >
This example uses the ASM library’s tree API. If speed and memory are precious, you can refactor the example to use its visitor API instead.
Get parameter names in a method using reflection
I am writing a small framework, that will get the classes loaded in the jvm and invoke its methods. Method arguments has been generated based on formal parameter names. I am trying to get its name by using reflection.
import java.lang.reflect.*; public class Test < public static void main(String[] args) < Method[] methods = Test.class.getMethods(); for(Method method : methods) < Type[] params = method.getGenericParameterTypes(); for(Type param : params) < System.out.println(param); >> > >
I know its possible in jdk8
http://docs.oracle.com/javase/8/docs/api/java/lang/reflect/Executable.html#getParameters— How to get this in jdk6 or 7?. Because, most of our servers are running with jdk6.
I don’t think this is possible with Java < 8 and even with 8 it's only possible if you'r using some special compiler arguments, AFAIK.
2 Answers 2
Use Paranamer. It was designed expressly for this purpose, back in the pre-Java-8 days when method parameter names were not available (synthesized or baked into the bytecode) via reflection.
Just Try this even it is little bit lengthy but very easy to understand and you get the parameters of a method names
import java.lang.reflect.*; import java.util.function.*; import static java.lang.System.out; public class MethodParameterSpy < private static final String fmt = "%24s: %s%n"; // for the morbidly curious void genericThrow() throws E <> public static void printClassConstructors(Class c) < Constructor[] allConstructors = c.getConstructors(); out.format(fmt, "Number of constructors", allConstructors.length); for (Constructor currentConstructor : allConstructors) < printConstructor(currentConstructor); >Constructor[] allDeclConst = c.getDeclaredConstructors(); out.format(fmt, "Number of declared constructors", allDeclConst.length); for (Constructor currentDeclConst : allDeclConst) < printConstructor(currentDeclConst); >> public static void printClassMethods(Class c) < Method[] allMethods = c.getDeclaredMethods(); out.format(fmt, "Number of methods", allMethods.length); for (Method m : allMethods) < printMethod(m); >> public static void printConstructor(Constructor c) < out.format("%s%n", c.toGenericString()); Parameter[] params = c.getParameters(); out.format(fmt, "Number of parameters", params.length); for (int i = 0; i < params.length; i++) < printParameter(params[i]); >> public static void printMethod(Method m) < out.format("%s%n", m.toGenericString()); out.format(fmt, "Return type", m.getReturnType()); out.format(fmt, "Generic return type", m.getGenericReturnType()); Parameter[] params = m.getParameters(); for (int i = 0; i < params.length; i++) < printParameter(params[i]); >> public static void printParameter(Parameter p) < out.format(fmt, "Parameter class", p.getType()); out.format(fmt, "Parameter name", p.getName()); out.format(fmt, "Modifiers", p.getModifiers()); out.format(fmt, "Is implicit?", p.isImplicit()); out.format(fmt, "Is name present?", p.isNamePresent()); out.format(fmt, "Is synthetic?", p.isSynthetic()); >public static void main(String. args) < try < printClassConstructors(Class.forName(args[0])); printClassMethods(Class.forName(args[0])); >catch (ClassNotFoundException x) < x.printStackTrace(); >> >
How to get Method Parameter names in Java 8 using reflection?
. If the parameter’s name is present, then this method returns the name provided by the class file. Otherwise, this method synthesizes a name of the form argN, where N is the index of the parameter in the descriptor of the method which declares the parameter.
Whether a JDK supports this, is implementation specific (as you can see form the above output, build 125 of JDK 8 does not support it). The class file format supports optional attributes which can be used by a specific JVM/javac implementation and which are ignored by other implementations which do not support it.
Note that you could even generate the above output with arg0 , arg1 , . with pre Java 8 JVMs — all you need to know is the parameter count which is accessible through Method.getParameterTypes() :
Class clz = String.class; for (Method m : clz.getDeclaredMethods()) < System.err.println(m.getName()); int paramCount = m.getParameterTypes().length; for (int i = 0; i < paramCount; i++) < System.err.println(" arg" + i); >>
What is new with JDK 8 is that there is an extended API and the possibility for JVMs to provide the real parameter names instead of arg0 , arg1 , .
Supporting such optional features is possible through optional attributes which can be attached to the various class file structures. See 4.6. Methods for the method_info structure within a class file. See also 4.7.1. Defining and Naming New Attributes in the JVM spec.
Since with JDK 8, the class file version will be incremented to 52, it would also be possible to change the file format itself to support this feature.
See also JEP 118: Access to Parameter Names at Runtime for more information and implementation alternatives. The proposed implementation model is to add an optional attribute which stores the parameter names. Since the class file format already supports these optional attributes, this would even be possible in a way so that the class files can still be used by older JVMs, where they are simply ignored as demanded by the spec:
Java Virtual Machine implementations are required to silently ignore attributes they do not recognize.
As suggested by @assylias, the source needs to be compiled with the javac command line option -parameters in order to add the meta data for parameter name reflection to the class file. However, this will of course only affect code compiled with this option — the code above will still print arg0 , arg1 etc. since the runtime libraries are not be compiled with this flag and hence do not contain the necessary entries in the class files.
How to get the parameters of a method using reflection
Say someone calls this method with inputs of foo(«hey», 5); How can I get the values «hey» and 5 using reflection? When I try to do it I just get a whole bunch of the String and Integer object variables.
@user743949 I think we need more information on what your trying to achieve exactly. What is reflecting what?
Where are you trying to do the reflecting? In foo ? I don’t think you can «intercept» a method call with reflection. You can inspect an object and discover its properties, methods, parameters, etc., but not grab a method call when somebody invokes foo .
3 Answers 3
It sounds like you are talking about AOP(aspect oriented programming) — not reflection. A method interceptor would give you access to the invocation at runtime (including access to the arguments). How you access the arguments depends on the API.
public class MyMethodInterceptor implements MethodInterceptor < public Object invoke(MethodInvocation invocation) throws Throwable < System.out.println("Before: invocation=[" + invocation + "]"); // use MethodInvocation.getArguments() to access the runtime parameters System.out.println(Arrays.toString(methodInvocation.getArguments())); Object rval = invocation.proceed(); System.out.println("Invocation returned"); return rval; >>
Note: AOP is an advanced technology and you would need to do some homework to use it effectively. See http://static.springsource.org/spring/docs/2.0.2/reference/aop-api.html for details on the example given above.
Reflection is about accessing the program at a «meta» level, so you can tinker with the details (objects, classes) of how it is put together. Accessing the actual values of variables and parameters is done at the usual «normal» level.
I’m not sure why you cannot access the parameters at the usual «normal, non-meta» level, maybe you are trying to see the parameters to a method up in the stack, or on another thread? For that, you’ll probably need using a debugging interface like JDI.
I think reflection is a misguided way to think about achieving what you want to do here.
Think of reflection as looking at a car and finding out that it has wheels, engine, seats etc and what type they are. Its not about finding out how these parts are working at a given moment. I know its not a very good analogy but I hope it helps. Reflection means you are looking at the car from outside and deciding what it looks like and what it can do. Finding out the values of the arguments is done from the «inside».
Basically if you have a java class, you can use reflection to know what methods, attributes it has and what are their types and invoke them too. But what you are looking to do here with reflection is like calling a method and magically finding out its arguments from «outside» the method.
You said «I am practicing, and I want to output everything to a display». why don’t you just log the arguments or print them to an output stream? Or as someone said, use a debugger.