KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > easymock > classextension > internal > ClassProxyFactory


1 /*
2  * Copyright (c) 2001-2004 OFFIS. This program is made available under the terms of
3  * the MIT License.
4  */

5 package org.easymock.classextension.internal;
6
7 import java.lang.reflect.Field JavaDoc;
8 import java.lang.reflect.InvocationHandler JavaDoc;
9 import java.lang.reflect.Method JavaDoc;
10 import java.util.Arrays JavaDoc;
11 import java.util.HashSet JavaDoc;
12 import java.util.List JavaDoc;
13 import java.util.Set JavaDoc;
14
15 import net.sf.cglib.core.CollectionUtils;
16 import net.sf.cglib.core.VisibilityPredicate;
17 import net.sf.cglib.proxy.Callback;
18 import net.sf.cglib.proxy.Enhancer;
19 import net.sf.cglib.proxy.MethodInterceptor;
20 import net.sf.cglib.proxy.MethodProxy;
21
22 import org.easymock.internal.IProxyFactory;
23 import org.easymock.internal.ObjectMethodsFilter;
24
25 /**
26  * Factory generating a mock for a class.
27  * <p>
28  * Note that this class is stateful
29  */

30 public class ClassProxyFactory implements IProxyFactory {
31
32     private Set JavaDoc mockedMethods;
33
34     /**
35      * Create a factory with an array of methods to be mocked on the mocks to be
36      * created.
37      *
38      * @param mockedMethods
39      * methods to be mocked. If null, all methods will be mocked.
40      */

41     public ClassProxyFactory(Method JavaDoc[] mockedMethods) {
42         this.mockedMethods = (mockedMethods == null ? null : new HashSet JavaDoc(Arrays
43                 .asList(mockedMethods)));
44     }
45
46     public Object JavaDoc createProxy(Class JavaDoc toMock, final InvocationHandler JavaDoc handler) {
47
48         // Dirty trick to fix ObjectMethodsFilter
49
// It will replace the equals, hashCode, toString methods it kept that
50
// are the ones
51
// from Object.class by the correct ones since they might have been
52
// overloaded
53
// in the mocked class.
54
try {
55             updateMethod(handler, toMock.getMethod("equals",
56                     new Class JavaDoc[] { Object JavaDoc.class }));
57             updateMethod(handler, toMock.getMethod("hashCode", new Class JavaDoc[0]));
58             updateMethod(handler, toMock.getMethod("toString", new Class JavaDoc[0]));
59         } catch (NoSuchMethodException JavaDoc e) {
60             // ///CLOVER:OFF
61
throw new InternalError JavaDoc(
62                     "We strangly failed to retrieve methods that always exist on an object...");
63             // ///CLOVER:ON
64
}
65
66         MethodInterceptor interceptor = new MethodInterceptor() {
67             public Object JavaDoc intercept(Object JavaDoc obj, Method JavaDoc method, Object JavaDoc[] args,
68                     MethodProxy proxy) throws Throwable JavaDoc {
69                 if (mockedMethods != null && !mockedMethods.contains(method)) {
70                     return proxy.invokeSuper(obj, args);
71                 }
72                 return handler.invoke(obj, method, args);
73             }
74         };
75
76         // Create the mock
77
Enhancer enhancer = new Enhancer() {
78             /**
79              * Filter all private constructors but do not check that there are
80              * some left
81              */

82             protected void filterConstructors(Class JavaDoc sc, List JavaDoc constructors) {
83                 CollectionUtils.filter(constructors, new VisibilityPredicate(
84                         sc, true));
85             }
86         };
87         enhancer.setSuperclass(toMock);
88         enhancer.setCallbackType(interceptor.getClass());
89         // no need to implement the factory interface
90
// and implementing it prevents ObjectMethodFilter to provide a nice
91
// toString()
92
enhancer.setUseFactory(false);
93         // do not use cache to prevent having the same class since we
94
// are registering the callback for a given class and a callback
95
// must be used by only one mock instance (they are stateful)
96
enhancer.setUseCache(false);
97
98         Class JavaDoc mock = enhancer.createClass();
99         Enhancer.registerCallbacks(mock, new Callback[] { interceptor });
100         try {
101             return ClassInstantiatorFactory.getInstantiator().newInstance(mock);
102         } catch (InstantiationException JavaDoc e) {
103             // ///CLOVER:OFF
104
throw new RuntimeException JavaDoc("Fail to instantiate mock for " + toMock
105                     + " on " + ClassInstantiatorFactory.getJVM() + " JVM");
106             // ///CLOVER:ON
107
}
108     }
109
110     private void updateMethod(InvocationHandler JavaDoc objectMethodsFilter,
111             Method JavaDoc correctMethod) {
112         Field JavaDoc methodField = retrieveField(ObjectMethodsFilter.class,
113                 correctMethod.getName() + "Method");
114         updateField(objectMethodsFilter, correctMethod, methodField);
115     }
116
117     private Field JavaDoc retrieveField(Class JavaDoc clazz, String JavaDoc field) {
118         try {
119             return clazz.getDeclaredField(field);
120         } catch (NoSuchFieldException JavaDoc e) {
121             // ///CLOVER:OFF
122
throw new InternalError JavaDoc(
123                     "There must be some refactoring because the " + field
124                             + " field was there...");
125             // ///CLOVER:ON
126
}
127     }
128
129     private void updateField(Object JavaDoc instance, Object JavaDoc value, Field JavaDoc field) {
130         boolean accessible = field.isAccessible();
131         field.setAccessible(true);
132         try {
133             field.set(instance, value);
134         } catch (IllegalAccessException JavaDoc e) {
135             // ///CLOVER:OFF
136
throw new InternalError JavaDoc(
137                     "Should be accessible since we set it ourselves");
138             // ///CLOVER:ON
139
}
140         field.setAccessible(accessible);
141     }
142 }
Popular Tags