001 // Copyright 2004, 2005 The Apache Software Foundation 002 // 003 // Licensed under the Apache License, Version 2.0 (the "License"); 004 // you may not use this file except in compliance with the License. 005 // You may obtain a copy of the License at 006 // 007 // http://www.apache.org/licenses/LICENSE-2.0 008 // 009 // Unless required by applicable law or agreed to in writing, software 010 // distributed under the License is distributed on an "AS IS" BASIS, 011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 012 // See the License for the specific language governing permissions and 013 // limitations under the License. 014 package org.apache.tapestry.enhance; 015 016 import org.apache.hivemind.service.ClassFabUtils; 017 018 import java.lang.reflect.Method; 019 020 021 /** 022 * JDK 1.4 based version of {@link MethodSignature}. 023 */ 024 public class MethodSignatureImpl implements MethodSignature 025 { 026 protected int _hashCode = -1; 027 028 protected Class _returnType; 029 030 protected String _name; 031 032 protected Class[] _parameterTypes; 033 034 protected Class[] _exceptionTypes; 035 036 public MethodSignatureImpl(Class returnType, String name, 037 Class[] parameterTypes, Class[] exceptionTypes) 038 { 039 _returnType = returnType; 040 _name = name; 041 _parameterTypes = parameterTypes; 042 _exceptionTypes = exceptionTypes; 043 } 044 045 public MethodSignatureImpl(Method m) 046 { 047 this(m.getReturnType(), m.getName(), m.getParameterTypes(), m.getExceptionTypes()); 048 } 049 050 public Class[] getExceptionTypes() 051 { 052 return _exceptionTypes; 053 } 054 055 public String getName() 056 { 057 return _name; 058 } 059 060 public Class[] getParameterTypes() 061 { 062 return _parameterTypes; 063 } 064 065 public Class getReturnType() 066 { 067 return _returnType; 068 } 069 070 public int hashCode() 071 { 072 if (_hashCode == -1) 073 { 074 _hashCode = _returnType.hashCode(); 075 076 _hashCode = 31 * _hashCode + _name.hashCode(); 077 078 int count = count(_parameterTypes); 079 080 for (int i = 0; i < count; i++) 081 _hashCode = 31 * _hashCode + _parameterTypes[i].hashCode(); 082 083 count = count(_exceptionTypes); 084 085 for (int i = 0; i < count; i++) 086 _hashCode = 31 * _hashCode + _exceptionTypes[i].hashCode(); 087 } 088 089 return _hashCode; 090 } 091 092 protected static int count(Object[] array) 093 { 094 return array == null ? 0 : array.length; 095 } 096 097 /** 098 * Returns true if the other object is an instance of MethodSignature with identical values for 099 * return type, name, parameter types and exception types. 100 */ 101 public boolean equals(Object o) 102 { 103 if (o == null || !(o instanceof MethodSignatureImpl)) 104 return false; 105 106 MethodSignatureImpl ms = (MethodSignatureImpl) o; 107 108 if (_returnType != ms._returnType) 109 return false; 110 111 if (!_name.equals(ms._name)) 112 return false; 113 114 if (mismatch(_parameterTypes, ms._parameterTypes)) 115 return false; 116 117 return !mismatch(_exceptionTypes, ms._exceptionTypes); 118 } 119 120 protected boolean mismatch(Class[] a1, Class[] a2) 121 { 122 int a1Count = count(a1); 123 int a2Count = count(a2); 124 125 if (a1Count != a2Count) 126 return true; 127 128 // Hm. What if order is important (for exceptions)? We're really saying here that they 129 // were derived from the name Method. 130 131 for (int i = 0; i < a1Count; i++) 132 { 133 if (!a1[i].isAssignableFrom(a2[i])) 134 return true; 135 } 136 137 return false; 138 } 139 140 public String toString() 141 { 142 StringBuffer buffer = new StringBuffer(); 143 144 buffer.append(ClassFabUtils.getJavaClassName(_returnType)); 145 buffer.append(" "); 146 buffer.append(_name); 147 buffer.append("("); 148 149 for (int i = 0; i < count(_parameterTypes); i++) 150 { 151 if (i > 0) 152 buffer.append(", "); 153 154 buffer.append(ClassFabUtils.getJavaClassName(_parameterTypes[i])); 155 } 156 157 buffer.append(")"); 158 159 for (int i = 0; i < count(_exceptionTypes); i++) 160 { 161 if (i == 0) 162 buffer.append(" throws "); 163 else 164 buffer.append(", "); 165 166 buffer.append(_exceptionTypes[i].getName()); 167 } 168 169 return buffer.toString(); 170 } 171 172 public String getUniqueId() 173 { 174 StringBuffer buffer = new StringBuffer(_name); 175 buffer.append("("); 176 177 for (int i = 0; i < count(_parameterTypes); i++) 178 { 179 if (i > 0) 180 buffer.append(","); 181 182 buffer.append(ClassFabUtils.getJavaClassName(_parameterTypes[i])); 183 } 184 185 buffer.append(")"); 186 187 return buffer.toString(); 188 } 189 190 public boolean isGeneric() 191 { 192 return false; 193 } 194 195 public boolean isOverridingSignatureOf(MethodSignature ms) 196 { 197 if (!(ms instanceof MethodSignatureImpl)) 198 return false; 199 200 MethodSignatureImpl sig = (MethodSignatureImpl)ms; 201 202 if (!sig._returnType.isAssignableFrom(_returnType)) 203 return false; 204 205 if (!_name.equals(sig._name)) 206 return false; 207 208 if (mismatch(_parameterTypes, sig._parameterTypes)) 209 return false; 210 211 return exceptionsEncompass(sig._exceptionTypes); 212 } 213 214 /** 215 * The nuts and bolts of checking that another method signature's exceptions are a subset of 216 * this signature's. 217 */ 218 219 protected boolean exceptionsEncompass(Class[] otherExceptions) 220 { 221 int ourCount = count(_exceptionTypes); 222 int otherCount = count(otherExceptions); 223 224 // If we have no exceptions, then ours encompass theirs only if they 225 // have no exceptions, either. 226 227 if (ourCount == 0) 228 return otherCount == 0; 229 230 boolean[] matched = new boolean[otherCount]; 231 int unmatched = otherCount; 232 233 for (int i = 0; i < ourCount && unmatched > 0; i++) 234 { 235 for (int j = 0; j < otherCount; j++) 236 { 237 // Ignore exceptions that have already been matched 238 239 if (matched[j]) 240 continue; 241 242 // When one of our exceptions is a super-class of one of their exceptions, 243 // then their exceptions is matched. 244 245 if (_exceptionTypes[i].isAssignableFrom(otherExceptions[j])) 246 { 247 matched[j] = true; 248 unmatched--; 249 } 250 } 251 } 252 253 return unmatched == 0; 254 } 255 }