KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jruby > javasupport > JavaMethod


1 /***** BEGIN LICENSE BLOCK *****
2  * Version: CPL 1.0/GPL 2.0/LGPL 2.1
3  *
4  * The contents of this file are subject to the Common Public
5  * License Version 1.0 (the "License"); you may not use this file
6  * except in compliance with the License. You may obtain a copy of
7  * the License at http://www.eclipse.org/legal/cpl-v10.html
8  *
9  * Software distributed under the License is distributed on an "AS
10  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
11  * implied. See the License for the specific language governing
12  * rights and limitations under the License.
13  *
14  * Copyright (C) 2001 Chad Fowler <chadfowler@chadfowler.com>
15  * Copyright (C) 2001 Alan Moore <alan_moore@gmx.net>
16  * Copyright (C) 2001-2004 Jan Arne Petersen <jpetersen@uni-bonn.de>
17  * Copyright (C) 2002 Benoit Cerrina <b.cerrina@wanadoo.fr>
18  * Copyright (C) 2002-2004 Anders Bengtsson <ndrsbngtssn@yahoo.se>
19  * Copyright (C) 2004 Stefan Matthias Aust <sma@3plus4.de>
20  * Copyright (C) 2004 Thomas E Enebo <enebo@acm.org>
21  * Copyright (C) 2004 David Corbin <dcorbin@users.sourceforge.net>
22  * Copyright (C) 2005 Charles O Nutter <headius@headius.com>
23  * Copyright (C) 2006 Kresten Krab Thorup <krab@gnu.org>
24  *
25  * Alternatively, the contents of this file may be used under the terms of
26  * either of the GNU General Public License Version 2 or later (the "GPL"),
27  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28  * in which case the provisions of the GPL or the LGPL are applicable instead
29  * of those above. If you wish to allow use of your version of this file only
30  * under the terms of either the GPL or the LGPL, and not to allow others to
31  * use your version of this file under the terms of the CPL, indicate your
32  * decision by deleting the provisions above and replace them with the notice
33  * and other provisions required by the GPL or the LGPL. If you do not delete
34  * the provisions above, a recipient may use your version of this file under
35  * the terms of any one of the CPL, the GPL or the LGPL.
36  ***** END LICENSE BLOCK *****/

37 package org.jruby.javasupport;
38
39 import java.lang.reflect.AccessibleObject JavaDoc;
40 import java.lang.reflect.InvocationTargetException JavaDoc;
41 import java.lang.reflect.Method JavaDoc;
42 import java.lang.reflect.Modifier JavaDoc;
43
44 import org.jruby.Ruby;
45 import org.jruby.RubyBoolean;
46 import org.jruby.RubyClass;
47 import org.jruby.RubyModule;
48 import org.jruby.RubyString;
49 import org.jruby.exceptions.RaiseException;
50 import org.jruby.javasupport.proxy.InternalJavaProxy;
51 import org.jruby.javasupport.proxy.JavaProxyClass;
52 import org.jruby.javasupport.proxy.JavaProxyMethod;
53 import org.jruby.runtime.CallbackFactory;
54 import org.jruby.runtime.ObjectAllocator;
55 import org.jruby.runtime.builtin.IRubyObject;
56
57 public class JavaMethod extends JavaCallable {
58     private final Method JavaDoc method;
59
60     public static RubyClass createJavaMethodClass(Ruby runtime, RubyModule javaModule) {
61         // TODO: NOT_ALLOCATABLE_ALLOCATOR is probably ok here, since we don't intend for people to monkey with
62
// this type and it can't be marshalled. Confirm. JRUBY-415
63
RubyClass result =
64             javaModule.defineClassUnder("JavaMethod", runtime.getObject(), ObjectAllocator.NOT_ALLOCATABLE_ALLOCATOR);
65         CallbackFactory callbackFactory = runtime.callbackFactory(JavaMethod.class);
66
67         JavaAccessibleObject.registerRubyMethods(runtime, result);
68         
69         result.defineFastMethod("name", callbackFactory.getFastMethod("name"));
70         result.defineFastMethod("arity", callbackFactory.getFastMethod("arity"));
71         result.defineFastMethod("public?", callbackFactory.getFastMethod("public_p"));
72         result.defineFastMethod("final?", callbackFactory.getFastMethod("final_p"));
73         result.defineFastMethod("static?", callbackFactory.getFastMethod("static_p"));
74         result.defineFastMethod("invoke", callbackFactory.getFastOptMethod("invoke"));
75         result.defineFastMethod("invoke_static", callbackFactory.getFastOptMethod("invoke_static"));
76         result.defineFastMethod("argument_types", callbackFactory.getFastMethod("argument_types"));
77         result.defineFastMethod("inspect", callbackFactory.getFastMethod("inspect"));
78         result.defineFastMethod("return_type", callbackFactory.getFastMethod("return_type"));
79
80         return result;
81     }
82
83     public JavaMethod(Ruby runtime, Method JavaDoc method) {
84         super(runtime, (RubyClass) runtime.getModule("Java").getClass("JavaMethod"));
85         this.method = method;
86
87         // Special classes like Collections.EMPTY_LIST are inner classes that are private but
88
// implement public interfaces. Their methods are all public methods for the public
89
// interface. Let these public methods execute via setAccessible(true).
90
if (Modifier.isPublic(method.getModifiers()) &&
91             Modifier.isPublic(method.getClass().getModifiers()) &&
92             !Modifier.isPublic(method.getDeclaringClass().getModifiers())) {
93             accesibleObject().setAccessible(true);
94         }
95     }
96
97     public static JavaMethod create(Ruby runtime, Method JavaDoc method) {
98         return new JavaMethod(runtime, method);
99     }
100
101     public static JavaMethod create(Ruby runtime, Class JavaDoc javaClass, String JavaDoc methodName, Class JavaDoc[] argumentTypes) {
102         try {
103             Method JavaDoc method = javaClass.getMethod(methodName, argumentTypes);
104             return create(runtime, method);
105         } catch (NoSuchMethodException JavaDoc e) {
106             throw runtime.newNameError("undefined method '" + methodName + "' for class '" + javaClass.getName() + "'",
107                     methodName);
108         }
109     }
110
111     public static JavaMethod createDeclared(Ruby runtime, Class JavaDoc javaClass, String JavaDoc methodName, Class JavaDoc[] argumentTypes) {
112         try {
113             Method JavaDoc method = javaClass.getDeclaredMethod(methodName, argumentTypes);
114             return create(runtime, method);
115         } catch (NoSuchMethodException JavaDoc e) {
116             throw runtime.newNameError("undefined method '" + methodName + "' for class '" + javaClass.getName() + "'",
117                     methodName);
118         }
119     }
120
121     public RubyString name() {
122         return getRuntime().newString(method.getName());
123     }
124
125     protected int getArity() {
126         return method.getParameterTypes().length;
127     }
128
129     public RubyBoolean public_p() {
130         return getRuntime().newBoolean(Modifier.isPublic(method.getModifiers()));
131     }
132
133     public RubyBoolean final_p() {
134         return getRuntime().newBoolean(Modifier.isFinal(method.getModifiers()));
135     }
136
137     public IRubyObject invoke(IRubyObject[] args) {
138         if (args.length != 1 + getArity()) {
139             throw getRuntime().newArgumentError(args.length, 1 + getArity());
140         }
141
142         IRubyObject invokee = args[0];
143         if (! (invokee instanceof JavaObject)) {
144             throw getRuntime().newTypeError("invokee not a java object");
145         }
146         Object JavaDoc javaInvokee = ((JavaObject) invokee).getValue();
147         Object JavaDoc[] arguments = new Object JavaDoc[args.length - 1];
148         System.arraycopy(args, 1, arguments, 0, arguments.length);
149         convertArguments(arguments);
150
151         if (! method.getDeclaringClass().isInstance(javaInvokee)) {
152             throw getRuntime().newTypeError("invokee not instance of method's class (" +
153                                               "got" + javaInvokee.getClass().getName() + " wanted " +
154                                               method.getDeclaringClass().getName() + ")");
155         }
156         
157         //
158
// this test really means, that this is a ruby-defined subclass of a java class
159
//
160
if (javaInvokee instanceof InternalJavaProxy) {
161             JavaProxyClass jpc = ((InternalJavaProxy) javaInvokee)
162                     .___getProxyClass();
163             JavaProxyMethod jpm;
164             try {
165                 jpm = jpc.getMethod(method.getName(), method
166                         .getParameterTypes());
167             } catch (NoSuchMethodException JavaDoc e) {
168                 RaiseException err = getRuntime().newTypeError(
169                         "mismatch with proxy/super method?");
170                 err.initCause(e);
171                 throw err;
172             }
173             if (jpm.hasSuperImplementation()) {
174                 return invokeWithExceptionHandling(jpm.getSuperMethod(),
175                         javaInvokee, arguments);
176             }
177
178         }
179         
180         return invokeWithExceptionHandling(method, javaInvokee, arguments);
181     }
182
183     public IRubyObject invoke_static(IRubyObject[] args) {
184         if (args.length != getArity()) {
185             throw getRuntime().newArgumentError(args.length, getArity());
186         }
187         Object JavaDoc[] arguments = new Object JavaDoc[args.length];
188         System.arraycopy(args, 0, arguments, 0, arguments.length);
189         convertArguments(arguments);
190         return invokeWithExceptionHandling(method, null, arguments);
191     }
192
193     public IRubyObject return_type() {
194         Class JavaDoc klass = method.getReturnType();
195         
196         if (klass.equals(void.class)) {
197             return getRuntime().getNil();
198         }
199         return JavaClass.get(getRuntime(), klass);
200     }
201
202     private IRubyObject invokeWithExceptionHandling(Method JavaDoc method, Object JavaDoc javaInvokee, Object JavaDoc[] arguments) {
203         try {
204             Object JavaDoc result = method.invoke(javaInvokee, arguments);
205             return JavaObject.wrap(getRuntime(), result);
206         } catch (IllegalArgumentException JavaDoc iae) {
207             throw getRuntime().newTypeError("expected " + argument_types().inspect());
208         } catch (IllegalAccessException JavaDoc iae) {
209             throw getRuntime().newTypeError("illegal access on '" + method.getName() + "': " + iae.getMessage());
210         } catch (InvocationTargetException JavaDoc ite) {
211             getRuntime().getJavaSupport().handleNativeException(ite.getTargetException());
212             // This point is only reached if there was an exception handler installed.
213
return getRuntime().getNil();
214         }
215     }
216
217     private void convertArguments(Object JavaDoc[] arguments) {
218         Class JavaDoc[] parameterTypes = parameterTypes();
219         for (int i = 0; i < arguments.length; i++) {
220             arguments[i] = JavaUtil.convertArgument(arguments[i], parameterTypes[i]);
221         }
222     }
223
224     protected Class JavaDoc[] parameterTypes() {
225         return method.getParameterTypes();
226     }
227
228     protected String JavaDoc nameOnInspection() {
229         return "#<" + getType().toString() + "/" + method.getName() + "(";
230     }
231
232     public RubyBoolean static_p() {
233         return getRuntime().newBoolean(isStatic());
234     }
235
236     private boolean isStatic() {
237         return Modifier.isStatic(method.getModifiers());
238     }
239
240     protected int getModifiers() {
241         return method.getModifiers();
242     }
243
244     protected AccessibleObject JavaDoc accesibleObject() {
245         return method;
246     }
247 }
248
Popular Tags