Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / Java

Alternate Proxy class with bytecode manipulation

4.00/5 (1 vote)
20 May 2012CPOL1 min read 10.8K   21  
This article provides alternative to Java's Proxy class with bytecode manipulation.

Introduction 

A proxy forces object method calls to occur indirectly through the proxy object, which acts as a surrogate or delegate for the underlying object being proxied. Proxy objects are usually declared so that the client objects have no indication that they have a proxy object instance.

java.lang.reflect.Proxy class has a few drawbacks:

  1. It uses reflection extensively.
  2. Code written to handle methods is not clean.

The invoke method becomes ugly at times.

Using the code  

Java
Proxy.newProxyInstance(Class clazz, Map<Class, Object> interfaceMap, Object... args)

clazz - Proxy base class  

interfaceMap - key is interface class and value is 

  • either object implementing the interface 
  • or concrete class (not abstract) implementing the respective interface and having public zero argument constructor 
args - Arguments passed to constructor to create instance of proxy class (same give in clazz parameter)

Base class is just a simple class (with at least one non private constructor). If signature of method is same as one of the interfaces then that function will be called instead of the one provided in actual implementation (i.e. value in interfaceMap). 

You can also make Base class abstract implementing the interfaces and defining only selective methods.

Example,

Java
public /*abstract*/ class Base /*implements Runnable, Callable, Comparable*/  {
 
    //method from Callable
    public Object call() throws Exception {
        System.out.println("Call start");
        Object o = (Proxy.<Callable> getInnerObject(this, Callable.class))
                .call();
        System.out.println("Call end");
        return o;
    }
 
    //method from Comparable
    public int compareTo(Object o) {
        System.out.println("compareTo called with argument - " + o);
        return 0;
    }
}

The above compareTo will be called instead implementation passed in interfaceMap

Java
interfaceMap.put(Comparable.class, new Comparable(){
    @Override
    public int compareTo(Object o) {
        System.out.println("This will not be called as inner object is not accessed from base class.");
        return 0;
    }
});
 
interfaceMap.put(Runnable.class, MyRunnable.class);
interfaceMap.put(Callable.class, MyCallable.class);
Runnable runnable = (Runnable)Proxy.newProxyInstance(Base.class, interfaceMap);
Thread thread = new Thread(runnable);
thread.start(); 

You can access the actual implementation object (i.e. value in interfaceMap) by using something like:

Java
Callable callable = Proxy.<Callable> getInnerObject(this, Callable.class); 

Where this is the instance of base class and Callable.class is the key passed in interfaceMap. 

If you want that nobody else should be able to access you inner objects directly (i.e. by using Proxy.<Callable> getInnerObject) you can use an overloaded method of newProxyInstance which restricts of calling this function of any other class other than Base class.  

Bytecode manipulation is used only first time newProxyInstance is called. 

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)