JavaEnterprise JavaMake Use of Reflection API to Write Dynamically Pluggable Code

Make Use of Reflection API to Write Dynamically Pluggable Code

Developer.com content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More.

A class, as we understand it, is basically a “capability set,” an entity type that agrees to abide by a contract of what it is capable of. Now, the capability of any class must be known before it can be used in a program. The capability is “published” in the form of method signatures of the class and also the “type” of accessible “fields.”

In Java, this knowledge of the capabilities of the class being used in a program is enforced at compile time, javac checks and verifies this capability set very thoroughly. How is this achieved? Obviously javac has a mechanism to read and understand a class and find out the implication of the messages between objects. For example, there could be a method in a class, say Callee:


class Callee {
.
.
public void doIt () throws CantDoException {
}
….
}

And in a class, say Caller, you have an object of Callee and the method

doIt()
is called:


class Caller {
Callee callee;
…..
callee.doIt();
…..
}

Assuming that CantDoException is not derived from RuntimeException, the compiler will obviously complain that CantDoException should either be caught or declared in the throws clause of the method from within which the

doIt()
call is made. Here, javac is making use of the capability set and enforcing certain semantics.

The next logical question is: Can we find out the capability at runtime of a class whose capabilities were not known at compile time? A program that analyzes the capabilities of classes is referred to as being reflective. Java has a package, java.lang.reflect, that has classes that support this reflection, along with some classes in java.lang, the most notable of which is the java.lang.Class class. These classes support creation of programs such as debuggers, interpreters, object analyzers, WYSIWYG GUI tools and so on.

How many times while programming for applications other than those mentioned above do you need to use reflection? I reckon not much, but sometimes when you need to work on a class that was not known at compile time, reflection provides the answer.

The JavaBeans framework makes use of this reflection mechanism to actually plug in a bean to a container of beans or a beanbox.

Let me liven up the proceedings with an example. Suppose there is a great program that is running around the clock on a server and is collecting data about possible extraterrestrial life, it is continuously collecting data and cannot be brought down, suppose there is a small piece of an algorithm that plays a role in that program. Scientists find out a way to optimize that algorithm and thus save time, but the program cannot be brought down. If the early designers of the program were thoughtful enough, then there is a way to dynamically plug in the brand new algorithm.

Now, if the algorithm implemented an interface Algorithm


interface Algorithm {
public void process();
}

and if we have the reference to the algorithm as this interface type, then we could easily swap the Algorithm implementations after reading it at runtime, like:


Algorithm algo;
.
.
String className = ConsoleReader.readLine(); // read from console
algo = (Algorithm) ((Class.forName(className)).newInstance());

Let’s say “algo” is the name of a variable of type Algorithm (interface) and this reference is used to call the method

process()
, now we can swap the implementations and make the “algo” reference point toward a new implementation of the Algorithm interface. Here, the String ‘className’ now contains the name of the new implementation class (which, say, you enter from the console). The

forName(className)
method of class “Class” (

Class.forName(String)
) loads and links this new implementation into the VM and returns an object of type “Class”. The method

newInstance()
creates a new instance (i.e., an Object) of that class. Since our new class also implements the interface Algorithm, we can cast it to type Algorithm and assign it to reference “algo”. So now the reference “algo” points toward the new implementation.

DynamicLoad.java


You can actually code separately (from a separate terminal window, compile and provide the name to our Star Trek program in DynamicLoad.java), and bingo, it gets into operation immediately.

Going back to our original discussion, is this loading really dynamic, in the sense that the new class really was not known at compile time? The answer is no. We imposed a restriction on the behavior by restricting our interaction through the Algorithm interface, which was known at compile time; in fact, we made use of polymorphism apart from dynamically loading the class. Even in the case of JavaBeans, while using introspection, we enforce a design pattern of getter and setter methods to find out the properties and their kind (read/write or read-only).

Using the class Class methods like

getMethod()
,

getMethods()
,

getInterfaces()
,

getConstructors()
,

getField()
, and so forth, we can peek inside a class and find this information at runtime. We can then “search” for the matching method by looking at the parameters and return the type each method has and, depending upon what we are interested in, invoke the method of our choice.

Suppose our

process()
method requires that the input should be of type InputParam and the return should be of type ReturnValue, both defined earlier, now a new programmer has coded a new algorithm that has the same signatures (it has to be, otherwise it will be of no use to us) but he or she has named the method

myInnovation()
, we can still search through his or her class and use the method:


Method m[];
Class c = Class.forName(classname);
m = c.getDeclaredMethods();
for(int i=0;i<m.length;i++) {
if(m[i].getReturnType().getName().equals(“ReturnValue”) && m[i].getParameterTypes().equals(“InputParam”) )
{
rtObj = (ReturnValue) (m[i].invoke(c.newInstance(), ipObj));


Now this is not compilable, because

getParameterTypes()
returns an array of

Class[]
, and we have to look for index 0, but for simplicity’s sake, this is okay, what we have done is that we can iterate over the declared methods of a class and look for the method that adheres to the signature of our choice, then we can instantiate an object of that class and invoke the method of our choice, all dynamically! This takes us a step further in runtime identification of the capabilities of a class.

As a matter of fact the new Dynamic Proxy API with JDK 1.3 makes use of a similar searching mechanism to arrive at the functionality of having a dynamic proxy. Let me explain this, the API allows us to create a Proxy object, which is told about certain interfaces that it has to handle; then in an application an instance of this Proxy object is created, and calls meant to be handled by implementations of these interfaces are made to this Proxy object. This Proxy object is also told about an InvocationHandler, which contains the actual delegate object to which the call is finally made. Sounds cryptic! Let me clarify this with an example. InvocationHandler is actually an interface that has a single method:


public Object invoke (Object proxy, Method m, Object[] args) throws Throwable

Here, the proxy is the reference to the Proxy object created. This

invoke()
method is called at runtime and is transparent to the implementor, as well as the client. Here’s the example of the InvocationHandler implementation:


public class MyHandler implements java.lang.reflect.InvocationHandler {

// this is the delegate object, can be any user defined object
Object delegate;

public MyHandler (Object obj) {
this.delegate = obj ;
}

public Object invoke (Object proxy, Method m, Object[] args) throws Throwable {
try {

// may actually invoke on the delegate here and also do something before or after

}
catch(InvocationTargetException e){
throw e.getTargetException();
}
catch(Exception e) {
throw e;
}
// return here
}

Now, assume that the delegate object implements three interfaces — A, B, and C — the dynamic proxy API enables you to create a Proxy object with a type of any of the interfaces. For example:


A a = (A) java.lang.reflect.Proxy.newInstance (ClassLoader cl, Class[] { A.class, B.class,C.class }, new MyHandler(delegate) );

Or the same can also be assigned to reference of type B or C. When the client says “

a.doSomethig()
“, assuming that

doSomething()
was a method of interface A, then the call is actually forwarded to the InvocationHandler instance, which in our case is MyHandler. Before that, a reference to the Method is obtained (method pointer!) by reflecting over all the interfaces provided to Proxy as an array in the

newProxyInstance()
method. This Method reference and the arguments to it are passed to the

invoke()
method of the handler, where you can actually call it on the delegate object or do whatever you please.

This, I presume, is the best we can do in getting to dynamic pluggability of classes at runtime; the underlying idea being that some form of contract or some design pattern has to be adhered to. Reflection APIs actually take us very close to this goal.

About the Author

Nasir Khan is a Sun Certified Java programmer, with a B.E. in electrical engineering and a masters degree in systems. His areas of interest include Java applications, EJB, RMI, CORBA, JDBC and JFC. He is presently working with BayPackets Inc. in high-technology areas of telecom software.

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Latest Posts

Related Stories