Monday, September 14, 2015

What makes the CGLib Proxy Enhancer the good substitution for the Java Dynamic Proxy

Java standard Dynamic Proxy and Binary Code Generation Library GCLib Proxy Enhancer are serving the same purpose, which is to provide a proxy layer to a Java object of interest. This allows us to add additional functionality to this object in the proxy layer without changing the implementation of this object.

This post identifies the differences between them and these differences could give us the answer why the CGLib Proxy Enhancer is a good substitution for the Java Dynamic Proxy.

Java Dynamic Proxy


diagram 1.0 Class diagram

Java Dynamic Proxy (java.lang.reflect.Proxy) creates a proxy instance that implements the Interfaces which are given during runtime. A proxy instance is associated with a single InvocationHandler instance and this InvocationHandler instance has to keep the proxied instances so that their real method could be invoked.

diagram 1.1: Method invocation flow

Every method invocation made to the proxy instance will be encoded and dispatched to the associated InvocationHandler's invoke() method and this is the place where we could intercept or add any additional functionality before we decide to invoke the real method of the proxied instance.

The code implementation below realizes the class diagram in diagram 1.0.

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class JavaDynamicProxyApp {
    
    public static void main(String[] args) {
        
        Person person = new Person("HauChee");
        Animal animal = new Animal();
        Object proxy = Proxy.newProxyInstance(
                MyInvocationHandler.class.getClassLoader(),
                new Class[] {IPerson.class, IAnimal.class},
                new MyInvocationHandler(person, animal));
        
        System.out.println(proxy instanceof Object); // output: true
        System.out.println(proxy instanceof IPerson); // output: true
        System.out.println(proxy instanceof IAnimal); // output: true
        
        /**
         * Proxy class implements the interfaces not the concrete class
         * therefore, any public method in Person such as think() will never
         * be invoked from proxy instance.
         */
        System.out.println(proxy instanceof Person); // output: false
        System.out.println(proxy instanceof Animal); // output: false
        
        IPerson proxiedPerson = (IPerson) proxy;
        proxiedPerson.getName(); // output: Intercepted.. Person name..
        proxiedPerson.eat(); // output: Intercepted.. Person eat..
        
        IAnimal proxiedAnimal = (IAnimal) proxy;
        proxiedAnimal.eat(); // output: Intercepted.. Person eat.. 
        /**
         * WAIT A MINUTE! ISN't IT SHOULD SHOW "Animal eat.." INSTEAD?
         * 
         * Although eat() method is called based on IAnimal interface
         * but because there is a duplicate method eat() in IPerosn
         * therefore Method object passed into MyInvocationHandler.invoke()
         * method always take from the foremost interface which is IPerson
         * in this case.
         */
    }
}

class MyInvocationHandler implements InvocationHandler {
    
    private Object proxiedPerson;
    private Object proxiedAnimal;

    public MyInvocationHandler(Object person, Object animal) {
        this.proxiedPerson = person;
        this.proxiedAnimal = animal;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        System.out.print("Intercepted.. ");
        if (method.getDeclaringClass() == IPerson.class) {
            // Invoke real method of Person object
            return method.invoke(proxiedPerson, args); 
        }
        // Invoke real method of Animal object
        return method.invoke(proxiedAnimal, args); 
    }
}

class Person implements IPerson {
    
    private String name;
    
    Person(String name) {
        this.name = name;
    }

    @Override
    public String getName() {
        System.out.println("Person name..");
        return name;
    }

    @Override
    public void eat() {
        System.out.println("Person eat..");
    }
    
    public void think() {
        System.out.println("Person think..");
    }
}

class Animal implements IAnimal {

    @Override
    public void eat() {
        System.out.println("Animal eat..");
    }
}

interface IPerson {
    String getName();
    void eat();
}

interface IAnimal {
    void eat();
}

Characteristics of Java Dynamic Proxy

  • Only the methods declared in the given interfaces and java.lang.Object's methods such as hashcode(), equals() and toString() are eligible to be intercepted, other public methods of the proxied class are ignored. This is because there is no way to call the other public method from the proxy instance. In diagram 1.0, think() method of Person is out of the proxy scope.
  • Clear-cut between the proxy instance and the proxied instances. The InvocationHandler instance becomes the bridge between them. It is allowed to have more than 1 proxied object because after all it is up to the programmer to decide how and which real method of which proxied object to be invoked
  • There is only one InvocationHandler instance associated with a proxy instance. Its only method invoke() is simple and raw. It is the programmer's job to extends the capabilities of the InvocationHandler.

CGLib Proxy Enhancer


diagram 2.0: Class diagram

CGLib Proxy Enhancer (net.sf.cglib.proxy.Enhancer) creates a proxy instance that extends a concrete class in addition to implements the interfaces. A proxy instance is associated with a list of Callback instances that could serve for the different purpose other than purely method interception. Enhancer uses CallbackFilter instance to determine which Callback instance to use when a proxy method is invoked.

diagram 2.1: Method invocation flow

Every method invocation made to the proxy instance will be encoded and dispatched to the associated Callback method according to the signal given by CallbackFilter instance. The Callback methods are the place where we could intercept or add additional functions to the real method. After that, we could decide to invoke the proxy's superclass's real method accordingly.

The code implementation below realizes the class diagram in diagram 2.0.

import java.lang.reflect.Method;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.CallbackFilter;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.FixedValue;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class CGLibProxyEnhancerApp {
    
    public static void main(String[] args) {
        Object proxy = Enhancer.create(
                Mutant.class,
                new Class[] {IPerson.class, IAnimal.class}, 
                new MyClassbackFilter(),
                new Callback[] {new MyMethodInterceptor(), new MyFixedValue()});
        
        System.out.println(proxy instanceof Object); // output: true
        System.out.println(proxy instanceof IPerson); // output: true
        System.out.println(proxy instanceof IAnimal); // output: true
        System.out.println(proxy instanceof Mutant); // output: true
        
        Mutant proxiedMutant = Mutant.class.cast(proxy);
        /**
         * Although setName() method is not declared in proxy interfaces
         * but it is eligible to be intercepted because proxy class is a subclass
         * of Mutant and inherit setName() method.
         */
        proxiedMutant.setName("HauChee");// output: Intercepted..Mutant set name..
        // output: Intercepted and always return "Fixed"
        System.out.println(proxiedMutant.getName()); 
        // output: Intercepted and always return "Fixed"
        System.out.println(proxiedMutant.toString()); 
        proxiedMutant.eat(); // output: Intercepted..Mutant eat..
    }
}

class MyClassbackFilter implements CallbackFilter {
    
    @Override
    public int accept(Method method) {
        if (method.getReturnType() == String.class) {
            return 1;
        }
        return 0;
    }
}

class MyFixedValue implements FixedValue {

    @Override
    public Object loadObject() throws Exception {
        return "Intercepted and always return \"Fixed\"";
    }
}

class MyMethodInterceptor implements MethodInterceptor {

    @Override
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy mp)
            throws Throwable {
        System.out.print("Intercepted..");
        // Invoke the real method of proxy's superclass 
        return mp.invokeSuper(proxy, args); 
    }    
}

class Mutant implements IPerson, IAnimal {
    
    private String name;
    
    /**
     * Enhancer requires the no-arg constructor to construct the proxy instance.
     * IllegalArgumentException is thrown if Enhancer can't find the no-arg
     * constructor during proxy creation time.
     */
    public Mutant() {
    }
    
    public Mutant(String name) {
        this.name = name;
    }

    @Override
    public String getName() {
        System.out.println("Mutant get name..");
        return name;
    }

    @Override
    public void eat() {
        System.out.println("Mutant eat..");
    }
    
    public void setName(String name) {
        System.out.println("Mutant set name..");
        this.name = name;
    }
}

interface IPerson {
    String getName();
    void eat();
}

interface IAnimal {
    void eat();
}

Characteristics of CGLib Proxy Enhancer

  • Since the proxy class is the subclass of concrete class and interfaces, all its non-final methods which are visible to the Enhancer are intercept-able. In fact, the interfaces are optional. The proxy class could live solely as the subclass of a concrete class without implement any interface. This is very useful when we want to proxy a class that not meant to implement any interface.
  • There is no distinction between proxy instance and proxied instance. The proxy instance is treated as the proxied instance as it directly inherits all public behaviors from its concrete class. This has enforced one to one relationship between them. After all, this is what we are looking for compared to handling multiple proxied instances at once which could increase the complexity.
  • CGLib has extended the method interception capability by providing a few of Callbacks to serve different purpose and CallbackFilter to control the Callbacks. Programmer could focus on the functionality implementation and has better control over the method interception.

Summary

Table below summarise the differences between Java Dynamic Proxy and CGLib Proxy Enhancer.


In short, CGLib Proxy Enhancer provides better framework and greater capability compare to Java Dynamic Proxy.


References:
http://cglib.sourceforge.net/apidocs/net/sf/cglib/Enhancer.html
http://docs.oracle.com/javase/7/docs/api/java/lang/reflect/Proxy.html
http://mydailyjava.blogspot.my/2013/11/cglib-missing-manual.html


Tuesday, September 1, 2015

Differences between List, List<Object> and List<?>

We may mistakenly think that List, List<Object> and List<?> are the same because of their similarity behavior. For example, calling the getter method of each of them will return a Java object with java.lang.Object type. Despite their behaviors are similar, they do have different behaviors and carrying different notion and purpose.

List: Raw Type

A list that could contain any Java object as its elements. This is the old way of using Java Collection before Java version 5. It is not type-safe because Java compiler has no way to check and prohibit the getter and setter operations called upon it. It is valid to accept any Java object, and it is the calling code's responsibility to cast its return object/element to the correct type. Doing this casting wrongly can't be revealed during compilation time, and one will get ClassCastException only during runtime. Since Java version 5, we should never make use of raw type. Doing so Java compiler will generate unchecked or unsafe operations warning to indicate there is a risk in the code.

List rawTypeList = new ArrayList();

// Java compiler warns unchecked or unsafe operations
rawTypeList.add(0);
rawTypeList.add("test");

String str = (String) rawTypeList.get(0); // ClassCastException thrown during runtime

The only reason it is still allowed is to support backward compatibility of legacy code.

List<Object>: Parameterized Type

A list that is purposely declared and created to contains Java object (which IS A Object) as its elements. Although it works similar to raw type, but it is type-safe and conceptually different compares to raw type. The Object type argument specified in the List<Object> indicates that this list is purposely used to deal with the element(s) with Object type only. Whoever use this list should aware that its return object/element should be used as a generic object and should never be casted to any specific type. If one still do the manual casting, then he/she is taking his/her own risk of getting ClassCastException during runtime.

List<Object> parameterizedTypeList = new ArrayList<>();

// No warning, Integer and String IS A Object, hence it is a valid input object.
parameterizedTypeList.add(0); 
parameterizedTypeList.add("test"); 

// Do not do this as it against the purpose of using Java Generic.
// ClassCastException thrown during runtime.
String str = (String) parameterizedTypeList.get(0); 

Although List<Object> is a valid parameterized type, but the value it offers not more than a raw type list. Moreover, it is restrictive because Java compiler ensures it can only refer to an instance of List that had parameterized to Object type.

public static int countNonNullItems(List<Object> list) {
    int count = 0;
    for (int i = 0; i < list.size(); i++) {
        Object obj = list.get(i);
        if (obj != null) {
            count++;
        }
    }
    return count;
}

public static void main(String[] args) {
    countNonNullItems(new ArrayList<Object>()); // Valid
    countNonNullItems(new ArrayList<Integer>()); // Compilation error: incompatible types
    countNonNullItems(new ArrayList<String>()); // Compilation error: incompatible types
}

Whenever applicable, you could change your method parameter from List<Object> to List<?> to increase method reusability. Refer to next section for more detail.

List<?>: Unbounded Wildcard Type

A List that could contain elements with unknown type. It is used in the operation where this operation does not care about its element type. It is type-safe and actually a special kind of parameterized type where its element type is parameterized to unknown. It only able to accept null as its element, because null has the unknown type. Trying to add an object into this list will cause the compilation error. Why? Because this breaks the intention of wildcard where the element type must be remained unknown.

List<?> unBoundedWildcardTypeList = new ArrayList<>();

unBoundedWildcardTypeList.add(null); // Valid
unBoundedWildcardTypeList.add(1); // Compilation error
unBoundedWildcardTypeList.add("test"); // Compilation error

In term of instance reference, the List<?> is looser than the List<Object>. It is able to refer to an instance of List with any element type. Why? Since the Java compiler blocks the business logic in the operation from working with the list's element type, it does not matter what List instance (with what element type) is given to this operation. This behavior could improve the method reusability, that is why we should take this into consideration when designing our methods.

public static int countNonNullItems(List<?> list) {
    int count = 0;
    for (int i = 0; i < list.size(); i++) {
        Object obj = list.get(i);
        if (obj != null) {
            count++;
        }
    }
    return count;
}

public static void main(String[] args) {
    countNonNullItems(new ArrayList<Object>()); // Valid
    countNonNullItems(new ArrayList<Integer>()); // Valid
    countNonNullItems(new ArrayList<String>()); // Valid
}

In fact, there are API in java.util.Collection are using wildcard type as their method parameters such as containsAll(Collection<?> c)removeAll(Collection<?> c)retainAll(Collection<?> c).

Summary

Table below summarized the differences between ListList<Object> and List<?>.


In short, we should avoid from using raw type in the new code. Whenever a method parameter is List<Object>, change it to List<?> to promote the method reusability.


References:
Book: Effective Java 2nd Edition  - Joshua Bloch
Book: Java Generics and Collections - Maurice Naftalin & Philip Wadler
https://docs.oracle.com/javase/tutorial/java/generics/index.html