001 /* 002 * (c) 2003-2005, 2009, 2010 ThoughtWorks Ltd 003 * All rights reserved. 004 * 005 * The software in this package is published under the terms of the BSD 006 * style license a copy of which has been included with this distribution in 007 * the LICENSE.txt file. 008 * 009 * Created on 14-May-2004 010 */ 011 package com.thoughtworks.proxy.toys.nullobject; 012 013 import java.io.IOException; 014 import java.io.NotSerializableException; 015 import java.io.ObjectOutputStream; 016 import java.io.Serializable; 017 import java.lang.reflect.Method; 018 019 import com.thoughtworks.proxy.Invoker; 020 import com.thoughtworks.proxy.ProxyFactory; 021 import com.thoughtworks.proxy.kit.ReflectionUtils; 022 023 024 /** 025 * A {@link Invoker} implementation that returns always new Null objects. 026 * 027 * @author Dan North 028 * @since 0.1 029 */ 030 public class NullInvoker implements Invoker { 031 private static final long serialVersionUID = -4713875509846468548L; 032 private static final Method toString; 033 034 static { 035 try { 036 toString = Object.class.getMethod("toString", new Class[0]); 037 } catch (NoSuchMethodException e) { 038 throw new ExceptionInInitializerError(e.toString()); 039 } 040 } 041 042 private Class<?> type; 043 private ProxyFactory proxyFactory; 044 045 /** 046 * Construct a NullInvoker. 047 * 048 * @param type the type of the proxy 049 * @param proxyFactory the {@link ProxyFactory} to use 050 * @since 0.1 051 */ 052 public NullInvoker(final Class<?> type, final ProxyFactory proxyFactory) { 053 this.type = type; 054 this.proxyFactory = proxyFactory; 055 } 056 057 public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable { 058 Object result; 059 060 // Object methods 061 if (toString.equals(method)) { 062 result = "Null Object for " + type.getName(); 063 } else if (ReflectionUtils.equals.equals(method)) { 064 Object other = args[0]; 065 result = (Null.isNullObject(other, proxyFactory) && type.equals(getType(other))); 066 } else if (ReflectionUtils.hashCode.equals(method)) { 067 result = type.hashCode(); 068 } 069 070 // Just another null object 071 else { 072 result = Null.proxy(method.getReturnType()).build(proxyFactory); 073 } 074 return result; 075 } 076 077 private Class<?> getType(Object object) { 078 final Class<?> result; 079 if (proxyFactory.isProxyClass(object.getClass())) { 080 NullInvoker nullInvoker = NullInvoker.class.cast(proxyFactory.getInvoker(object)); 081 result = nullInvoker.type; 082 } else { 083 result = object.getClass(); 084 } 085 return result; 086 } 087 088 // Serialization 089 090 private void writeObject(ObjectOutputStream out) throws IOException { 091 if (!nullObjectIsSerializable()) { 092 throw new NotSerializableException(type.getName()); 093 } 094 out.defaultWriteObject(); 095 } 096 097 private boolean nullObjectIsSerializable() { 098 return Serializable.class.isAssignableFrom(type); 099 } 100 }