1 16 package org.springframework.binding.method; 17 18 import java.io.Serializable ; 19 import java.lang.reflect.Method ; 20 import java.util.HashMap ; 21 import java.util.Map ; 22 23 import org.springframework.core.style.ToStringCreator; 24 import org.springframework.util.ObjectUtils; 25 26 31 public class ClassMethodKey implements Serializable { 32 33 36 private Class type; 37 38 41 private String methodName; 42 43 46 private Class [] parameterTypes; 47 48 51 private transient Method method; 52 53 59 public ClassMethodKey(Class type, String methodName, Class [] parameterTypes) { 60 this.type = type; 61 this.methodName = methodName; 62 this.parameterTypes = parameterTypes; 63 } 64 65 public Class getType() { 66 return type; 67 } 68 69 public String getMethodName() { 70 return methodName; 71 } 72 73 public Class [] getParameterTypes() { 74 return parameterTypes; 75 } 76 77 public Method getMethod() throws InvalidMethodSignatureException { 78 if (method == null) { 79 method = resolveMethod(); 80 } 81 return method; 82 } 83 84 protected Method resolveMethod() throws InvalidMethodSignatureException { 85 try { 86 return type.getMethod(getMethodName(), getParameterTypes()); 87 } 88 catch (NoSuchMethodException e) { 89 Method 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 findMethodConsiderAssignableParameterTypes() { 100 Method [] candidateMethods = getType().getMethods(); 101 for (int i = 0; i < candidateMethods.length; i++) { 102 if (candidateMethods[i].getName().equals(getMethodName())) { 103 Class [] candidateParameterTypes = candidateMethods[i].getParameterTypes(); 105 if (candidateParameterTypes.length == getParameterTypes().length) { 106 int numberOfCorrectArguments = 0; 107 for (int j = 0; j < candidateParameterTypes.length; j++) { 108 Class candidateType = candidateParameterTypes[j]; 111 Class parameterType = parameterTypes[j]; 112 if (parameterType != null) { 113 if (isAssignable(candidateType, parameterType)) { 114 numberOfCorrectArguments++; 115 } 116 } 117 else { 118 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 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 [] 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 parameterType = parameterTypes[i]; 167 if (parameterType != null) { 168 hash += parameterTypes[i].hashCode(); 169 } 170 } 171 return hash; 172 } 173 174 176 187 private static boolean isAssignable(Class targetType, Class valueType) { 188 return (targetType.isAssignableFrom(valueType) || 189 targetType.equals(primitiveWrapperTypeMap.get(valueType))); 190 } 191 192 196 private static final Map primitiveWrapperTypeMap = new HashMap (8); 197 198 static { 199 primitiveWrapperTypeMap.put(Boolean .class, boolean.class); 200 primitiveWrapperTypeMap.put(Byte .class, byte.class); 201 primitiveWrapperTypeMap.put(Character .class, char.class); 202 primitiveWrapperTypeMap.put(Double .class, double.class); 203 primitiveWrapperTypeMap.put(Float .class, float.class); 204 primitiveWrapperTypeMap.put(Integer .class, int.class); 205 primitiveWrapperTypeMap.put(Long .class, long.class); 206 primitiveWrapperTypeMap.put(Short .class, short.class); 207 } 208 209 public String toString() { 210 return new ToStringCreator(this).append("class", type).append("methodName", methodName).append("parameterTypes", 211 parameterTypes).toString(); 212 } 213 } | Popular Tags |