|
|
||||||||||||||||||||||||||||||||||||||||||||||||
In Rickard's recent entry he discusses a technique whereby abstract classes can implement an arbitrary set of interfaces, the missing implementations of which are "filled in" by his AOP framework.
I've done something very similar with CGLIB
for my own Mock Object needs. Let's say you need a mock
HttpServletRequest. Actually implementing one is pain,
since it has so many methods and you probably only care about one or two
for a given test, for example:
abstract public class MockRequest implements HttpServletRequest { public String getRequestURI() { return "/foo"; } }
The trick is how to get an instance of MockRequest (you cannot
instantiate one directly since it is abstract):
request = (HttpServletRequest)makeMock(MockRequest.class);
Here is the code for makeMock (using CGLIB2):
public static Object makeMock(Class impl) { return Enhancer.create(impl, null, NoOp.INSTANCE); }
The CGLIB Enhancer API generates a dynamic subclass
and implements all of the missing interface methods. Any method that you
do not implement will simply throw an AbstractMethodError when called.
The advantage of using CGLIB here instead of Dynamic Proxies (besides performance) is that you are not limited to interfaces--you can just as easily create a mock for any class:
abstract public class MockImage extends java.awt.Image { public int getHeight(java.awt.ImageObserver observer) { return 480; } public int getWidth(java.awt.ImageObserver observer) { return 640; } }