View Javadoc

1   // Copyright (c) 2003, Chad Woolley, All rights reserved.
2   
3   package org.virtualmock.call;
4   
5   /***
6    * The signature for a method call, representing the class, method name, and
7    * classes of the arguments.  It is NOT a unique identifier for a call, since
8    * multiple calls can be recorded for the same signature.
9    *
10   * @author Chad Woolley
11   * @version $Revision: 1.14 $
12   */
13  public class Signature {
14      private static final int LENGTH_OF_WORD_CLASS_PLUS_ONE_SPACE = 6;
15      private Class classType = null;
16      private Class returnType = null;
17      private String methodName = null;
18      private Class[] argTypes = null;
19  
20      /***
21       * Creates a new Signature object with a return value and arguments.
22       *
23       * @param returnType The type of the return value for this signature
24       * @param classType The type of the class which owns this signature
25       * @param methodName The name of the method for this signature
26       * @param argTypes Class array representing the argument types, or null if
27       *        there are no arguments.
28       */
29      public Signature(Class returnType, Class classType, String methodName,
30          Class[] argTypes) {
31          create(returnType, classType, methodName, argTypes);
32      }
33  
34      /***
35       * Creates a new Signature object with a return value but no arguments.
36       *
37       * @param returnType The type of the return value for this signature
38       * @param classType The type of the class which owns this signature
39       * @param methodName The name of the method for this signature
40       */
41      public Signature(Class returnType, Class classType, String methodName) {
42          create(returnType, classType, methodName, null);
43      }
44  
45      /***
46       * Creates a new Signature object with no return value but with arguments.
47       *
48       * @param classType The type of the class which owns this signature
49       * @param methodName The name of the method for this signature
50       * @param argTypes Class array representing the argument types, or null if
51       *        there are no arguments.
52       */
53      public Signature(Class classType, String methodName, Class[] argTypes) {
54          create(null, classType, methodName, argTypes);
55      }
56  
57      /***
58       * Creates a new Signature object with no return value or arguments.
59       *
60       * @param classType The type of the class which owns this signature
61       * @param methodName The name of the method for this signature
62       */
63      public Signature(Class classType, String methodName) {
64          create(null, classType, methodName, null);
65      }
66  
67      /***
68       * Accessor.
69       *
70       * @return An array of Class objects representing the argument types for
71       *         this signature, or an empty array if there are no arguments for
72       *         this signature.
73       */
74      public Class[] getArgTypes() {
75          return argTypes;
76      }
77  
78      /***
79       * <p>
80       * This method is similar to Java's Class.isAssignableFrom() method, but it
81       * checks the class type, method name and each individual argument type
82       * for this Signature.
83       * </p>
84       * 
85       * <p>
86       * To paraphrase the javadoc for Class.isAssignableFrom(): "Determines if
87       * all argument types contained in this Signature object are either the
88       * same as, or are superclasses or superinterfaces of, the argument types
89       * of the Signature represented by the specified call parameter. It
90       * returns true if so; otherwise it returns false. If the argument types
91       * of this Signature object represent primitive types, the method returns
92       * true if the specified argument types of the Signature parameter are
93       * exactly this Calls argument objects; otherwise it returns false."
94       * </p>
95       *
96       * @param signature the Signature which will be checked against this
97       *        Signature
98       *
99       * @return true if the passed Signature's method name and argument types
100      *         are assignable to this Signature
101      */
102     public boolean isAssignableFrom(Signature signature) {
103         // if the class type name doesn't match, return false
104         if (!classType.equals(signature.getClassType())) {
105             return false;
106         }
107 
108         // if the method name doesn't match, return false
109         if (!methodName.equals(signature.getMethodName())) {
110             return false;
111         }
112 
113         // if the argumentss don't have the same number of arguments, return false
114         if (argTypes.length != signature.getArgTypes().length) {
115             return false;
116         }
117 
118         // loop through all the argument types for this call
119         for (int i = 0; i < argTypes.length; i++) {
120             // return false if the passed Call's argument is not assignable
121             // to the corresponding argument for this call
122             if (!argTypes[i].isAssignableFrom(signature.getArgTypes()[i])) {
123                 return false;
124             }
125         }
126 
127         return true;
128     }
129 
130     /***
131      * Returns the name of the class type of this Signature.
132      *
133      * @return the name of the class type of this Signature
134      */
135     public String getClassName() {
136         return classType.getName();
137     }
138 
139     /***
140      * Accessor.
141      *
142      * @return the class type of this signature
143      */
144     public Class getClassType() {
145         return classType;
146     }
147 
148     /***
149      * Accessor.
150      *
151      * @return the method name of this signature
152      */
153     public String getMethodName() {
154         return methodName;
155     }
156 
157     /***
158      * Accessor.
159      *
160      * @return the return type of this signature
161      */
162     public Class getReturnType() {
163         return returnType;
164     }
165 
166     /***
167      * Returns true is return type is primitive.
168      *
169      * @return true is return type is primitive
170      */
171     public boolean isReturnTypePrimitive() {
172         if (returnType == null) {
173             return false;
174         }
175 
176         return returnType.isPrimitive();
177     }
178 
179     /***
180      * Compares this Signature to another object.  Note that this ignores the
181      * type of the return value, like Java does.
182      *
183      * @param object The object with which we are comparing
184      *
185      * @return true if the passed object is a Signature that matches this one
186      */
187     public boolean equals(Object object) {
188         if (!(object instanceof Signature)) {
189             return false;
190         }
191 
192         Signature compareSignature = (Signature) object;
193 
194         // if the class type name doesn't match, return false
195         if (!classType.equals(compareSignature.getClassType())) {
196             return false;
197         }
198 
199         // if the method name doesn't match, return false
200         if (!methodName.equals(compareSignature.getMethodName())) {
201             return false;
202         }
203 
204         // if the number of arguments don't match, return false
205         if (argTypes.length != compareSignature.getArgTypes().length) {
206             return false;
207         }
208 
209         // if the types of the arguments don't match, return false
210         for (int i = 0; i < argTypes.length; i++) {
211             if (!argTypes[i].equals(compareSignature.getArgTypes()[i])) {
212                 return false;
213             }
214         }
215 
216         return true;
217     }
218 
219     /***
220      * Return hashCode for this Signature.
221      *
222      * @return the hashCode for this Signature
223      */
224     public int hashCode() {
225         return this.toStringWithoutReturnType().hashCode();
226     }
227 
228     /***
229      * Represents this signature as a String.
230      *
231      * @return This Signature, represented as a String
232      *
233      * @todo investigate all possible values for return type string other than
234      *       not null, null, or void
235      */
236     public String toString() {
237         StringBuffer stringBuffer = new StringBuffer();
238         String returnTypeClass = null;
239         String returnTypeString = null;
240 
241         if (getReturnType() != null) {
242             returnTypeString = getReturnType().toString();
243         }
244 
245         if ((returnTypeString == null) || "void".equals(returnTypeString)) {
246             returnTypeClass = "void";
247         } else if (!returnTypeString.startsWith("class")) {
248             // if it doesn't start with the word "class" then it must be a primitive
249             returnTypeClass = returnTypeString;
250         } else {
251             // strip the word "class" from in front of the return type
252             returnTypeClass =
253                 returnTypeString.substring(LENGTH_OF_WORD_CLASS_PLUS_ONE_SPACE);
254         }
255 
256         stringBuffer.append(returnTypeClass);
257         stringBuffer.append(" ");
258         stringBuffer.append(toStringWithoutReturnType());
259 
260         return stringBuffer.toString();
261     }
262 
263     /***
264      * Internal method which contains the logic to create a signature.
265      *
266      * @param newReturnType the returnType which will be used to create this
267      *        Signature
268      * @param newClassType the classType which will be used to create this
269      *        Signature
270      * @param newMethodName the methodName which will be used to create this
271      *        Signature
272      * @param newArgTypes the argTypes which will be used to create this
273      *        Signature
274      */
275     protected void create(Class newReturnType, Class newClassType,
276         String newMethodName, Class[] newArgTypes) {
277         returnType = newReturnType;
278         classType = newClassType;
279         methodName = newMethodName;
280 
281         if (newArgTypes == null) {
282             argTypes = new Class[0];
283         } else {
284             argTypes = newArgTypes;
285         }
286     }
287 
288     /***
289      * Returns the representation of the Signature as a string, with the return
290      * type omitted.
291      *
292      * @return the representation of the Signature as a string, with the return
293      *         type omitted.
294      */
295     protected String toStringWithoutReturnType() {
296         StringBuffer stringBuffer = new StringBuffer();
297         stringBuffer.append(getClassName());
298         stringBuffer.append(".");
299         stringBuffer.append(methodName);
300         stringBuffer.append("(");
301 
302         for (int i = 0; i < argTypes.length; i++) {
303             stringBuffer.append(argTypes[i].getName());
304 
305             if (i < (argTypes.length - 1)) {
306                 stringBuffer.append(", ");
307             }
308         }
309 
310         stringBuffer.append(")");
311 
312         return stringBuffer.toString();
313     }
314 }