KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > springframework > util > MethodInvoker


1 /*
2  * Copyright 2002-2007 the original author or authors.
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
17 package org.springframework.util;
18
19 import java.lang.reflect.InvocationTargetException JavaDoc;
20 import java.lang.reflect.Method JavaDoc;
21 import java.lang.reflect.Modifier JavaDoc;
22
23 /**
24  * Helper class that allows for specifying a method to invoke in a declarative
25  * fashion, be it static or non-static.
26  *
27  * <p>Usage: Specify "targetClass"/"targetMethod" or "targetObject"/"targetMethod",
28  * optionally specify arguments, prepare the invoker. Afterwards, you may
29  * invoke the method any number of times, obtaining the invocation result.
30  *
31  * <p>Typically not used directly but via its subclasses
32  * {@link org.springframework.beans.factory.config.MethodInvokingFactoryBean} and
33  * {@link org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean}.
34  *
35  * @author Colin Sampaleanu
36  * @author Juergen Hoeller
37  * @since 19.02.2004
38  * @see #prepare
39  * @see #invoke
40  * @see org.springframework.beans.factory.config.MethodInvokingFactoryBean
41  * @see org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean
42  */

43 public class MethodInvoker {
44
45     private Class JavaDoc targetClass;
46
47     private Object JavaDoc targetObject;
48
49     private String JavaDoc targetMethod;
50
51     private String JavaDoc staticMethod;
52
53     private Object JavaDoc[] arguments;
54
55     /** The method we will call */
56     private Method JavaDoc methodObject;
57
58
59     /**
60      * Set the target class on which to call the target method.
61      * Only necessary when the target method is static; else,
62      * a target object needs to be specified anyway.
63      * @see #setTargetObject
64      * @see #setTargetMethod
65      */

66     public void setTargetClass(Class JavaDoc targetClass) {
67         this.targetClass = targetClass;
68     }
69
70     /**
71      * Return the target class on which to call the target method.
72      */

73     public Class JavaDoc getTargetClass() {
74         return targetClass;
75     }
76
77     /**
78      * Set the target object on which to call the target method.
79      * Only necessary when the target method is not static;
80      * else, a target class is sufficient.
81      * @see #setTargetClass
82      * @see #setTargetMethod
83      */

84     public void setTargetObject(Object JavaDoc targetObject) {
85         this.targetObject = targetObject;
86         if (targetObject != null) {
87             this.targetClass = targetObject.getClass();
88         }
89     }
90
91     /**
92      * Return the target object on which to call the target method.
93      */

94     public Object JavaDoc getTargetObject() {
95         return targetObject;
96     }
97
98     /**
99      * Set the name of the method to be invoked.
100      * Refers to either a static method or a non-static method,
101      * depending on a target object being set.
102      * @see #setTargetClass
103      * @see #setTargetObject
104      */

105     public void setTargetMethod(String JavaDoc targetMethod) {
106         this.targetMethod = targetMethod;
107     }
108
109     /**
110      * Return the name of the method to be invoked.
111      */

112     public String JavaDoc getTargetMethod() {
113         return targetMethod;
114     }
115
116     /**
117      * Set a fully qualified static method name to invoke,
118      * e.g. "example.MyExampleClass.myExampleMethod".
119      * Convenient alternative to specifying targetClass and targetMethod.
120      * @see #setTargetClass
121      * @see #setTargetMethod
122      */

123     public void setStaticMethod(String JavaDoc staticMethod) {
124         this.staticMethod = staticMethod;
125     }
126
127     /**
128      * Set arguments for the method invocation. If this property is not set,
129      * or the Object array is of length 0, a method with no arguments is assumed.
130      */

131     public void setArguments(Object JavaDoc[] arguments) {
132         this.arguments = arguments;
133     }
134
135     /**
136      * Retrun the arguments for the method invocation.
137      */

138     public Object JavaDoc[] getArguments() {
139         return arguments;
140     }
141
142
143     /**
144      * Prepare the specified method.
145      * The method can be invoked any number of times afterwards.
146      * @see #getPreparedMethod
147      * @see #invoke
148      */

149     public void prepare() throws ClassNotFoundException JavaDoc, NoSuchMethodException JavaDoc {
150         if (this.staticMethod != null) {
151             int lastDotIndex = this.staticMethod.lastIndexOf('.');
152             if (lastDotIndex == -1 || lastDotIndex == this.staticMethod.length()) {
153                 throw new IllegalArgumentException JavaDoc(
154                         "staticMethod must be a fully qualified class plus method name: " +
155                         "e.g. 'example.MyExampleClass.myExampleMethod'");
156             }
157             String JavaDoc className = this.staticMethod.substring(0, lastDotIndex);
158             String JavaDoc methodName = this.staticMethod.substring(lastDotIndex + 1);
159             this.targetClass = resolveClassName(className);
160             this.targetMethod = methodName;
161         }
162
163         if (this.targetClass == null) {
164             throw new IllegalArgumentException JavaDoc("Either targetClass or targetObject is required");
165         }
166         if (this.targetMethod == null) {
167             throw new IllegalArgumentException JavaDoc("targetMethod is required");
168         }
169         if (this.arguments == null) {
170             this.arguments = new Object JavaDoc[0];
171         }
172
173         Class JavaDoc[] argTypes = new Class JavaDoc[this.arguments.length];
174         for (int i = 0; i < this.arguments.length; ++i) {
175             argTypes[i] = (this.arguments[i] != null ? this.arguments[i].getClass() : Object JavaDoc.class);
176         }
177
178         // Try to get the exact method first.
179
try {
180             this.methodObject = this.targetClass.getMethod(this.targetMethod, argTypes);
181         }
182         catch (NoSuchMethodException JavaDoc ex) {
183             // Just rethrow exception if we can't get any match.
184
this.methodObject = findMatchingMethod();
185             if (this.methodObject == null) {
186                 throw ex;
187             }
188         }
189
190         if (this.targetObject == null && !Modifier.isStatic(this.methodObject.getModifiers())) {
191             throw new IllegalArgumentException JavaDoc("Target method must not be non-static without a target");
192         }
193     }
194
195     /**
196      * Resolve the given class name into a Class.
197      * <p>The default implementations uses <code>ClassUtils.forName</code>,
198      * using the thread context class loader.
199      * @param className the class name to resolve
200      * @return the resolved Class
201      * @throws ClassNotFoundException if the class name was invalid
202      */

203     protected Class JavaDoc resolveClassName(String JavaDoc className) throws ClassNotFoundException JavaDoc {
204         return ClassUtils.forName(className);
205     }
206
207     /**
208      * Find a matching method with the specified name for the specified arguments.
209      * @return a matching method, or <code>null</code> if none
210      * @see #getTargetClass()
211      * @see #getTargetMethod()
212      * @see #getArguments()
213      */

214     protected Method JavaDoc findMatchingMethod() {
215         String JavaDoc targetMethod = getTargetMethod();
216         Object JavaDoc[] arguments = getArguments();
217         int argCount = arguments.length;
218
219         Method JavaDoc[] candidates = getTargetClass().getMethods();
220         Method JavaDoc matchingMethod = null;
221         int numberOfMatchingMethods = 0;
222
223         for (int i = 0; i < candidates.length; i++) {
224             Method JavaDoc candidate = candidates[i];
225             Class JavaDoc[] paramTypes = candidate.getParameterTypes();
226             int paramCount = paramTypes.length;
227             if (candidate.getName().equals(targetMethod) && paramCount == argCount) {
228                 boolean match = true;
229                 for (int j = 0; j < paramCount && match; j++) {
230                     match = match && ClassUtils.isAssignableValue(paramTypes[j], arguments[j]);
231                 }
232                 if (match) {
233                     matchingMethod = candidate;
234                     numberOfMatchingMethods++;
235                 }
236             }
237         }
238
239         // Only return matching method if exactly one found.
240
if (numberOfMatchingMethods == 1) {
241             return matchingMethod;
242         }
243         else {
244             return null;
245         }
246     }
247
248     /**
249      * Return the prepared Method object that will be invoker.
250      * Can for example be used to determine the return type.
251      * @see #prepare
252      * @see #invoke
253      */

254     public Method JavaDoc getPreparedMethod() {
255         return this.methodObject;
256     }
257
258     /**
259      * Invoke the specified method.
260      * The invoker needs to have been prepared before.
261      * @return the object (possibly null) returned by the method invocation,
262      * or <code>null</code> if the method has a void return type
263      * @see #prepare
264      */

265     public Object JavaDoc invoke() throws InvocationTargetException JavaDoc, IllegalAccessException JavaDoc {
266         if (this.methodObject == null) {
267             throw new IllegalStateException JavaDoc("prepare() must be called prior to invoke() on MethodInvoker");
268         }
269         // In the static case, target will just be <code>null</code>.
270
return this.methodObject.invoke(this.targetObject, this.arguments);
271     }
272
273 }
274
Popular Tags