KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2  * Copyright (c) 2003-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.io.ByteArrayInputStream JavaDoc;
8 import java.io.ByteArrayOutputStream JavaDoc;
9 import java.io.DataOutputStream JavaDoc;
10 import java.io.IOException JavaDoc;
11 import java.io.ObjectInputStream JavaDoc;
12 import java.io.ObjectStreamClass JavaDoc;
13 import java.io.ObjectStreamConstants JavaDoc;
14 import java.io.Serializable JavaDoc;
15 import java.lang.reflect.Constructor JavaDoc;
16 import java.lang.reflect.Field JavaDoc;
17 import java.lang.reflect.InvocationTargetException JavaDoc;
18 import java.lang.reflect.Method JavaDoc;
19 import java.lang.reflect.Modifier JavaDoc;
20
21 import org.easymock.MockControl;
22 import org.easymock.classextension.MockClassControl;
23 import org.easymock.internal.RecordState;
24
25 /**
26  * Default class instantiator that is pretty limited. It just hope that the
27  * mocked class has a public empty constructor.
28  */

29 public class DefaultClassInstantiator implements IClassInstantiator {
30
31     /**
32      * Try to instantiate a class without using a special constructor. See
33      * documentation for the algorithm.
34      *
35      * @param c
36      * Class to instantiate
37      */

38     public Object JavaDoc newInstance(Class JavaDoc c) throws InstantiationException JavaDoc {
39
40         if (isSerializable(c)) {
41             try {
42                 return readObject(getSerializedBytes(c));
43                 // ///CLOVER:OFF
44
} catch (IOException JavaDoc e) {
45                 throw new RuntimeException JavaDoc("Failed to instantiate "
46                         + c.getName() + "'s mock: " + e.getMessage());
47             } catch (ClassNotFoundException JavaDoc e) {
48                 throw new RuntimeException JavaDoc("Failed to instantiate "
49                         + c.getName() + "'s mock: " + e.getMessage());
50             }
51             // ///CLOVER:ON
52
}
53
54         Constructor JavaDoc constructor = getConstructorToUse(c);
55         Object JavaDoc[] params = getArgsForTypes(constructor.getParameterTypes());
56         try {
57             return constructor.newInstance(params);
58             // ///CLOVER:OFF
59
} catch (IllegalArgumentException JavaDoc e) {
60             throw new RuntimeException JavaDoc("Failed to instantiate " + c.getName()
61                     + "'s mock: " + e.getMessage());
62         } catch (IllegalAccessException JavaDoc e) {
63             throw new RuntimeException JavaDoc("Failed to instantiate " + c.getName()
64                     + "'s mock: " + e.getMessage());
65             // ///CLOVER:ON
66
} catch (InvocationTargetException JavaDoc e) {
67             throw new RuntimeException JavaDoc("Failed to instantiate " + c.getName()
68                     + "'s mock: " + e.getMessage());
69         }
70     }
71
72     /**
73      * Tells if the provided class is serializable
74      *
75      * @param clazz
76      * Class to check
77      * @return If the class is serializable
78      */

79     private boolean isSerializable(Class JavaDoc clazz) {
80         return Serializable JavaDoc.class.isAssignableFrom(clazz);
81     }
82
83     /**
84      * Return the constructor considered the best to use with this class.
85      * Algorithm is: No args constructor and then first constructor defined in
86      * the class
87      *
88      * @param clazz
89      * Class in which constructor is searched
90      * @return Constructor to use
91      */

92     private Constructor JavaDoc getConstructorToUse(Class JavaDoc clazz) {
93         // First try to use the empty constructor
94
try {
95             return clazz.getConstructor(new Class JavaDoc[0]);
96         } catch (NoSuchMethodException JavaDoc e) {
97             // If it fails just use the first one
98
if (clazz.getConstructors().length == 0) {
99                 throw new IllegalArgumentException JavaDoc(
100                         "No visible constructors in class " + clazz.getName());
101             }
102             return clazz.getConstructors()[0];
103         }
104     }
105
106     /**
107      * Get some default instances of provided classes
108      *
109      * @param methodTypes
110      * Classes to instantiate
111      * @return Instances of methodTypes in order
112      */

113     private Object JavaDoc[] getArgsForTypes(Class JavaDoc[] methodTypes)
114             throws InstantiationException JavaDoc {
115         Object JavaDoc[] methodArgs = new Object JavaDoc[methodTypes.length];
116
117         for (int i = 0; i < methodTypes.length; i++) {
118
119             if (methodTypes[i].isPrimitive()) {
120                 // Return a nice wrapped primitive type
121
methodArgs[i] = RecordState.emptyReturnValueFor(methodTypes[i]);
122             } else if (Modifier.isFinal(methodTypes[i].getModifiers())) {
123                 // Instantiate the class using the best constructor we can find
124
// (because it's not
125
// possible to mock a final class)
126
methodArgs[i] = newInstance(methodTypes[i]);
127             } else {
128                 // For all classes and interfaces, just return a nice mock
129
MockControl ctrl = MockClassControl
130                         .createNiceControl(methodTypes[i]);
131                 ctrl.replay();
132                 methodArgs[i] = ctrl.getMock();
133             }
134         }
135         return methodArgs;
136     }
137
138     private static byte[] getSerializedBytes(Class JavaDoc clazz) throws IOException JavaDoc {
139         ByteArrayOutputStream JavaDoc baos = new ByteArrayOutputStream JavaDoc();
140         DataOutputStream JavaDoc data = new DataOutputStream JavaDoc(baos);
141         data.writeShort(ObjectStreamConstants.STREAM_MAGIC);
142         data.writeShort(ObjectStreamConstants.STREAM_VERSION);
143         data.writeByte(ObjectStreamConstants.TC_OBJECT);
144         data.writeByte(ObjectStreamConstants.TC_CLASSDESC);
145         data.writeUTF(clazz.getName());
146
147         Long JavaDoc suid = getSerializableUID(clazz);
148
149         data.writeLong(suid.longValue());
150
151         data.writeByte(2); // classDescFlags (2 = Serializable)
152
data.writeShort(0); // field count
153
data.writeByte(ObjectStreamConstants.TC_ENDBLOCKDATA);
154         data.writeByte(ObjectStreamConstants.TC_NULL);
155         return baos.toByteArray();
156     }
157
158     private static Long JavaDoc getSerializableUID(Class JavaDoc clazz) {
159
160         try {
161             Field JavaDoc f = clazz.getDeclaredField("serialVersionUID");
162             final int mask = Modifier.STATIC | Modifier.FINAL;
163             if ((f.getModifiers() & mask) == mask) {
164                 f.setAccessible(true);
165                 return new Long JavaDoc(f.getLong(null));
166             }
167         } catch (NoSuchFieldException JavaDoc e) {
168             // It's not there, compute it then
169
} catch (IllegalAccessException JavaDoc e) {
170             // ///CLOVER:OFF
171
throw new RuntimeException JavaDoc(
172                     "Should have been able to get serialVersionUID since it's there");
173             // ///CLOVER:ON
174
}
175         // ///CLOVER:OFF
176
return callLongMethod(clazz, ClassInstantiatorFactory
177                 .is1_3Specifications() ? "computeSerialVersionUID"
178                 : "computeDefaultSUID");
179         // ///CLOVER:ON
180
}
181
182     private static Long JavaDoc callLongMethod(Class JavaDoc clazz, String JavaDoc methodName) {
183
184         Method JavaDoc method;
185         // ///CLOVER:OFF
186
try {
187             method = ObjectStreamClass JavaDoc.class.getDeclaredMethod(methodName,
188                     new Class JavaDoc[] { Class JavaDoc.class });
189         } catch (NoSuchMethodException JavaDoc e) {
190             throw new InternalError JavaDoc("ObjectStreamClass." + methodName
191                     + " seems to have vanished");
192         }
193         boolean accessible = method.isAccessible();
194         method.setAccessible(true);
195         Long JavaDoc suid;
196         try {
197             suid = (Long JavaDoc) method.invoke(null, new Object JavaDoc[] { clazz });
198         } catch (IllegalAccessException JavaDoc e) {
199             throw new InternalError JavaDoc("ObjectStreamClass." + methodName
200                     + " should have been accessible");
201         } catch (InvocationTargetException JavaDoc e) {
202             throw new InternalError JavaDoc("ObjectStreamClass." + methodName
203                     + " failled to be called: " + e.getMessage());
204         }
205         method.setAccessible(accessible);
206         // ///CLOVER:ON
207
return suid;
208     }
209
210     private static Object JavaDoc readObject(byte[] bytes) throws IOException JavaDoc,
211             ClassNotFoundException JavaDoc {
212         ObjectInputStream JavaDoc in = new ObjectInputStream JavaDoc(new ByteArrayInputStream JavaDoc(
213                 bytes));
214         return in.readObject();
215     }
216
217 }
218
Popular Tags