Here is an exercise for you!
Write a java program that take two or more command line arguments. 1st argument is a class name. 2nd argument is a method name. Rest of the arguments are string values to be passed in to that method.
Your program has to load the class specified in first argument (this class may not be available at compile time). Create an instance of that class. Then invoke the method given in the 2nd argument on that object passing the values given in rest of the arguments as parameters to that function. To simplify things lets say all parameters are string.
The answer is reflections. To give you a very simplified description, Reflections allow you to access members of a class/object dynamically in run time without having to hard-code things in the source code. This is slower than hard-coding. But it is very useful when the class/methods/fields that you need to access are not known or not available at compile time. Also in some cases you can do cool things like accessing private members.
Lets see how to do the above task step by step.
1. Load the class specified in first parameter.
This part is not really reflection, but this is where most reflection code start. Before you can access members of a class you need the class itself. How do we load a class of which the name is inside a string. Well! if you have done some JDBC coding you have done this already. Yes you can use Class.forName(….) method. But this time we need a reference to the class itself. For that we use Class class.
Class myClass = Class.forName(args);
If the value in args array element is a valid class name above line should place a reference to the Class object of that class in myClass variable. Otherwise you will be greeted with a ClassNotFoundException.
2. Create an instance of that class.
For simplicity lets assume that we use default constructor. In that case, creating an instance of a class is as simple as
Object myInstance = myClass.newInstance();
If you need to use a non-default constructor that is bit tricky. First you need to call getConstructor(Class… parameterTypes) method on your Class object to get a Constructor object and then call newInstance(Object… initargs) method on the Constructor object to create the object. Don’t worry about these wired looking parameters of these methods for the moment. Because we are not going to use those methods for this example and also after next step you will know all about those parameters.
3. Get the Method
Well this is the tricky part. Before you can invoke a method you must first get a Method object that represent the method. Question is how do you do that. Well if you have learned the java basics, you should know that in java, a method is identified by its signature. And the signature has two parts, method name and parameters types.
We have the method name in 2nd argument passed in to our program. We assume that the number of parameters in the method is equal to the additional parameters passed in to our program (total parameters – 2). And we have the class object.
Since we have the Class object all we got to do is call getMethod(String name, Class… parameterTypes) method on it, passing method name and an array of class objects to represent the list of parameter types.
Lets first make the Class array to represent parameter types…
Class parameterTypes = new Class[args.length-2];
We assume that all parameters are of type String. So we can fill the array with String class objects.
for (int i=0; i<parameterTypes.length; i++) parameterTypes[i] = String.class;
Now we have everything we need to define the method signature, therefore we are ready to call getMethod function
Method myMethod = myClass.getMethod(args, parameterTypes)
If you revisit step 2 where I touched on getConstructur function, the class array parameter on that function is also used to identify the signature of constructor. And it is as same as 2nd parameter on getMethod function.
4. Invoke the method
Now we just have the method. All that is left is to invoke it.
Once we have the Method instance you just have to call invoke(Object obj, Object… args) method on Method object. First parameter of this method is the object on which we invoke the method. That object should belong to the class that contain the method that we are trying to invoke. Second parameter is an array of objects containing the parameters to be passed in to the method that we invoke. Constructing that array is similar to creating the parameter types array in previous step. In this step we also assume that invoking this method will not cause any Exception. Also we ignore any return value from the method. You can figure out how to deal with those things by reading the documentation.
Ok, lets get down to work. We already have the object that we need to pass in to first parameter. We created that in step 2. All we need to do is to construct the array of parameters. This time since we already have the parameters as a part of incoming argument array to the program, we can use System.arraycopy method.
String parameters = new String[args.length-2]; System.arraycopy(args, 2, parameters, 0, parameters.length);
Now we got everything we need to invoke the thing.
Lets just put all above together…
Well, it looks like an awful lot of code just to invoke a single method. But as you can see above, the method we need to invoke or its class is not there in the code. Reflections can look messy but in complex applications it is a very powerful tool and most often it is also the cleanest way to do it.
This is a very basic example of using java reflections. It is not possible to cover everything about reflections in one post. If you read java documentation on package java.lang.reflect you will be able to learn lot more. I’ll write few more posts on this topic in the future.
6 comments on “Java Core API: Introduction to Java Reflections”
You must log in to post a comment.