001: // Copyright 2006, 2007 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:
015: package org.apache.tapestry.services;
016:
017: import static org.apache.tapestry.ioc.internal.util.Defense.notBlank;
018:
019: import java.lang.reflect.Modifier;
020:
021: /**
022: * A representation of a method signature, which consists of its name, modifiers (primarily,
023: * visibility), return type, parameter types, and declared exception types.
024: * <p>
025: * Types are stored as class names (or primitive names) because the MethodSignature is often used in
026: * situations where the actual class has not been loaded yet. When classes are already loaded (such
027: * as, for use with {@link org.apache.hivemind.service.ClassFab}), then a different implementation
028: * with the same name, {@link org.apache.tapestry.ioc.services.MethodSignature} is used.
029: */
030: public class MethodSignature implements Comparable<MethodSignature> {
031: private int _hashCode = -1;
032:
033: private final int _modifiers;
034:
035: private final String _returnType;
036:
037: private final String _methodName;
038:
039: private final String[] _parameterTypes;
040:
041: private final String[] _exceptionTypes;
042:
043: private static final String[] EMPTY_STRINGS = new String[0];
044:
045: /** Convienience for adding a public void method with no parameters or exception types. */
046:
047: public MethodSignature(String name) {
048: this (Modifier.PUBLIC, "void", name, EMPTY_STRINGS,
049: EMPTY_STRINGS);
050: }
051:
052: public MethodSignature(int modifiers, String type, String name,
053: String[] parameterTypes, String[] exceptionTypes) {
054: _modifiers = modifiers;
055:
056: _returnType = notBlank(type, "type");
057: _methodName = notBlank(name, "name");
058:
059: // TODO: Checks that no element within the two arrays
060: // is null or blank.
061:
062: _parameterTypes = typeNamesOrEmpty(parameterTypes);
063: _exceptionTypes = typeNamesOrEmpty(exceptionTypes);
064: }
065:
066: private String[] typeNamesOrEmpty(String[] types) {
067: return types == null ? EMPTY_STRINGS : types;
068: }
069:
070: /**
071: * Returns a non-null array of the names of each declared exception type thrown by the method.
072: * Calling code should not modify the array.
073: */
074: public String[] getExceptionTypes() {
075: return _exceptionTypes;
076: }
077:
078: /** Returns the name of the method. */
079: public String getMethodName() {
080: return _methodName;
081: }
082:
083: /**
084: * Returns the set of modifier flags for this method.
085: *
086: * @see java.lang.reflect.Modifier
087: */
088: public int getModifiers() {
089: return _modifiers;
090: }
091:
092: /**
093: * Returns an array of the type name for each parameter. Calling code should not modify the
094: * array.
095: */
096: public String[] getParameterTypes() {
097: return _parameterTypes;
098: }
099:
100: /** Return the type name of the return type of the method. */
101: public String getReturnType() {
102: return _returnType;
103: }
104:
105: @Override
106: public int hashCode() {
107: if (_hashCode == -1) {
108: _hashCode = 17 * _modifiers;
109: _hashCode += 31 * _returnType.hashCode();
110: _hashCode += 31 * _methodName.hashCode();
111:
112: for (String parameterType : _parameterTypes) {
113: _hashCode += 31 * parameterType.hashCode();
114: }
115:
116: for (String exceptionType : _exceptionTypes) {
117: _hashCode += 31 * exceptionType.hashCode();
118: }
119: }
120:
121: return _hashCode;
122: }
123:
124: @Override
125: public boolean equals(Object other) {
126: if (other == null || !(other instanceof MethodSignature))
127: return false;
128:
129: MethodSignature ms = (MethodSignature) other;
130:
131: return _modifiers == ms._modifiers
132: && _returnType.equals(ms._returnType)
133: && _methodName.equals(ms._methodName)
134: && matches(_parameterTypes, ms._parameterTypes)
135: && matches(_exceptionTypes, ms._exceptionTypes);
136: }
137:
138: private boolean matches(String[] values, String[] otherValues) {
139: if (values.length != otherValues.length)
140: return false;
141:
142: for (int i = 0; i < values.length; i++) {
143: if (!values[i].equals(otherValues[i]))
144: return false;
145: }
146:
147: return true;
148: }
149:
150: /**
151: * Returns the long form description of the signature. This includes modifiers, return type,
152: * method name, parameters and thrown exceptions, formatter approximately as it would appear in
153: * Java source (except that parameter names, which are not known, do no appear).
154: */
155: @Override
156: public String toString() {
157: StringBuilder builder = new StringBuilder();
158:
159: // Package private is simply omitted.
160:
161: if (_modifiers != 0) {
162: builder.append(Modifier.toString(_modifiers));
163: builder.append(' ');
164: }
165:
166: builder.append(_returnType);
167: builder.append(' ');
168:
169: addMethodNameAndParameters(builder);
170:
171: for (int i = 0; i < _exceptionTypes.length; i++) {
172: if (i == 0)
173: builder.append(" throws ");
174: else
175: builder.append(", ");
176:
177: builder.append(_exceptionTypes[i]);
178: }
179:
180: return builder.toString();
181: }
182:
183: private void addMethodNameAndParameters(StringBuilder builder) {
184: builder.append(_methodName);
185: builder.append('(');
186:
187: for (int i = 0; i < _parameterTypes.length; i++) {
188: if (i > 0)
189: builder.append(", ");
190:
191: builder.append(_parameterTypes[i]);
192: }
193:
194: builder.append(')');
195: }
196:
197: /**
198: * Sorting is primarily via method name. For methods with the same name, the second level of
199: * sorting is by parameter count (ascending).
200: */
201: public int compareTo(MethodSignature o) {
202: int result = _methodName.compareTo(o._methodName);
203:
204: if (result == 0)
205: result = _parameterTypes.length - o._parameterTypes.length;
206:
207: return result;
208: }
209:
210: /**
211: * Returns a shortened form of the string representation of the method. It lists just the name
212: * of the method and the types of any parameters, omitting return type, exceptions and
213: * modifiers.
214: *
215: * @return
216: */
217: public String getMediumDescription() {
218: StringBuilder builder = new StringBuilder();
219:
220: addMethodNameAndParameters(builder);
221:
222: return builder.toString();
223: }
224:
225: }
|