Home > Reflection and Generics > Dynamic proxies for classes

Dynamic proxies for classes

If you have made your hobby a job, like I did, you have possibly seen your hobby die just like me. Because when you come home from work, you are likely to have seen enough code for a day. In such a situation a “be your own boss day” can be a delightful experience. Twice a year my company pays me a whole day to do whatever I like to do, given that I will report what I did. In the course of the past years, they say, the company has seen some interesting projects. I chose to devote some time to enhance my knowledge about the Java technology; more precisely I finally found the time to crack a nut that has been bugging me ever since I wrote the blog “Reflection without Strings”, more than two years ago: Dynamic Proxies for classes.
To my advantage people have accomplished this before. If you use Google, you are likely to find some solutions using CGLib, Javassist or XML-infested AOP-frameworks. Unfortunately all of them lack one tiny detail: How will you create a new proxy instance of a class that has no default constructor, when you don’t have a clue which objects that constructor needs? Which constructor should you chose if there are many? Can the chosen constructor cope with “null” references or empty Strings? In the utility I developed in the Reflection without Strings blog, I don’t even need any functionality of the class behind the proxy; I just need its signature.

A basic proxy for classes

In my example code I’m using cglib (cglib-nodep-2.2.3.jar), you can grab it at: http://sourceforge.net/projects/cglib/files/
Just add it to your class path and everything should work as expected.
GCLib actually makes it very easy to create a proxy for a class.
Let’s first write a class that we like to create a proxy for:

public class Foo {
	private final String str;

	public Foo(final String str) {
		this.str = str;
	}

	@Override
	public String toString() {
		return str;
	}
}

Creating a Proxy is pretty easy at a first glance:

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import org.objenesis.ObjenesisHelper;

import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.Factory;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
	@SuppressWarnings("unchecked")
	private static <T> T createProxy(final Class<Foo> classToMock,
			final Class[]  paramTypes,
			final Object[] params,
			final MethodInterceptor interceptor) 
			throws InstantiationException, IllegalAccessException, 
				InvocationTargetException, NoSuchMethodException {

		final Enhancer enhancer = new Enhancer();
		enhancer.setSuperclass(classToMock);
		enhancer.setCallback(interceptor);
		
		return (T) enhancer.create(paramTypes, params);
	}
	//...		
 }

However, we have a problem here: We need to know how the constructor of the class looks like, since when cglib tries to create a new instance of the proxy, it needs to initialize the super type of the proxy accordingly. For mocking frameworks this is not convenient.

Bypassing the constructor

The problem with having to use the proper parameters and signature of proxy’s super class is to know which parameters it accepts: It could reject null or zero parameters or require a type that we cannot obtain, because it is created by some factory that is hidden from our view. We can’t just simply assume some default works. And if the class has several constructors there is no method to automatically detect which one is the best one to use. Instead an easy way to solve that problem is to do what serialization frameworks do: Bypass the constructor.
There are several ways to do create an object of a class bypassing the constructor.
Let’s first take a rather unsafe route:

import sun.reflect.ReflectionFactory;
	@SuppressWarnings("restriction")
	public static <T> T newInstance(final Class<T> clazz) {
		try {
			final Constructor<?> constructor 
				= ReflectionFactory.getReflectionFactory()
					.newConstructorForSerialization(
						clazz, Object.class.getDeclaredConstructor());
			return clazz.cast(constructor.newInstance());
		} catch (NoSuchMethodException e) {
			throw new UnsupportedOperationException(e);
		} catch (InstantiationException e) {
			throw new UnsupportedOperationException(e);
		} catch (IllegalAccessException e) {
			throw new IllegalStateException(e);
		} catch (InvocationTargetException e) {
			throw new IllegalStateException(e);
		}
	}

Be careful! Note that we’re using a class from the “sun.” package, which may not be present in your favorite Java Runtime Environment implementation.
To make this work, we also need to change the method that creates our proxy:

	@SuppressWarnings("unchecked")
	private static <T> T createProxy(final Class<Foo> classToMock,
			final MethodInterceptor interceptor) {
		final Enhancer enhancer = new Enhancer();
		enhancer.setSuperclass(classToMock);
		enhancer.setCallbackType(interceptor.getClass());

		final Class<?> proxyClass = enhancer.createClass();
		Enhancer.registerCallbacks(proxyClass, new Callback[] { interceptor });
		return (T) newInstance(proxyClass);
	}

As you can see, creating the proxy has become a tad different, but it still looks like an easy thing to do.
There is a safer way to bypass the constructor though: Objenesis.
Objenesis is a framework designed especially for object instantiation, made by some folks at Google: http://code.google.com/p/objenesis/
For this example I’m using the Objenesis 1.2 Bundle (objenesis-1.2-bin.zip) and adding it to my class path. Everything that changes is the last line of our proxy-creation method and an import statement.

import org.objenesis.ObjenesisHelper;
//...
	@SuppressWarnings("unchecked")
	private static <T> T createProxy(final Class<Foo> classToMock,
			final MethodInterceptor interceptor) {
		//...
		return (T) ObjenesisHelper.newInstance(proxyClass);	
	}

Yes, it looks kind of wasteful to import a whole library just for a simple object instantiation, but if you have a look at the code behind it, it gets clear that you will gain a lot of compatibility with several Java Runtime Environment versions and implementations, which should be worth it.

Using the proxy

Before I’m posting the whole source code, let me briefly demonstrate how the method is used:

public static void main(final String[] args) {

	final MethodInterceptor withHashCodeAlwaysNull = new MethodInterceptor() {
		@Override
		public Object intercept(final Object object, final Method method,
				final Object[] args, final MethodProxy methodProxy)
				throws Throwable {
			if ("hashCode".equals(method.getName())) {
				return 0;
			}
			return methodProxy.invokeSuper(object, args);
		}
	};
	final Foo proxy = createProxy(Foo.class, withHashCodeAlwaysNull);
	System.out.println(proxy.hashCode()); //prints "0"
 }

As you can see, you don’t need any parameter for the constructor of the class “Foo”, even though it, unlike Java beans, only has one “Foo(String s){..}” constructor and no default.

Putting it all together

So here is the complete code for this example. Feel free to use it as you wish:

public class Foo {
	private final String str;

	public Foo(final String str) {
		this.str = str;
	}

	@Override
	public String toString() {
		return str;
	}
}
import java.lang.reflect.Method;

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

import org.objenesis.ObjenesisHelper;

public class ProxyPlayground {

	public static void main(final String[] args) {

		final MethodInterceptor hashCodeAlwaysNull = new MethodInterceptor() {

			@Override
			public Object intercept(final Object object, final Method method,
					final Object[] args, final MethodProxy methodProxy)
					throws Throwable {
				if ("hashCode".equals(method.getName())) {
					return 0;
				}
				return methodProxy.invokeSuper(object, args);
			}
		};
		final Foo proxy = createProxy(Foo.class, hashCodeAlwaysNull);
		System.out.println(proxy.hashCode()); // prints 0

	}

	@SuppressWarnings("unchecked")
	private static <T> T createProxy(final Class<Foo> classToMock,
			final MethodInterceptor interceptor) {
		final Enhancer enhancer = new Enhancer();
		enhancer.setSuperclass(classToMock);
		enhancer.setCallbackType(interceptor.getClass());

		final Class<?> proxyClass = enhancer.createClass();
		Enhancer.registerCallbacks(proxyClass, new Callback[] { interceptor });
		return (T) ObjenesisHelper.newInstance(proxyClass);
	}
}

What’s next? Well, I think I should start to include that code in my utility class from the Reflection without Strings blog, but there is still one thing that bugs me: final classes.
I’m sure there must be a way to create a proxy for final classes too.

About these ads
  1. John
    November 26, 2013 at 21:53

    It is not possible to create proxies for final classes. There is a way around that though – you can remove the final modifier (from both classes (including inner classes) and methods) using bytecode instrumentataion. If you create a javaagent that does this instrumentation, you can pretty much proxy anything…

  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 42 other followers

%d bloggers like this: