KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > springframework > binding > method > ClassMethodKey


1 /*
2  * Copyright 2002-2006 the original author or authors.
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  */

16 package org.springframework.binding.method;
17
18 import java.io.Serializable JavaDoc;
19 import java.lang.reflect.Method JavaDoc;
20 import java.util.HashMap JavaDoc;
21 import java.util.Map JavaDoc;
22
23 import org.springframework.core.style.ToStringCreator;
24 import org.springframework.util.ObjectUtils;
25
26 /**
27  * A class method signature.
28  *
29  * @author Keith Donald
30  */

31 public class ClassMethodKey implements Serializable JavaDoc {
32
33     /**
34      * The class the method is a member of.
35      */

36     private Class JavaDoc type;
37
38     /**
39      * The name of the method.
40      */

41     private String JavaDoc methodName;
42
43     /**
44      * The method's parameter types.
45      */

46     private Class JavaDoc[] parameterTypes;
47
48     /**
49      * A cached handle to the resolved method (may be null).
50      */

51     private transient Method JavaDoc method;
52
53     /**
54      * Create a new class method key.
55      * @param type the class the method is a member of
56      * @param methodName the method name
57      * @param parameterTypes the method parameter types
58      */

59     public ClassMethodKey(Class JavaDoc type, String JavaDoc methodName, Class JavaDoc[] parameterTypes) {
60         this.type = type;
61         this.methodName = methodName;
62         this.parameterTypes = parameterTypes;
63     }
64
65     public Class JavaDoc getType() {
66         return type;
67     }
68
69     public String JavaDoc getMethodName() {
70         return methodName;
71     }
72
73     public Class JavaDoc[] getParameterTypes() {
74         return parameterTypes;
75     }
76
77     public Method JavaDoc getMethod() throws InvalidMethodSignatureException {
78         if (method == null) {
79             method = resolveMethod();
80         }
81         return method;
82     }
83
84     protected Method JavaDoc resolveMethod() throws InvalidMethodSignatureException {
85         try {
86             return type.getMethod(getMethodName(), getParameterTypes());
87         }
88         catch (NoSuchMethodException JavaDoc e) {
89             Method JavaDoc method = findMethodConsiderAssignableParameterTypes();
90             if (method != null) {
91                 return method;
92             }
93             else {
94                 throw new InvalidMethodSignatureException(this, e);
95             }
96         }
97     }
98
99     protected Method JavaDoc findMethodConsiderAssignableParameterTypes() {
100         Method JavaDoc[] candidateMethods = getType().getMethods();
101         for (int i = 0; i < candidateMethods.length; i++) {
102             if (candidateMethods[i].getName().equals(getMethodName())) {
103                 // Check if the method has the correct number of parameters.
104
Class JavaDoc[] candidateParameterTypes = candidateMethods[i].getParameterTypes();
105                 if (candidateParameterTypes.length == getParameterTypes().length) {
106                     int numberOfCorrectArguments = 0;
107                     for (int j = 0; j < candidateParameterTypes.length; j++) {
108                         // Check if the candidate type is assignable to the sig
109
// parameter type.
110
Class JavaDoc candidateType = candidateParameterTypes[j];
111                         Class JavaDoc parameterType = parameterTypes[j];
112                         if (parameterType != null) {
113                             if (isAssignable(candidateType, parameterType)) {
114                                 numberOfCorrectArguments++;
115                             }
116                         }
117                         else {
118                             // just match on a null param type (effectively
119
// 'any')
120
numberOfCorrectArguments++;
121                         }
122                     }
123                     if (numberOfCorrectArguments == parameterTypes.length) {
124                         return candidateMethods[i];
125                     }
126                 }
127             }
128         }
129         return null;
130     }
131
132     public boolean equals(Object JavaDoc obj) {
133         if (!(obj instanceof ClassMethodKey)) {
134             return false;
135         }
136         ClassMethodKey other = (ClassMethodKey)obj;
137         return type.equals(other.type) && methodName.equals(other.methodName)
138                 && argumentTypesEqual(other.parameterTypes);
139     }
140
141     private boolean argumentTypesEqual(Class JavaDoc[] other) {
142         if (parameterTypes == other) {
143             return true;
144         }
145         if (parameterTypes.length != other.length) {
146             return false;
147         }
148         for (int i = 0; i < this.parameterTypes.length; i++) {
149             if (!ObjectUtils.nullSafeEquals(parameterTypes[i], other[i])) {
150                 return false;
151             }
152         }
153         return true;
154     }
155
156     public int hashCode() {
157         return type.hashCode() + methodName.hashCode() + argumentTypesHash();
158     }
159
160     private int argumentTypesHash() {
161         if (parameterTypes == null) {
162             return 0;
163         }
164         int hash = 0;
165         for (int i = 0; i < parameterTypes.length; i++) {
166             Class JavaDoc parameterType = parameterTypes[i];
167             if (parameterType != null) {
168                 hash += parameterTypes[i].hashCode();
169             }
170         }
171         return hash;
172     }
173
174     // internal helpers
175

176     /**
177      * Determine if the given target type is assignable from the given value
178      * type, assuming setting by reflection. Considers primitive wrapper
179      * classes as assignable to the corresponding primitive types.
180      * <p>
181      * NOTE: Pulled from ClassUtils in Spring 2.0 for 1.2.8 compatability. Should
182      * be collapsed when 1.2.9 is released.
183      * @param targetType the target type
184      * @param valueType the value type that should be assigned to the target type
185      * @return if the target type is assignable from the value type
186      */

187     private static boolean isAssignable(Class JavaDoc targetType, Class JavaDoc valueType) {
188         return (targetType.isAssignableFrom(valueType) ||
189                 targetType.equals(primitiveWrapperTypeMap.get(valueType)));
190     }
191
192     /**
193      * Map with primitive wrapper type as key and corresponding primitive
194      * type as value, for example: Integer.class -> int.class.
195      */

196     private static final Map JavaDoc primitiveWrapperTypeMap = new HashMap JavaDoc(8);
197
198     static {
199         primitiveWrapperTypeMap.put(Boolean JavaDoc.class, boolean.class);
200         primitiveWrapperTypeMap.put(Byte JavaDoc.class, byte.class);
201         primitiveWrapperTypeMap.put(Character JavaDoc.class, char.class);
202         primitiveWrapperTypeMap.put(Double JavaDoc.class, double.class);
203         primitiveWrapperTypeMap.put(Float JavaDoc.class, float.class);
204         primitiveWrapperTypeMap.put(Integer JavaDoc.class, int.class);
205         primitiveWrapperTypeMap.put(Long JavaDoc.class, long.class);
206         primitiveWrapperTypeMap.put(Short JavaDoc.class, short.class);
207     }
208
209     public String JavaDoc toString() {
210         return new ToStringCreator(this).append("class", type).append("methodName", methodName).append("parameterTypes",
211                 parameterTypes).toString();
212     }
213 }
Popular Tags