Core Java

Creating a proxy object using cglib

In the previous post I was talking about the standard Java based proxy objects. These can be used when you want to have a method invocation handler on an object that implements an interface. The Java reflection proxy creation demands that you have an object that implements the interface. The object we want to proxy is out of our hand, it does not implement the interface that we want to invoke from our handler and still we want to have a proxy.

When do we need proxy to objects w/o interface?

This is a very common case. If ever we have a JPA implementation e.g. Hibernate that implements lazy loading of the records. For example the audit log records are stored in a table and each record, except the first one has a reference to the previous item. Something like

class LinkedAuditLogRecord {
  LinkedAuditLogRecord previous;
  AuditLogRecord actualRecord;
}

Loading a record via JPA will return an object LinkedAuditLogRecord which contains the previous record as an object and so on until the first one that probably has null in the field named previos. (This is not an actual code.) Any JPA implementation grabbing and loading the whole table from the start to the record of our interest would be an extremely poor implementation. Instead the persistence layer loads the actual record only and creates a proxy object extending LinkedAuditLogRecord and that is what the field previous is going to be. The actual fields are usually private fields and if ever our code tries to access the previous record the proxy object will load it that time. This is lazy loading in short.

But how do the JPA implementations create proxies to objects of classes that do not implement interfaces? Java reflection proxy implementation can not do that and thus JPA implementation uses something different. What they usually use is cglib.

What is cglib

Cglib is an open source library that capable creating and loading class files in memory during Java run time. To do that it uses Java byte-code generation library ‘asm’, which is a very low level byte code creation tool. I will not dig that deep in this article.

How to use cglib

To create a proxy object using cglib is almost as simple as using the JDK reflection proxy API. I created the same code as the last week article, this time using cglib:

package proxy;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class CglibProxyDemo {

    static class Original {
        public void originalMethod(String s) {
            System.out.println(s);
        }
    }

    static class Handler implements MethodInterceptor {
        private final Original original;

        public Handler(Original original) {
            this.original = original;
        }

        public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
            System.out.println("BEFORE");
            method.invoke(original, args);
            System.out.println("AFTER");
            return null;
        }
    }

    public static void main(String[] args){
        Original original = new Original();
        MethodInterceptor handler = new Handler(original);
        Original f = (Original) Enhancer.create(Original.class,handler);
        f.originalMethod("Hallo");
    }
}

The difference is that name of the classes are a bit different and we do not have an interface.

It is also important that the proxy class extends the original class and thus when the proxy object is created it invokes the constructor of the original class. In case this is resource hungry we may have some issue with that. However this is something that we can not circumvent. If we want to have a proxy object to an already existing class then we should have either an interface or we have to extend the original class, otherwise we just could not use the proxy object in place of the original one.

Reference: Creating a proxy object using cglib from our JCG partner Peter Verhas at the Java Deep blog.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button