Brian's Waste of Time

Mon, 23 Aug 2004

Picocontainer Null Object Builder

Charles Miller pointed out that passing null instead of a null object would just as happily generate an exception. I like to be explicit though, especially when cheating and purposefully not providing a component implementation. As promised in the comments, here is a much fancier null component builder (and testcase) than you'll ever really need ;-)

package org.skife.picotools;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class NC
{
    private static class NCHandler implements InvocationHandler
    {
        private final Class iface;

        NCHandler(final Class iface)
        {
            this.iface = iface;
        }

        public Object invoke(final Object proxy,
                             final Method method,
                             final Object[] args) throws Throwable
        {
            final StringBuffer signature = new StringBuffer();
            signature.append(method.getDeclaringClass().getName()).append("#");
            signature.append(method.getName()).append("(");
            final Class[] params = method.getParameterTypes();
            for (int i = 0; i != params.length; i++)
            {
                final Class param = params[i];
                signature.append(param.getName());
                if (i != params.length - 1) signature.append(", ");
            }
            signature.append("): ")
                    .append(method.getReturnType().getName())
                    .append("]");
            throw new IllegalStateException(new StringBuffer()
                                            .append("Invoked method [")
                                            .append(signature.toString())
                                            .append(" on null component implementing [")
                                            .append(iface.getName())
                                            .append("]").toString());
        }
    };

    public static Object build(final Class iface)
    {
        return Proxy.newProxyInstance(iface.getClassLoader(),
                                      new Class[]{iface},
                                      new NCHandler(iface));
    }
}



package org.skife.picotools;

import java.util.Map;
import junit.framework.TestCase;

public class NCTest extends TestCase {
    public void testThing() {
        final Map null_map = (Map) NC.build(Map.class);
        try {
            null_map.put("key", "value");
            fail("Should have thrown excpetion");
        } catch (IllegalStateException e) {
            assertTrue("Go through here", true);
        }
    }
}

Exception message will look like Invoked method [java.util.Map#put(java.lang.Object, java.lang.Object): java.lang.Object] on null component implementing [java.util.Map]

Easy, and the error is much more explicit than a null pointer exception. Admittedly, (WombatDAO)NC.build(WombatDAO.class) is 21 keystrokes more than (WombatDAO)null but we are using Java here, not Perl =)

2 writebacks [/src/java] permanent link