1/*
2 * Copyright 2001-2009 OFFIS, Tammo Freese
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.easymock.internal;
17
18import java.io.IOException;
19import java.io.Serializable;
20import java.lang.reflect.InvocationHandler;
21import java.lang.reflect.Method;
22import java.lang.reflect.Proxy;
23
24public class ObjectMethodsFilter implements InvocationHandler, Serializable {
25
26    private static final long serialVersionUID = -2120581954279966998L;
27
28    private transient Method equalsMethod;
29
30    private transient Method hashCodeMethod;
31
32    private transient Method toStringMethod;
33
34    private final MockInvocationHandler delegate;
35
36    private final String name;
37
38    public ObjectMethodsFilter(Class<?> toMock, MockInvocationHandler delegate,
39            String name) {
40        if (name != null && !Invocation.isJavaIdentifier(name)) {
41            throw new IllegalArgumentException(String.format("'%s' is not a valid Java identifier.", name));
42
43        }
44        try {
45            if (toMock.isInterface()) {
46                toMock = Object.class;
47            }
48            equalsMethod = toMock.getMethod("equals",
49                    new Class[] { Object.class });
50            hashCodeMethod = toMock.getMethod("hashCode", (Class[]) null);
51            toStringMethod = toMock.getMethod("toString", (Class[]) null);
52        } catch (NoSuchMethodException e) {
53            // ///CLOVER:OFF
54            throw new RuntimeException("An Object method could not be found!");
55            // ///CLOVER:ON
56        }
57        this.delegate = delegate;
58        this.name = name;
59    }
60
61    public final Object invoke(Object proxy, Method method, Object[] args)
62            throws Throwable {
63        if (equalsMethod.equals(method)) {
64            return Boolean.valueOf(proxy == args[0]);
65        }
66        if (hashCodeMethod.equals(method)) {
67            return Integer.valueOf(System.identityHashCode(proxy));
68        }
69        if (toStringMethod.equals(method)) {
70            return mockToString(proxy);
71        }
72        return delegate.invoke(proxy, method, args);
73    }
74
75    private String mockToString(Object proxy) {
76        return (name != null) ? name : "EasyMock for " + mockType(proxy);
77    }
78
79    private String mockType(Object proxy) {
80        if (Proxy.isProxyClass(proxy.getClass()))
81            return proxy.getClass().getInterfaces()[0].toString();
82        else
83            return proxy.getClass().getSuperclass().toString();
84    }
85
86    public MockInvocationHandler getDelegate() {
87        return delegate;
88    }
89
90    private void readObject(java.io.ObjectInputStream stream) throws IOException, ClassNotFoundException {
91        stream.defaultReadObject();
92        try {
93            toStringMethod = ((MethodSerializationWrapper) stream.readObject()).getMethod();
94            equalsMethod = ((MethodSerializationWrapper) stream.readObject()).getMethod();
95            hashCodeMethod = ((MethodSerializationWrapper) stream.readObject()).getMethod();
96        } catch (NoSuchMethodException e) {
97            // ///CLOVER:OFF
98            throw new IOException(e.toString());
99            // ///CLOVER:ON
100        }
101    }
102
103    private void writeObject(java.io.ObjectOutputStream stream) throws IOException {
104        stream.defaultWriteObject();
105        stream.writeObject(new MethodSerializationWrapper(toStringMethod));
106        stream.writeObject(new MethodSerializationWrapper(equalsMethod));
107        stream.writeObject(new MethodSerializationWrapper(hashCodeMethod));
108    }
109}