KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sf > jga > fn > property > InvokeMethod


1 // ============================================================================
2
// $Id: InvokeMethod.java,v 1.17 2006/05/22 03:28:53 davidahall Exp $
3
// Copyright (c) 2003-2005 David A. Hall
4
// ============================================================================
5
// The contents of this file are subject to the Common Development and
6
// Distribution License (CDDL), Version 1.0 (the License); you may not use this
7
// file except in compliance with the License. You should have received a copy
8
// of the the License along with this file: if not, a copy of the License is
9
// available from Sun Microsystems, Inc.
10
//
11
// http://www.sun.com/cddl/cddl.html
12
//
13
// From time to time, the license steward (initially Sun Microsystems, Inc.) may
14
// publish revised and/or new versions of the License. You may not use,
15
// distribute, or otherwise make this file available under subsequent versions
16
// of the License.
17
//
18
// Alternatively, the contents of this file may be used under the terms of the
19
// GNU Lesser General Public License Version 2.1 or later (the "LGPL"), in which
20
// case the provisions of the LGPL are applicable instead of those above. If you
21
// wish to allow use of your version of this file only under the terms of the
22
// LGPL, and not to allow others to use your version of this file under the
23
// terms of the CDDL, indicate your decision by deleting the provisions above
24
// and replace them with the notice and other provisions required by the LGPL.
25
// If you do not delete the provisions above, a recipient may use your version
26
// of this file under the terms of either the CDDL or the LGPL.
27
//
28
// This library is distributed in the hope that it will be useful,
29
// but WITHOUT ANY WARRANTY; without even the implied warranty of
30
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
31
// ============================================================================
32

33 package net.sf.jga.fn.property;
34
35 import java.lang.reflect.InvocationTargetException JavaDoc;
36 import java.lang.reflect.Method JavaDoc;
37 import java.text.MessageFormat JavaDoc;
38 import net.sf.jga.fn.BinaryFunctor;
39 import net.sf.jga.fn.EvaluationException;
40 import net.sf.jga.fn.UnaryFunctor;
41 import net.sf.jga.fn.adaptor.ChainBinary;
42 import net.sf.jga.fn.adaptor.ChainUnary;
43 import net.sf.jga.util.ArrayUtils;
44
45 /**
46  * Functor that invokes a method described at construction and returns the
47  * result or null if the result is void. The arguments must be passed to the
48  * functor in an array, and the values must be assignable to the corresponding
49  * classes given at construction.
50  * <p>
51  * Note that declaring the return type incorrectly can result in
52  * ClassCastExceptions being thrown when the functor is invoked: the compiler
53  * cannot check the return type of a reflectively loaded method.
54  * <p>
55  * Copyright &copy; 2003-2005 David A. Hall
56  *
57  * @author <a HREF="mailto:davidahall@users.sourceforge.net">David A. Hall</a>
58  **/

59
60 public class InvokeMethod<T,R> extends BinaryFunctor<T,Object JavaDoc[],R> {
61
62     static final long serialVersionUID = -4632096384509133504L;
63
64     // The class in which the method is accessed (not necessarily the class in which it is defined)
65
private Class JavaDoc<T> _objclass;
66
67     // The name of the method to invoke
68
private String JavaDoc _methName;
69
70     // The types of the arguments the method requires
71
private Class JavaDoc[] _argtypes;
72
73     // The method to be invoked (lazily loaded)
74
private transient Method JavaDoc _meth;
75
76     /**
77      * Builds a InvokeMethod for a given method, using the given class
78      * to find the desired method.
79      * @throws IllegalArgumentException if the method name is null or empty, or
80      * if the argument type array is null.
81      */

82     public InvokeMethod(Class JavaDoc<T> objClass, Method JavaDoc method) {
83         if (method == null) {
84             String JavaDoc msg = "Must supply method";
85             throw new IllegalArgumentException JavaDoc(msg);
86         }
87
88         if (objClass == null) {
89             String JavaDoc msg = "Must supply object class";
90             throw new IllegalArgumentException JavaDoc(msg);
91         }
92
93         if (!method.getDeclaringClass().isAssignableFrom(objClass)) {
94             String JavaDoc msg = "Method {0} not defined for class {1}";
95             Object JavaDoc[] args = { method.getName(), objClass.getName() };
96             throw new IllegalArgumentException JavaDoc(MessageFormat.format(msg, args));
97         }
98         
99         _objclass = objClass;
100         _meth = method;
101         _methName = method.getName();
102         _argtypes = method.getParameterTypes();
103     }
104
105     /**
106      * Builds an InvokeMethod for a given method, using the given class
107      * to find the desired method. Note that this is a convenience constructor
108      * for a common case: the case where the method takes a single argument.
109      * It is still necessary for the argument passed to the fn method to be an
110      * array, in this case it must be an array of length 1 containing a value of
111      * of type argtype. A ClassCastException may be thrown if this functor is
112      * called incorrectly: if the line number in the associated stack dump points
113      * to the class statement (on or about line 45), then the argument was likely
114      * passed without being wrapped in an array.
115      * @throws IllegalArgumentException if the method name is null or empty, or
116      * if the argument type array is null.
117      */

118     public InvokeMethod(Class JavaDoc<T> objClass, String JavaDoc methName, Class JavaDoc argtype) {
119         this(objClass, methName, new Class JavaDoc[]{argtype});
120     }
121
122     /**
123      * Builds a InvokeMethod for the given method, using the given class array
124      * to find the desired method.
125      * @throws IllegalArgumentException if the method name is null or empty, or
126      * if the argument type array is null.
127      */

128     public InvokeMethod(Class JavaDoc<T> objClass, String JavaDoc methName, Class JavaDoc... argtypes) {
129         if (methName == null || methName.length() == 0) {
130             String JavaDoc msg = "Must supply method name";
131             throw new IllegalArgumentException JavaDoc(msg);
132         }
133
134         if (objClass == null) {
135             String JavaDoc msg = "Must supply object class";
136             throw new IllegalArgumentException JavaDoc(msg);
137         }
138
139         _methName = methName;
140         _objclass = objClass;
141         _argtypes = argtypes;
142         
143         try {
144             _meth = _objclass.getMethod(_methName, _argtypes);
145         }
146         catch (NoSuchMethodException JavaDoc x) {
147             String JavaDoc msg = "No method {0} for class {1} that takes an argument(s) of type {2}";
148             Object JavaDoc[] args =
149                 new Object JavaDoc[]{_methName, _objclass.getName(), ArrayUtils.toString(_argtypes) };
150             IllegalArgumentException JavaDoc iax =
151                 new IllegalArgumentException JavaDoc(MessageFormat.format(msg,args));
152             iax.initCause(x);
153             throw iax;
154         }
155     }
156
157     /**
158      * Returns the class on which the method is invoked.
159      */

160     // UNTESTED
161
public Class JavaDoc<T> getObjectType() {
162         return _objclass;
163     }
164
165     /**
166      * Returns the name of the method that this functor invokes.
167      */

168     public String JavaDoc getMethodName() {
169         return _methName;
170     }
171
172
173     /**
174      * Returns the type of the method
175      */

176     public Class JavaDoc<R> getReturnType() {
177         return (Class JavaDoc<R>) _meth.getReturnType();
178     }
179
180     
181     /**
182      * Lazy loads the method
183      */

184     public synchronized Method JavaDoc getMethod() throws NoSuchMethodException JavaDoc {
185         if (_meth == null)
186             _meth = _objclass.getMethod(_methName, _argtypes);
187
188         return _meth;
189     }
190
191     
192     // BinaryFunctor interface
193

194     public R fn(T obj, Object JavaDoc[] args) {
195         try {
196             // @SuppressWarnings
197
// There's nothing we can do about this other than warn the users
198
// to make sure that they don't use an inappropriate return type
199

200
201             return (R) getMethod(/*_argtypes*/).invoke(obj, args);
202         }
203         catch (NoSuchMethodException JavaDoc x) {
204             String JavaDoc msg = "No method {0} for class {1} that takes an argument(s) of type {2}";
205             Object JavaDoc[] msgargs =
206                 new Object JavaDoc[]{_methName, _objclass.getName(), ArrayUtils.toString(_argtypes) };
207             throw new EvaluationException(MessageFormat.format(msg,msgargs), x);
208         }
209         catch (ClassCastException JavaDoc x) {
210             String JavaDoc msg = "ClassCastException: " +_objclass +"." +_methName
211                 +"("+ArrayUtils.toString(args)+")";
212             throw new EvaluationException(msg, x);
213         }
214         catch (IllegalAccessException JavaDoc x) {
215             String JavaDoc msg = _objclass +"." +_methName +" is not accessible";
216             throw new EvaluationException(msg, x);
217         }
218         catch (InvocationTargetException JavaDoc x) {
219             String JavaDoc xmsg = x.getMessage();
220             String JavaDoc msg = "InvocationException: " +_objclass +"." +_methName
221                 +"("+ArrayUtils.toString(args)+")"+(xmsg != null ? (":"+xmsg) : "");
222             throw new EvaluationException(msg, x);
223         }
224     }
225
226     /**
227      * Calls the Visitor's <code>visit(InvokeMethod)</code> method, if it
228      * implements the nested Visitor interface.
229      */

230     public void accept(net.sf.jga.fn.Visitor v) {
231         if (v instanceof InvokeMethod.Visitor)
232             ((InvokeMethod.Visitor)v).visit(this);
233         else
234             v.visit(this);
235     }
236     
237     // Object overrides
238

239     public String JavaDoc toString() {
240         return "InvokeMethod("+_meth+")";
241     }
242     
243    // AcyclicVisitor
244

245     /**
246      * Interface for classes that may interpret a <b>InvokeMethod</b>
247      * function.
248      */

249     public interface Visitor extends net.sf.jga.fn.Visitor {
250         public void visit(InvokeMethod host);
251     }
252 }
253
Popular Tags