KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > commons > jxpath > util > MethodLookupUtils


1 /*
2  * Copyright 1999-2004 The Apache Software Foundation
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.apache.commons.jxpath.util;
17
18 import java.lang.reflect.Constructor JavaDoc;
19 import java.lang.reflect.Method JavaDoc;
20 import java.lang.reflect.Modifier JavaDoc;
21 import java.util.Arrays JavaDoc;
22
23 import org.apache.commons.jxpath.ExpressionContext;
24 import org.apache.commons.jxpath.JXPathException;
25
26 /**
27  * Method lookup utilities, which find static and non-static methods as well
28  * as constructors based on a name and list of parameters.
29  *
30  * @author Dmitri Plotnikov
31  * @version $Revision: 1.7 $ $Date: 2004/02/29 14:17:43 $
32  */

33 public class MethodLookupUtils {
34
35     private static final int NO_MATCH = 0;
36     private static final int APPROXIMATE_MATCH = 1;
37     private static final int EXACT_MATCH = 2;
38     private static final Object JavaDoc[] EMPTY_ARRAY = new Object JavaDoc[0];
39
40      public static Constructor JavaDoc lookupConstructor(
41         Class JavaDoc targetClass,
42         Object JavaDoc[] parameters)
43      {
44         boolean tryExact = true;
45         int count = parameters == null ? 0 : parameters.length;
46         Class JavaDoc types[] = new Class JavaDoc[count];
47         for (int i = 0; i < count; i++) {
48             Object JavaDoc param = parameters[i];
49             if (param != null) {
50                 types[i] = param.getClass();
51             }
52             else {
53                 types[i] = null;
54                 tryExact = false;
55             }
56         }
57
58         Constructor JavaDoc constructor = null;
59
60         if (tryExact) {
61             // First - without type conversion
62
try {
63                 constructor = targetClass.getConstructor(types);
64                 if (constructor != null) {
65                     return constructor;
66                 }
67             }
68             catch (NoSuchMethodException JavaDoc ex) {
69                 // Ignore
70
}
71         }
72
73         int currentMatch = 0;
74         boolean ambiguous = false;
75
76         // Then - with type conversion
77
Constructor JavaDoc[] constructors = targetClass.getConstructors();
78         for (int i = 0; i < constructors.length; i++) {
79             int match =
80                 matchParameterTypes(
81                     constructors[i].getParameterTypes(),
82                     parameters);
83             if (match != NO_MATCH) {
84                 if (match > currentMatch) {
85                     constructor = constructors[i];
86                     currentMatch = match;
87                     ambiguous = false;
88                 }
89                 else if (match == currentMatch) {
90                     ambiguous = true;
91                 }
92             }
93         }
94         if (ambiguous) {
95             throw new JXPathException(
96                 "Ambigous constructor " + Arrays.asList(parameters));
97         }
98         return constructor;
99     }
100
101     public static Method JavaDoc lookupStaticMethod(
102         Class JavaDoc targetClass,
103         String JavaDoc name,
104         Object JavaDoc[] parameters)
105     {
106         boolean tryExact = true;
107         int count = parameters == null ? 0 : parameters.length;
108         Class JavaDoc types[] = new Class JavaDoc[count];
109         for (int i = 0; i < count; i++) {
110             Object JavaDoc param = parameters[i];
111             if (param != null) {
112                 types[i] = param.getClass();
113             }
114             else {
115                 types[i] = null;
116                 tryExact = false;
117             }
118         }
119
120         Method JavaDoc method = null;
121
122         if (tryExact) {
123             // First - without type conversion
124
try {
125                 method = targetClass.getMethod(name, types);
126                 if (method != null
127                     && Modifier.isStatic(method.getModifiers())) {
128                     return method;
129                 }
130             }
131             catch (NoSuchMethodException JavaDoc ex) {
132                 // Ignore
133
}
134         }
135
136         int currentMatch = 0;
137         boolean ambiguous = false;
138
139         // Then - with type conversion
140
Method JavaDoc[] methods = targetClass.getMethods();
141         for (int i = 0; i < methods.length; i++) {
142             if (Modifier.isStatic(methods[i].getModifiers())
143                 && methods[i].getName().equals(name)) {
144                 int match =
145                     matchParameterTypes(
146                         methods[i].getParameterTypes(),
147                         parameters);
148                 if (match != NO_MATCH) {
149                     if (match > currentMatch) {
150                         method = methods[i];
151                         currentMatch = match;
152                         ambiguous = false;
153                     }
154                     else if (match == currentMatch) {
155                         ambiguous = true;
156                     }
157                 }
158             }
159         }
160         if (ambiguous) {
161             throw new JXPathException("Ambigous method call: " + name);
162         }
163         return method;
164     }
165
166     public static Method JavaDoc lookupMethod(
167         Class JavaDoc targetClass,
168         String JavaDoc name,
169         Object JavaDoc[] parameters)
170     {
171         if (parameters == null
172             || parameters.length < 1
173             || parameters[0] == null) {
174             return null;
175         }
176
177         if (matchType(targetClass, parameters[0]) == NO_MATCH) {
178             return null;
179         }
180
181         targetClass = TypeUtils.convert(parameters[0], targetClass).getClass();
182
183         boolean tryExact = true;
184         int count = parameters.length - 1;
185         Class JavaDoc types[] = new Class JavaDoc[count];
186         Object JavaDoc arguments[] = new Object JavaDoc[count];
187         for (int i = 0; i < count; i++) {
188             Object JavaDoc param = parameters[i + 1];
189             arguments[i] = param;
190             if (param != null) {
191                 types[i] = param.getClass();
192             }
193             else {
194                 types[i] = null;
195                 tryExact = false;
196             }
197         }
198
199         Method JavaDoc method = null;
200
201         if (tryExact) {
202             // First - without type conversion
203
try {
204                 method = targetClass.getMethod(name, types);
205                 if (method != null
206                     && !Modifier.isStatic(method.getModifiers())) {
207                     return method;
208                 }
209             }
210             catch (NoSuchMethodException JavaDoc ex) {
211                 // Ignore
212
}
213         }
214
215         int currentMatch = 0;
216         boolean ambiguous = false;
217
218         // Then - with type conversion
219
Method JavaDoc[] methods = targetClass.getMethods();
220         for (int i = 0; i < methods.length; i++) {
221             if (!Modifier.isStatic(methods[i].getModifiers())
222                 && methods[i].getName().equals(name)) {
223                 int match =
224                     matchParameterTypes(
225                         methods[i].getParameterTypes(),
226                         arguments);
227                 if (match != NO_MATCH) {
228                     if (match > currentMatch) {
229                         method = methods[i];
230                         currentMatch = match;
231                         ambiguous = false;
232                     }
233                     else if (match == currentMatch) {
234                         ambiguous = true;
235                     }
236                 }
237             }
238         }
239         if (ambiguous) {
240             throw new JXPathException("Ambigous method call: " + name);
241         }
242         return method;
243     }
244
245     private static int matchParameterTypes(
246         Class JavaDoc types[],
247         Object JavaDoc parameters[])
248     {
249         int pi = 0;
250         if (types.length >= 1
251             && ExpressionContext.class.isAssignableFrom(types[0])) {
252             pi++;
253         }
254         int length = parameters == null ? 0 : parameters.length;
255         if (types.length != length + pi) {
256             return NO_MATCH;
257         }
258         int totalMatch = EXACT_MATCH;
259         for (int i = 0; i < length; i++) {
260             int match = matchType(types[i + pi], parameters[i]);
261             if (match == NO_MATCH) {
262                 return NO_MATCH;
263             }
264             if (match < totalMatch) {
265                 totalMatch = match;
266             }
267         }
268         return totalMatch;
269     }
270
271     private static int matchType(Class JavaDoc expected, Object JavaDoc object) {
272         if (object == null) {
273             return APPROXIMATE_MATCH;
274         }
275
276         Class JavaDoc actual = object.getClass();
277
278         if (expected.equals(actual)) {
279             return EXACT_MATCH;
280         }
281         if (expected.isAssignableFrom(actual)) {
282             return EXACT_MATCH;
283         }
284
285         if (TypeUtils.canConvert(object, expected)) {
286             return APPROXIMATE_MATCH;
287         }
288
289         return NO_MATCH;
290     }
291 }
Popular Tags