Different Java proxy based frameworks with pros and cons.

Today there are several tools that can be used to manipulate bytecode, ranging from very low-level tools such as ASM, which require you to work at the bytecode level, to high level frameworks such as CGlib, AspectJ, which allow you to write pure Java. Ofcourse each framework have there own limitations in creating proxies.

For the moment, I just want to provide a quick summary on the pros and cons of proxy frameworks available. Hope everyone knows about the GOFProxy design pattern.

JDK dynamic proxies:

The JDK dynamic Proxy relies heavily on interface based implementations.JDK comes with the class java.lang.reflect.Proxy that allows you to create a dynamic proxy for a given interface. The InvocationHandler that sits behind the dynamically created class is called every time the application invokes a method on the proxy. Hence you can control dynamically what code is executed before the code of some framework or library is called.

Dynamic proxies can be used for many different purposes, e.g. database connection and transaction management, dynamic mock objects for unit testing, and other AOP-like method intercepting purposes.

Hibernate for lazy loading entities, Spring for AOP, LambdaJ for DSL, only to name a few: they all use their hidden magic. What are they? They are… Java’s dynamic proxies.

Limitation of JDK Dynamic proxy can only proxy by interface (so your target class needs to implement an interface).Any interface method is then forwarded to an InvocationHandler.If class does not implemented from interface then you will see ClassCastException.

Sample code to create proxy using JDK proxies.


MyInterface proxy = (MyInterface) Proxy.newProxyInstance(
                MyInterface.class.getClassLoader(),
                new Class[]{MyInterface.class},
                new InvocationHandler(){
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        if (method.getName().equals("your method name")) {
                            // do want ever magic you want...
                        }
                    }
                });
The invoke method will intercept all method calls on your proxied object.

CGLib proxies :

Java proxies are runtime implementations of interfaces. Objects do not necessarily implement interfaces, so Java proxies fail to provide an answer for a class not implemented from interface.

That's where CGlib came out.CGlib is a third-party framework, based on bytecode manipulation provided by ASM that can help with the previous limitations. 


     1. The proxies are created by sub-classing the actual class. This means wherever an instance of the class is used it is also possible to use the CGLib proxy.
     2. The class needs to provide a default constructor, i.e. without any arguments. Otherwise,you'll get an IllegalArgumentException: "Superclass has no null constructors but no arguments were given." This makes constructor injection impossible.
     3. The proxying does not work with final methods since the proxy subclass can not override the class' implementation.
     4. The CGLib proxy is final, so proxying a proxy does not work. You will get an IllegalArgumentException.
     5. Two objects are created (the instance of the class and the proxy as instance of a sub class) the constructor is called twice.
     6. Documentation of CGlib is not complete.
     7. The proxies are not Serializable.
     8. You will need add CGLIB binaries on your classpath or dependencies.
     9. Furthermore, cglib can improve performance by specialized interceptions like FixedValue,NoOp,LazyLoader...
CGlib introduced many callback handlers for better performance.Please go with my previous post "Creating Proxies Dynamically Using CGLIB Library with examples".

Spring AOP: CGLIB or JDK Dynamic Proxies ?

Spring AOP uses either JDK dynamic proxies or CGLIB to create the proxy for a given target object. (JDK dynamic proxies are preferred whenever you have a choice). If the target object to be proxied implements at least one interface then a JDK dynamic proxy will be used. All of the interfaces implemented by the target type will be proxied. If the target object does not implement any interfaces then a CGLIB proxy will be created. 

If you want to force the use of CGLIB proxying (for example, to proxy every method defined for the target object, not just those implemented by its interfaces) you can do so.



ASM :

CGLIB and almost all other libraries are built on top of ASM which itself acts on a very low level. This is a show-stopper for most people as you have to understand the byte code and a little bit of the JVMS to use it properly. But mastering ASM is most certainly very interesting. Note however that while there is a great ASM 4 guide, in some part of the API the javadoc documentation can be very concise if it is present at all, but it is being improved. It closely follows JVM versions to support new features.

Javassist :

The javadoc of Javassist is way better than that of CGLIB. The class engineering API is OK, but Javassist is not perfect either. In particular, the ProxyFactory which is the equivalent of the CGLIB's Enhancer suffer from some drawbacks too, just to list a few :

      1. Bridge method are not fully supported (ie the one that are generated for covariant return types).
      2. ClassloaderProvider is a static field instead, then it applies to all instances within the same classloader.
      3. Custom naming could have been welcome (with checks for signed jars).
      4. There is no extension point and almost all methods of interest are private, which is cumbersome if we want to change some behavior.
      5. While Javassist offer support for annotation attributes in classes, they are not supported in ProxyFactory. 

On the aspect oriented side, one can inject code in a proxy, but this approach in Javassist is limited and a bit error-prone .

      1. aspect code is written in a plain Java String that is compiled in opcodes.
      2. no type check.
      3. no generic.
      4. no lambda.
      5. no auto-(un)boxing

Also Javassist is recognized to be slower than Cglib. This is mainly due to its approach of reading class files instead of reading loaded classes such as CGLIB does. And the implementation itself is hard to read to be fair ; if one requires to make changes in the Javassist code there's many chances to break something.

Byte Buddy :

Byte Buddy is a rather new library but provides any functionality that CGLIB provides. Byte Buddy can be fully customized down to the byte code level and comes with an expressive domain specific language that allows for very readable code.

It supports all JVM bytecode versions, including Java 8 semantic changes of some opcodes regarding default methods.

      1. ByteBuddy don't seem to suffer from the drawbacks other libraries have.
     2. Highly configurable.
     3. Quite fast (benchmark code).
     4. Type safe.
     5. Type safe callbacks.
    6. Very well documented.
    7. Lots of example.
    8. Annotation driven (flexible).
    9. Available as an agent.
    10. Clean code, 93% test coverage

You can find more details on the benchmark in Byte Buddy's tutorial, where Byte Buddy is a more modern alternative to cglib. Also, note that cglib is no longer under active development.

Here are some metrics for implementing an interface with 18 stub methods:
Byte Buddy        CGlib                 Javassist         JDK proxy         
Creation 0.234 0.613 0.391 0.309
invocation       0.002   0.019  0.027 0.003 

The time is noted in nanoseconds.

In fact there are other proxy frameworks like BCEL, AspectJ, JiteScript, Proxetta are not discussed in this post as there are not much familiar.

To summarize, out of all frameworks Byte Buddy is a most modern(as of 2015) proxy framework with precise documentation and with various examples.Mockito used CGlib over years,in recent time mockito is replacing CGLIB by Byte Buddy.



Creating Proxies Dynamically Using CGLIB Library with examples

CGLIB is a bytecode generation framework,there are many such frameworks which do same job.But CGLIB is high-level framework that would dynamically change classes providing its proxy and substituting the functionality of some methods.

Even JDK dynamic proxies can do same,but there are some cons in JDK proxies.JDK proxies will only work if your class is implemented from interface/s.Where as CGLIB does not have such restriction.It will create subclass(proxy) to any class.

CGLIB is a powerful, high performance code generation library, that relies on low-level
ASM framework.It is widely used behind the scenes in proxy-based Aspect Oriented Programming (AOP) frameworks, such as Spring AOP and dynaop, to provide method interceptions. Hibernate, the most popular object-relational mapping tool, also uses the CGLIB library to proxy single-ended (many-to-one and one-to-one) associations (not lazy fetching for collections, which is implemented using a different mechanism). EasyMock and jMock are libraries for testing Java code using mock objects. Both of them use the CGLIB library to create mock objects for classes that do not have interfaces.


Here I will explain creating proxies in four ways using CGLIB library.Let me take a simple java class and create proxy for this class.
public class JobsManager {
private static List<String> jobs = new ArrayList<String>();
      static {
            jobs.add("job1");
            jobs.add("job2");
            jobs.add("job3");
      }
       public List<String> getAllJobs() {
            return jobs;
      }
      public int getCount()
            return jobs.size();
      }
       public boolean createJob(String name) {
            return jobs.add(name);
      }
}
In all below example,we will create proxy for this JobsManager and do method calls on proxy instance.

1) Create proxy using callbackhandler InvocationHandler : 

public class JobsInvocationHandlerDemo {
    public static void main(final String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(JobsManager.class);
        enhancer.setCallback(new InvocationHandler() {
            @Override
            public Object invoke(Object obj, Method method, Object[] args) throws Throwable {
                // redirecting all object class method calls to its super
                if (method.getDeclaringClass().equals(Object.class)) {
                    return NoOp.INSTANCE;
                }
                // returning static jobs list
                if (method.getName().equals("getAllJobs")) {
                    return Arrays.asList(new String[]{"job5", "job6", "job7"});
                }
                // returning static jobs count
                if (method.getName().equals("getCount")) {
                    return 555;
                }
                // which will create end less loop, you should be more care full in using invocation handler.
                //if(method.getName().equals("createJob"))
                //return method.invoke(obj,args);
                return null;
            }
        });
        // jobsManager is proxified class object
        JobsManager jobsManager = (JobsManager) enhancer.create();
        // jobs list will not equal with proxy method call
        Assert.assertNotEquals(new JobsManager().getAllJobs().get(0), jobsManager.getAllJobs().get(0));
        // jobs count will not equal with proxy method call
        Assert.assertNotEquals(new JobsManager().getCount(), jobsManager.getCount());
         //which will go end less loop if you uncomment above method.invoke
        //Assert.assertEquals(true, jobsManager.createJob("job4"));
    }
}
All the JobsManager proxy method calls will go though Invocationhanler, here you can write your own code or redirect.
But there is a limitation in Invocationhanler,if any method call dispatchs to its super class then it will result in an endless loop.

2) Create proxy using callbackhandler MethodInterceptor :

public class JobsMethodInterceptorDemo {
public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(JobsManager.class);
        enhancer.setCallback(new MethodInterceptor() {
            @Override
            public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                // redirecting all object class method calls to its super
                if (method.getDeclaringClass().equals(Object.class)) {
                    return NoOp.INSTANCE;
                }
                // returning some static jobs list
                if (method.getName().equals("getAllJobs")) {
                    return Arrays.asList(new String[]{"job5", "job6", "job7"});
                }
                // returning some static jobs count
                if (method.getName().equals("getCount")) {
                    return 555;
                }
                // redirecting it its super class
                if (method.getName().equals("createJob")) {
                    return methodProxy.invokeSuper(obj, args);
                }
                // NoOp Instance
                return NoOp.INSTANCE;
            }
        });
        // jobsManager is proxified class object
        JobsManager jobsManager = (JobsManager) enhancer.create();
        // jobs list will not equal with proxy method call
        Assert.assertNotEquals(new JobsManager().getAllJobs().get(0), jobsManager.getAllJobs().get(0));
        // jobs count will not equal with proxy method call
        Assert.assertNotEquals(new JobsManager().getCount(), jobsManager.getCount());
        // here both should be true.
        Assert.assertEquals(true, jobsManager.createJob("job4"));
    }
}
The MethodInterceptor allows full control over the intercepted method and offers some utilities for calling the method of the enhanced class.MethodInterceptor is the callback for all methods of a proxy, method invocations on the proxy are routed to this method before invoking the methods on the original object.

3)Create proxy using callbackhandler MethodInterceptor and CallBackFilter :

public class JobsInterceptorWithCallBackFilter {
    public static void main(final String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(JobsManager.class);
        enhancer.setCallbackFilter(new CallbackFilter() {
            @Override
            public int accept(Method method) {
                if (method.getDeclaringClass().equals(Object.class)) {
                    return 0;
                }
                if (method.getName().equals("getAllJobs")) {
                    return 1;
                }
                if (method.getName().equals("getCount") || method.getName().equals("createJob")) {
                    return 2;
                }
                return 0;
            }
        });
        enhancer.setCallbacks(new Callback[]{NoOp.INSTANCE, new FixedValue() {
            @Override
            public Object loadObject() throws Exception {
                return Arrays.asList(new String[]{"job5", "job6", "job7"});
            }
        }, new MethodInterceptor() {
            @Override
            public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                return methodProxy.invokeSuper(obj, args);
            }
        }});
        // jobsManager is proxified class object
        JobsManager jobsManager = (JobsManager) enhancer.create();
        // jobs list will not equal with proxy method call
        Assert.assertNotEquals(new JobsManager().getAllJobs().get(0), jobsManager.getAllJobs().get(0));
        // jobs count will be equal with proxy method call
        Assert.assertEquals(new JobsManager().getCount(), jobsManager.getCount());
        // here both should be true.
        Assert.assertEquals(true, jobsManager.createJob("job4"));
    }
}
If you want to use multiple callback filters based on some condition then use CallbackFilter. CallbackFilter is selectively apply callbacks on the methods. This feature is not available in the JDK dynamic proxy.
4) Create proxy using callbackhandler MethodInterceptor and CallBackHelper : 

public class JobsInterceptorWithCallBackHelper {
    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(JobsManager.class);
        CallbackHelper callbackHelper = new CallbackHelper(JobsManager.class, new Class[0]) {
            @Override
            protected Object getCallback(Method method) {
                if (method.getDeclaringClass().equals(Object.class)) {
                    return NoOp.INSTANCE;
                }
                if (method.getName().equals("getAllJobs")) {
                    return new FixedValue() {
                        @Override
                        public Object loadObject() throws Exception {
                            return Arrays.asList(new String[]{"job5", "job6", "job7"});
                        }
                    };
                }
                if (method.getName().equals("getCount") || method.getName().equals("createJob")) {
                    return new MethodInterceptor() {
                        @Override
                        public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                            return methodProxy.invokeSuper(obj, args);
                        }
                    };
                }
                return NoOp.INSTANCE;
            }
        };
        enhancer.setCallbackFilter(callbackHelper);
        enhancer.setCallbacks(callbackHelper.getCallbacks());
        // jobsManager is proxified class object
        JobsManager jobsManager = (JobsManager) enhancer.create();
        // jobs list will not equal with proxy method call
        Assert.assertNotEquals(new JobsManager().getAllJobs().get(0), jobsManager.getAllJobs().get(0));
        // jobs count will be equal with proxy method call
        Assert.assertEquals(new JobsManager().getCount(), jobsManager.getCount());
        // here both should be true.
        Assert.assertEquals(true, jobsManager.createJob("job4"));
    }
}

CallBackHelper is one of the implementation of CallBackFilter provided by CGLIB.

There are other callbacks which are introduced for simplicity and performance :


  • FixedValue : It is useful to force a particular method to return a fixed value for performance reasons.
  • NoOp  : It delegates method invocations directly to the default implementations in the super class.
  • LazyLoader : It is useful when the real object needs to be lazily loaded. Once the real object is loaded, it is used for every future method call to the proxy instance.
  • Dispatcher : It has the same signatures as LazyLoader, but the loadObject method is always called when a proxy method is invoked.
  • ProxyRefDispatcher : It is the same as Dispatcher, but it allows the proxy object to be passed in as an argument of the loadObject method.


You can download source @ GitHub.