Wednesday, November 7, 2007

Make use of Dynamic Proxy

Proxy is a very useful concept and I have created this simple sample to get started.
In this sample, we will be using Proxy to intercept calls to a java.util.Map object.

The Handler.java contains the Handler class that implements the InvocationHandler interface. The contructor takes the Map Object that will be the target of the proxy. All method calls to the proxy will be forwarded to the Map Object. The invoke method in the Handler gets called with the arguments whenever any method in the proxy is invoked. We are supposed to invoke that method in the proxied object from inside this method and return the returned values back. At this stage, we can do any custom tasks before and/or after invoking the method.

The following is the code for the Handler.java which implements the InvocationHandler. Here I am just printing some messages to the System.out before and after method invocation.

 
import java.util.Map;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;

public class Handler implements InvocationHandler
{
Map map;

public Handler(Map map)
{
this.map = map;
}

public Object invoke(Object proxy, Method method,
Object[] args) throws Throwable
{
Object ret = null;

try
{
System.out.println("\tBefore invoking: " +
method.toString());

// Invoke the method on the map object
ret = method.invoke(map,args);

System.out.println("\tAfter invoking: " +
method.toString());
}
catch (InvocationTargetException e)
{
throw e.getTargetException();
}

return ret;
}
}


The following is the DynamicProxy.java that contains the main application logic.
In this main method here, we are creating a map first whose access will be proxied.
We then call Proxy.newProxyInstance to create a proxy to this map with the help of the Handler above. Once we have the proxy, we can make all calls to the proxy just as if it is the map object, and all calls to that proxy will be passed to the Handler's invoke method. If we call the methods of the map object directly, those calls will not be passed to the Handler.

 
import java.util.Set;
import java.util.Map.Entry;
import java.util.HashMap;
import java.util.Map;
import java.lang.reflect.Proxy;

public class DynamicProxy
{

public static void main(String[] args)
{
System.out.println("This application tests dynamic proxy " +
"concept by intercepting method calls to Map Object");

// Create the map object
Map map = new HashMap();

// Create the proxy for the map passing Handler as the InvocationHandler
// The invocation Handler can intercept all method calls to the Map
Map proxy = (Map)Proxy.newProxyInstance(map.getClass().getClassLoader(),
new Class[] { Map.class },new Handler(map));

System.out.println("This will be intercepted...");
// Put values into the map using the proxy, so that the calls can be intercepted
proxy.put("key","intercepted");

System.out.println("This will not be intercepted...");
// Direct method calls to the map will not be intercepted by the proxy
map.put("key1","not-intercepted");

System.out.println("Contents of the map...");
// Iterator through the map to see whether the values are inserted into the map
for(Map.Entry entry : (Set)map.entrySet() )
{
System.out.println(entry.getKey() + "=" + entry.getValue());
}

}

}


Just compile the two classes and run. They dont need any external dependencies.

Java Reference