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 }