Say I somehow got an object reference from an other class:
Object myObj = anObject;
Now I can get the class of this object:
Class objClass = myObj.getClass();
Now, I can get all constructors of this class:
Constructor[] constructors = objClass.getConstructors();
Now, I can loop every constructor:
if (constructors.length > 0)
{
for (int i = 0; i < constructors.length; i++)
{
System.out.println(constructors[i]);
}
}
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!
You can obtain the names of the formal parameters of any method or constructor with the method java. lang. reflect.
reflect package is used to fetch the parameter types using method parameter reflection. Reflection is a process of analyzing and modifying all capabilities of class at runtime.
A parameterized constructor accepts parameters with which you can initialize the instance variables. Using parameterized constructor, you can initialize the class variables dynamically at the time of instantiating the class with distinct values.
Parameterized Constructor – A constructor is called Parameterized Constructor when it accepts a specific number of parameters. To initialize data members of a class with distinct values. In the above example, we are passing a string and an integer to the object.
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<String> getParameterNames(Constructor<?> constructor) throws IOException {
Class<?> declaringClass = 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<MethodNode> methods = classNode.methods;
for (MethodNode method : methods) {
if (method.name.equals("<init>") && method.desc.equals(constructorDescriptor)) {
Type[] argumentTypes = Type.getArgumentTypes(method.desc);
List<String> parameterNames = new ArrayList<String>(argumentTypes.length);
@SuppressWarnings("unchecked")
List<LocalVariableNode> 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.
Try https://github.com/paul-hammant/paranamer
Oh for goodness sake SO, really, you're going to make me enter at least 30 characters to edit an existing answer to make it correct.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With