Monday, August 22, 2011

The Builder and Null Object pattern meet the Java Proxy class

I love the Null Object pattern. It is a simple and useful pattern in many situations. The archetypal example is in the context of JUnit tests (or whatever is your favourite testing framework). In unit tests, Mock objects are often little more than Null Objects. Obviously, there are very good libraries for mocking objects in unit tests and I guess I could use this for Null objects in regular code but that would bring a lot of dead code into my application since those libraries provide some pretty fancy features. I need something simpler.
I have used the Java dynamic java.lang.reflect.Proxy class for things like debugging proxy and other applications so I though using this class for Null Object would be great (if you need a refresher on Java Dynamic Proxy check Explore the Dynamic Proxy API). In fact since a Null object has only one immutable state you only have to worry about the return value of its method. I want to keep this simple so what I will do is I will use two Map(s) in my proxy handler: one with return types for keys (Class) and one with method names for keys (String). This will allow me to define return value for different return types and return values for different method names. This implementation does not support having different return value for methods with the same name and different parameters (overloaded methods). This should not be a big limitation since a Null object is likely to return the same value in this case. Here are the declarations for my Map(s):
The returnTypeLookup must include values for primitive types since methods that return those cannot default to null. As a bonus the Map includes a consistent set of values for primitive wrapper classes.
The code below shows how the Map(s) are used in the invoke method of my handler:
As you can see we first check if there is a custom return value for the invoked method name and then we check if there is a custom value for the return type. This makes it possible to handle most common cases where you want to override the default.
Now how can we customize our Proxy ? We could use different constructors for our invocation handler or some extra methods to override values. I have considered several options and finally I think I have found a very elegant solution. Here is what creating a Null object using my API looks like:

ISomeInterface r = 
	NullObjectProxy.newInstance (ISomeInterface.class)
		.whenReturnType (boolean.class, true)
		.whenMethodName ("someMethodName", new SomeUserDefinedType())
		.build ();
To achieve this I use a generic Factory method and a Builder class.In my next post I will show you how to define a class that can be used with such a flexible and programmer friendly syntax.


1 comment:

  1. If you are not familiar with the NullObject Pattern check the short definition on Wikipedia.

    ReplyDelete