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 }