http://alexwinston.com/blog/2004/03/23/1080068110000.html
for those that are familiar with aop will have most certainly heard of cglib. for those that have not, cglib provides the ability instrument bytecode programmatically. it uses asm for the heavy lifting, and provides a simple interface to extend any non-final class as well as implement interfaces at runtime. i myself am rather new to cglib and cglib2 and have found examples rather lacking so i have decided to put together an example that concisely shows all of the power of cglib2's proxying prowess. if anyone finds this useful i might put together additional tutorials as well. please feel free to submit feedback.
unfortunately the cglib website does not do a very good job of selling the power of it's library. the documentation is scarce, the examples are thin, and i was is left scratching my head as to exactly how to utilize this powerful tool. fortunately the test cases are rather complete so after digging around i was able to piece together almost all of the proxying power of cglib. the example below will begin with several simple classes that we can either extend of implement with cglib -- below i will outline how to intercept methods, add mixins, and make proxies "aware" with the cglib Enhancer.
first we start with several simple interfaces Foo, Bar, and FooBar.
public interface Foo {
public void foo();
}
public interface Bar {
public void bar();
}
public interface FooBar extends Foo, Bar {
}
next we provide very simple implementations of the Foo and Bar interfaces.
import java.io.Serializable;
public class FooImpl implements Foo, Serializable {
public void foo() {
System.out.println("foo");
}
}
import java.io.Serializable;
public class BarImpl implements Bar, Serializable {
public void bar() {
System.out.println("bar");
}
}
next we provide a simple interceptor implementation to log method calls.
public class LoggingInterceptor implements MethodInterceptor {
public Object intercept(Object obj, Method method,
Object[] args, MethodProxy proxy) throws Throwable {
try {
System.out.println("before " + method);
return proxy.invokeSuper(obj, args);
} finally {
System.out.println("after " + method);
}
}
}
once this is done we can instruct cglib to enhance our classes accordingly. the first example shows how we can extend the superclass FooImpl by implementing the Bar interface and dispatch to the implementation and intercepting method calls. you will also notice that we are instructing cglib to implement the FooBar interface -- the purpose is to consolidate our interfaces into one "aware" interface so we do not have to cast to each interface cglib implemented for us.
public void testExtendingSuperclass() throws Exception {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(FooImpl.class);
enhancer.setInterfaces(new Class[] { Bar.class, FooBar.class });
enhancer.setCallbackTypes(new Class[] {
Dispatcher.class, MethodInterceptor.class });
enhancer.setCallbackFilter(new CallbackFilter() {
public int accept(Method method) {
if (Bar.class.isAssignableFrom(method.getDeclaringClass()))
return 0;
else
return 1;
}
});
Class clazz = enhancer.createClass();
enhancer.registerCallbacks(clazz, new Callback[] {
new Dispatcher() {
public Object loadObject() {
return Enhancer.create(BarImpl.class,
new LoggingInterceptor());
}
},
new LoggingInterceptor()
});
FooBar foobar = (FooBar) clazz.newInstance();
foobar.foo();
foobar.bar();
}
the next example shows how we can have cglib create a new Class for us without extending a superclass. in this example we are dispatching to all the implementation that cglib has implemented for us.
public void testNoSuperclass() throws Exception {
Enhancer enhancer = new Enhancer();
enhancer.setInterfaces(new Class[] {
Foo.class, Bar.class, FooBar.class });
enhancer.setCallbackTypes(new Class[] {
Dispatcher.class, Dispatcher.class });
enhancer.setCallbackFilter(new CallbackFilter() {
public int accept(Method method) {
return Foo.class.isAssignableFrom(
method.getDeclaringClass()) ? 0 : 1;
}
});
/*
enhancer.setStrategy(new DefaultGeneratorStrategy() {
protected byte[] transform(byte[] b) {
try {
FileOutputStream fos =
new FileOutputStream("build/Cglib2Generated.class");
fos.write(b);
} catch (Exception e) {
e.printStackTrace();
}
return b;
}
});
*/
Class clazz = enhancer.createClass();
enhancer.registerCallbacks(clazz, new Callback[] {
new Dispatcher() {
public Object loadObject() {
return Enhancer.create(FooImpl.class,
new LoggingInterceptor());
}
},
new Dispatcher() {
public Object loadObject() {
return Enhancer.create(BarImpl.class,
new LoggingInterceptor());
}
}
});
FooBar foobar = (FooBar) clazz.newInstance();
foobar.foo();
foobar.bar();
}
with these simple examples we are on our way to fully utilizing the power of cglib proxies. you may also notice that i have commented out setting the strategy in the second example. this is a very powerful undocumented feature that allows us to directly access the byte[] of our proxy. i hope this provides some valuable insight into how you can use cglib to it's fullest.