KickJava   Java API By Example, From Geeks To Geeks.

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


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) 2002-2004 Anders Bengtsson <ndrsbngtssn@yahoo.se>
15  * Copyright (C) 2002-2004 Jan Arne Petersen <jpetersen@uni-bonn.de>
16  * Copyright (C) 2004-2005 Thomas E Enebo <enebo@acm.org>
17  * Copyright (C) 2004 Stefan Matthias Aust <sma@3plus4.de>
18  * Copyright (C) 2004 David Corbin <dcorbin@users.sourceforge.net>
19  * Copyright (C) 2005 Charles O Nutter <headius@headius.com>
20  * Copyright (C) 2006 Kresten Krab Thorup <krab@gnu.org>
21  * Copyright (C) 2007 Miguel Covarrubias <mlcovarrubias@gmail.com>
22  *
23  * Alternatively, the contents of this file may be used under the terms of
24  * either of the GNU General Public License Version 2 or later (the "GPL"),
25  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26  * in which case the provisions of the GPL or the LGPL are applicable instead
27  * of those above. If you wish to allow use of your version of this file only
28  * under the terms of either the GPL or the LGPL, and not to allow others to
29  * use your version of this file under the terms of the CPL, indicate your
30  * decision by deleting the provisions above and replace them with the notice
31  * and other provisions required by the GPL or the LGPL. If you do not delete
32  * the provisions above, a recipient may use your version of this file under
33  * the terms of any one of the CPL, the GPL or the LGPL.
34  ***** END LICENSE BLOCK *****/

35 package org.jruby.javasupport;
36
37 import java.beans.BeanInfo JavaDoc;
38 import java.beans.IntrospectionException JavaDoc;
39 import java.beans.Introspector JavaDoc;
40 import java.beans.PropertyDescriptor JavaDoc;
41 import java.lang.reflect.Array JavaDoc;
42 import java.lang.reflect.Constructor JavaDoc;
43 import java.lang.reflect.Field JavaDoc;
44 import java.lang.reflect.Method JavaDoc;
45 import java.lang.reflect.Modifier JavaDoc;
46 import java.util.ArrayList JavaDoc;
47 import java.util.HashMap JavaDoc;
48 import java.util.Iterator JavaDoc;
49 import java.util.List JavaDoc;
50 import java.util.Map JavaDoc;
51 import java.util.regex.Matcher JavaDoc;
52 import java.util.regex.Pattern JavaDoc;
53
54 import org.jruby.Ruby;
55 import org.jruby.RubyArray;
56 import org.jruby.RubyBoolean;
57 import org.jruby.RubyClass;
58 import org.jruby.RubyFixnum;
59 import org.jruby.RubyInteger;
60 import org.jruby.RubyModule;
61 import org.jruby.RubyNumeric;
62 import org.jruby.RubyString;
63 import org.jruby.RubySymbol;
64 import org.jruby.exceptions.RaiseException;
65 import org.jruby.runtime.Arity;
66 import org.jruby.runtime.Block;
67 import org.jruby.runtime.CallType;
68 import org.jruby.runtime.CallbackFactory;
69 import org.jruby.runtime.ObjectAllocator;
70 import org.jruby.runtime.ThreadContext;
71 import org.jruby.runtime.builtin.IRubyObject;
72 import org.jruby.runtime.callback.Callback;
73
74 public class JavaClass extends JavaObject {
75
76     private JavaClass(Ruby runtime, Class JavaDoc javaClass) {
77         super(runtime, (RubyClass) runtime.getModule("Java").getClass("JavaClass"), javaClass);
78     }
79     
80     public static synchronized JavaClass get(Ruby runtime, Class JavaDoc klass) {
81         JavaClass javaClass = runtime.getJavaSupport().getJavaClassFromCache(klass);
82         if (javaClass == null) {
83             javaClass = new JavaClass(runtime, klass);
84             runtime.getJavaSupport().putJavaClassIntoCache(javaClass);
85         }
86         return javaClass;
87     }
88
89     public static RubyClass createJavaClassClass(Ruby runtime, RubyModule javaModule) {
90         // FIXME: Determine if a real allocator is needed here. Do people want to extend
91
// JavaClass? Do we want them to do that? Can you Class.new(JavaClass)? Should
92
// you be able to?
93
// TODO: NOT_ALLOCATABLE_ALLOCATOR is probably ok here, since we don't intend for people to monkey with
94
// this type and it can't be marshalled. Confirm. JRUBY-415
95
RubyClass result = javaModule.defineClassUnder("JavaClass", javaModule.getClass("JavaObject"), ObjectAllocator.NOT_ALLOCATABLE_ALLOCATOR);
96
97         CallbackFactory callbackFactory = runtime.callbackFactory(JavaClass.class);
98         
99         result.includeModule(runtime.getModule("Comparable"));
100         
101         JavaObject.registerRubyMethods(runtime, result);
102
103         result.getMetaClass().defineFastMethod("for_name",
104                 callbackFactory.getFastSingletonMethod("for_name", IRubyObject.class));
105         result.defineFastMethod("public?",
106                 callbackFactory.getFastMethod("public_p"));
107         result.defineFastMethod("protected?",
108                 callbackFactory.getFastMethod("protected_p"));
109         result.defineFastMethod("private?",
110                 callbackFactory.getFastMethod("private_p"));
111         result.defineFastMethod("final?",
112                 callbackFactory.getFastMethod("final_p"));
113         result.defineFastMethod("interface?",
114                 callbackFactory.getFastMethod("interface_p"));
115         result.defineFastMethod("array?",
116                 callbackFactory.getFastMethod("array_p"));
117         result.defineFastMethod("name",
118                 callbackFactory.getFastMethod("name"));
119         result.defineFastMethod("simple_name",
120                 callbackFactory.getFastMethod("simple_name"));
121         result.defineFastMethod("to_s",
122                 callbackFactory.getFastMethod("name"));
123         result.defineFastMethod("superclass",
124                 callbackFactory.getFastMethod("superclass"));
125         result.defineFastMethod("<=>",
126                 callbackFactory.getFastMethod("op_cmp", IRubyObject.class));
127         result.defineFastMethod("java_instance_methods",
128                 callbackFactory.getFastMethod("java_instance_methods"));
129         result.defineFastMethod("java_class_methods",
130                 callbackFactory.getFastMethod("java_class_methods"));
131         result.defineFastMethod("java_method",
132                 callbackFactory.getFastOptMethod("java_method"));
133         result.defineFastMethod("constructors",
134                 callbackFactory.getFastMethod("constructors"));
135         result.defineFastMethod("constructor",
136                 callbackFactory.getFastOptMethod("constructor"));
137         result.defineFastMethod("array_class",
138                 callbackFactory.getFastMethod("array_class"));
139         result.defineFastMethod("new_array",
140                 callbackFactory.getFastMethod("new_array", IRubyObject.class));
141         result.defineFastMethod("fields",
142                 callbackFactory.getFastMethod("fields"));
143         result.defineFastMethod("field",
144                 callbackFactory.getFastMethod("field", IRubyObject.class));
145         result.defineFastMethod("interfaces",
146                 callbackFactory.getFastMethod("interfaces"));
147         result.defineFastMethod("primitive?",
148                 callbackFactory.getFastMethod("primitive_p"));
149         result.defineFastMethod("assignable_from?",
150                 callbackFactory.getFastMethod("assignable_from_p", IRubyObject.class));
151         result.defineFastMethod("component_type",
152                 callbackFactory.getFastMethod("component_type"));
153         result.defineFastMethod("declared_instance_methods",
154                 callbackFactory.getFastMethod("declared_instance_methods"));
155         result.defineFastMethod("declared_class_methods",
156                 callbackFactory.getFastMethod("declared_class_methods"));
157         result.defineFastMethod("declared_fields",
158                 callbackFactory.getFastMethod("declared_fields"));
159         result.defineFastMethod("declared_field",
160                 callbackFactory.getFastMethod("declared_field", IRubyObject.class));
161         result.defineFastMethod("declared_constructors",
162                 callbackFactory.getFastMethod("declared_constructors"));
163         result.defineFastMethod("declared_constructor",
164                 callbackFactory.getFastOptMethod("declared_constructor"));
165         result.defineFastMethod("declared_classes",
166                 callbackFactory.getFastMethod("declared_classes"));
167         result.defineFastMethod("declared_method",
168                 callbackFactory.getFastOptMethod("declared_method"));
169         result.defineFastMethod("define_instance_methods_for_proxy",
170                 callbackFactory.getFastMethod("define_instance_methods_for_proxy", IRubyObject.class));
171         
172         result.getMetaClass().undefineMethod("new");
173         result.getMetaClass().undefineMethod("allocate");
174
175         return result;
176     }
177     
178     public static synchronized JavaClass for_name(IRubyObject recv, IRubyObject name) {
179         String JavaDoc className = name.asSymbol();
180         Class JavaDoc klass = recv.getRuntime().getJavaSupport().loadJavaClass(className);
181         return JavaClass.get(recv.getRuntime(), klass);
182     }
183     
184     /**
185      * Get all methods grouped by name (e.g. 'new => {new(), new(int), new(int, int)}, ...')
186      * @param isStatic determines whether you want static or instance methods from the class
187      */

188     private Map JavaDoc getMethodsClumped(boolean isStatic) {
189         Map JavaDoc map = new HashMap JavaDoc();
190         if(((Class JavaDoc)getValue()).isInterface()) {
191             return map;
192         }
193
194         Method JavaDoc methods[] = javaClass().getMethods();
195         
196         for (int i = 0; i < methods.length; i++) {
197             if (isStatic != Modifier.isStatic(methods[i].getModifiers())) {
198                 continue;
199             }
200             
201             String JavaDoc key = methods[i].getName();
202             RubyArray methodsWithName = (RubyArray) map.get(key);
203             
204             if (methodsWithName == null) {
205                 methodsWithName = RubyArray.newArrayLight(getRuntime());
206                 map.put(key, methodsWithName);
207             }
208             
209             methodsWithName.append(JavaMethod.create(getRuntime(), methods[i]));
210         }
211         
212         return map;
213     }
214     
215     private Map JavaDoc getPropertysClumped() {
216         Map JavaDoc map = new HashMap JavaDoc();
217         BeanInfo JavaDoc info;
218         
219         try {
220             info = Introspector.getBeanInfo(javaClass());
221         } catch (IntrospectionException JavaDoc e) {
222             return map;
223         }
224         
225         PropertyDescriptor JavaDoc[] descriptors = info.getPropertyDescriptors();
226         
227         for (int i = 0; i < descriptors.length; i++) {
228             Method JavaDoc readMethod = descriptors[i].getReadMethod();
229             
230             if (readMethod != null) {
231                 String JavaDoc key = readMethod.getName();
232                 List JavaDoc aliases = (List JavaDoc) map.get(key);
233                 
234                 if (aliases == null) {
235                     aliases = new ArrayList JavaDoc();
236                     
237                     map.put(key, aliases);
238                 }
239
240                 if (readMethod.getReturnType() == Boolean JavaDoc.class ||
241                     readMethod.getReturnType() == boolean.class) {
242                     aliases.add(descriptors[i].getName() + "?");
243                 }
244                 aliases.add(descriptors[i].getName());
245             }
246             
247             Method JavaDoc writeMethod = descriptors[i].getWriteMethod();
248
249             if (writeMethod != null) {
250                 String JavaDoc key = writeMethod.getName();
251                 List JavaDoc aliases = (List JavaDoc) map.get(key);
252                 
253                 if (aliases == null) {
254                     aliases = new ArrayList JavaDoc();
255                     map.put(key, aliases);
256                 }
257                 
258                 aliases.add(descriptors[i].getName() + "=");
259             }
260         }
261         
262         return map;
263     }
264     
265     private void define_instance_method_for_proxy(final RubyClass proxy, List JavaDoc names,
266             final RubyArray methods) {
267         final RubyModule javaUtilities = getRuntime().getModule("JavaUtilities");
268         Callback method = new Callback() {
269             private Map JavaDoc matchingMethods;
270             public IRubyObject execute(IRubyObject self, IRubyObject[] args, Block block) {
271                 IRubyObject[] argsArray = new IRubyObject[args.length + 1];
272                 ThreadContext context = self.getRuntime().getCurrentContext();
273                 
274                 argsArray[0] = self.getInstanceVariable("@java_object");
275                 RubyArray argsAsArray = RubyArray.newArrayLight(getRuntime());
276                 int argsTypeHash = 0;
277                 for (int j = 0; j < args.length; j++) {
278                     argsArray[j+1] = Java.ruby_to_java(proxy, args[j], Block.NULL_BLOCK);
279                     argsAsArray.append(argsArray[j+1]);
280                     // TODO: better hash combinator?
281
argsTypeHash += System.identityHashCode(args[j].getMetaClass());
282                 }
283                 Integer JavaDoc argsKey = new Integer JavaDoc(argsTypeHash);
284
285                 if (matchingMethods == null) {
286                     matchingMethods = new HashMap JavaDoc();
287                 }
288                 
289                 IRubyObject match = (IRubyObject)matchingMethods.get(argsKey);
290                 if (match == null) {
291                     IRubyObject[] mmArgs = new IRubyObject[] {methods, argsAsArray};
292                     match = javaUtilities.callMethod(context, "matching_method", mmArgs);
293                     matchingMethods.put(argsKey, match);
294                 }
295                 
296                 return Java.java_to_ruby(self, match.callMethod(context, "invoke", argsArray), Block.NULL_BLOCK);
297             }
298
299             public Arity getArity() {
300                 return Arity.optional();
301             }
302         };
303         
304         for(Iterator JavaDoc iter = names.iterator(); iter.hasNext(); ) {
305             String JavaDoc methodName = (String JavaDoc) iter.next();
306             
307             // We do not override class since it is too important to be overridden by getClass
308
// short name.
309
if (!methodName.equals("class")) {
310                 proxy.defineFastMethod(methodName, method);
311                 
312                 String JavaDoc rubyCasedName = getRubyCasedName(methodName);
313                 if (rubyCasedName != null) {
314                     proxy.defineAlias(rubyCasedName, methodName);
315                 }
316             }
317         }
318     }
319     
320     private static final Pattern JavaDoc CAMEL_CASE_SPLITTER = Pattern.compile("([a-z])([A-Z])");
321     
322     public static String JavaDoc getRubyCasedName(String JavaDoc javaCasedName) {
323         Matcher JavaDoc m = CAMEL_CASE_SPLITTER.matcher(javaCasedName);
324
325         String JavaDoc rubyCasedName = m.replaceAll("$1_$2").toLowerCase();
326         
327         if (rubyCasedName.equals(javaCasedName)) {
328             return null;
329         }
330         
331         return rubyCasedName;
332     }
333     
334     private static final Callback __jsend_method = new Callback() {
335             public IRubyObject execute(IRubyObject self, IRubyObject[] args, Block block) {
336                 int v = RubyNumeric.fix2int(((org.jruby.RubyMethod)self.method(((RubySymbol)args[0].callMethod(self.getRuntime().getCurrentContext(),"to_sym")))).arity());
337                 String JavaDoc name = args[0].asSymbol();
338
339                 IRubyObject[] newArgs = new IRubyObject[args.length - 1];
340                 System.arraycopy(args, 1, newArgs, 0, newArgs.length);
341
342                 if(v < 0 || v == (newArgs.length)) {
343                     return self.callMethod(self.getRuntime().getCurrentContext(), name, newArgs, CallType.FUNCTIONAL, block);
344                 } else {
345                     return self.callMethod(self.getRuntime().getCurrentContext(),self.getMetaClass().getSuperClass(), name, newArgs, CallType.SUPER, block);
346                 }
347             }
348
349             public Arity getArity() {
350                 return Arity.optional();
351             }
352         };
353
354     public IRubyObject define_instance_methods_for_proxy(IRubyObject arg) {
355         assert arg instanceof RubyClass;
356
357         Map JavaDoc aliasesClump = getPropertysClumped();
358         Map JavaDoc methodsClump = getMethodsClumped(false);
359         RubyClass proxy = (RubyClass) arg;
360
361         proxy.defineFastMethod("__jsend!", __jsend_method);
362         
363         for (Iterator JavaDoc iter = methodsClump.keySet().iterator(); iter.hasNext(); ) {
364             String JavaDoc name = (String JavaDoc) iter.next();
365             RubyArray methods = (RubyArray) methodsClump.get(name);
366             List JavaDoc aliases = (List JavaDoc) aliasesClump.get(name);
367
368             if (aliases == null) {
369                 aliases = new ArrayList JavaDoc();
370             }
371
372             aliases.add(name);
373             
374             define_instance_method_for_proxy(proxy, aliases, methods);
375         }
376         
377         return getRuntime().getNil();
378     }
379
380     public RubyBoolean public_p() {
381         return getRuntime().newBoolean(Modifier.isPublic(javaClass().getModifiers()));
382     }
383
384     public RubyBoolean protected_p() {
385         return getRuntime().newBoolean(Modifier.isProtected(javaClass().getModifiers()));
386     }
387
388     public RubyBoolean private_p() {
389         return getRuntime().newBoolean(Modifier.isPrivate(javaClass().getModifiers()));
390     }
391
392     Class JavaDoc javaClass() {
393         return (Class JavaDoc) getValue();
394     }
395
396     public RubyBoolean final_p() {
397         return getRuntime().newBoolean(Modifier.isFinal(javaClass().getModifiers()));
398     }
399
400     public RubyBoolean interface_p() {
401         return getRuntime().newBoolean(javaClass().isInterface());
402     }
403
404     public RubyBoolean array_p() {
405         return getRuntime().newBoolean(javaClass().isArray());
406     }
407     
408     public RubyString name() {
409         return getRuntime().newString(javaClass().getName());
410     }
411     
412
413     private static String JavaDoc getSimpleName(Class JavaDoc class_) {
414         if (class_.isArray()) {
415             return getSimpleName(class_.getComponentType()) + "[]";
416         }
417  
418         String JavaDoc className = class_.getName();
419  
420         int i = className.lastIndexOf('$');
421         if (i != -1) {
422             do {
423                 i++;
424             } while (i < className.length() && Character.isDigit(className.charAt(i)));
425             return className.substring(i);
426         }
427  
428         return className.substring(className.lastIndexOf('.') + 1);
429     }
430
431     public RubyString simple_name() {
432         return getRuntime().newString(getSimpleName(javaClass()));
433     }
434
435     public IRubyObject superclass() {
436         Class JavaDoc superclass = javaClass().getSuperclass();
437         if (superclass == null) {
438             return getRuntime().getNil();
439         }
440         return JavaClass.get(getRuntime(), superclass);
441     }
442
443     public RubyFixnum op_cmp(IRubyObject other) {
444         if (! (other instanceof JavaClass)) {
445             throw getRuntime().newTypeError("<=> requires JavaClass (" + other.getType() + " given)");
446         }
447         JavaClass otherClass = (JavaClass) other;
448         if (this.javaClass() == otherClass.javaClass()) {
449             return getRuntime().newFixnum(0);
450         }
451         if (otherClass.javaClass().isAssignableFrom(this.javaClass())) {
452             return getRuntime().newFixnum(-1);
453         }
454         return getRuntime().newFixnum(1);
455     }
456
457     public RubyArray java_instance_methods() {
458         return java_methods(javaClass().getMethods(), false);
459     }
460
461     public RubyArray declared_instance_methods() {
462         return java_methods(javaClass().getDeclaredMethods(), false);
463     }
464
465     private RubyArray java_methods(Method JavaDoc[] methods, boolean isStatic) {
466         RubyArray result = getRuntime().newArray(methods.length);
467         for (int i = 0; i < methods.length; i++) {
468             Method JavaDoc method = methods[i];
469             if (isStatic == Modifier.isStatic(method.getModifiers())) {
470                 result.append(JavaMethod.create(getRuntime(), method));
471             }
472         }
473         return result;
474     }
475
476     public RubyArray java_class_methods() {
477         return java_methods(javaClass().getMethods(), true);
478     }
479
480     public RubyArray declared_class_methods() {
481         return java_methods(javaClass().getDeclaredMethods(), true);
482     }
483
484     public JavaMethod java_method(IRubyObject[] args) throws ClassNotFoundException JavaDoc {
485         String JavaDoc methodName = args[0].asSymbol();
486         Class JavaDoc[] argumentTypes = buildArgumentTypes(args);
487         return JavaMethod.create(getRuntime(), javaClass(), methodName, argumentTypes);
488     }
489
490     public JavaMethod declared_method(IRubyObject[] args) throws ClassNotFoundException JavaDoc {
491         String JavaDoc methodName = args[0].asSymbol();
492         Class JavaDoc[] argumentTypes = buildArgumentTypes(args);
493         return JavaMethod.createDeclared(getRuntime(), javaClass(), methodName, argumentTypes);
494     }
495
496     private Class JavaDoc[] buildArgumentTypes(IRubyObject[] args) throws ClassNotFoundException JavaDoc {
497         if (args.length < 1) {
498             throw getRuntime().newArgumentError(args.length, 1);
499         }
500         Class JavaDoc[] argumentTypes = new Class JavaDoc[args.length - 1];
501         for (int i = 1; i < args.length; i++) {
502             JavaClass type = for_name(this, args[i]);
503             argumentTypes[i - 1] = type.javaClass();
504         }
505         return argumentTypes;
506     }
507
508     public RubyArray constructors() {
509         return buildConstructors(javaClass().getConstructors());
510     }
511     
512     public RubyArray declared_classes() {
513         return buildClasses(javaClass().getDeclaredClasses());
514     }
515     
516     private RubyArray buildClasses(Class JavaDoc [] classes) {
517         RubyArray result = getRuntime().newArray(classes.length);
518         for (int i = 0; i < classes.length; i++) {
519             result.append(new JavaClass(getRuntime(), classes[i]));
520         }
521         return result;
522     }
523     
524
525     public RubyArray declared_constructors() {
526         return buildConstructors(javaClass().getDeclaredConstructors());
527     }
528
529     private RubyArray buildConstructors(Constructor JavaDoc[] constructors) {
530         RubyArray result = getRuntime().newArray(constructors.length);
531         for (int i = 0; i < constructors.length; i++) {
532             result.append(new JavaConstructor(getRuntime(), constructors[i]));
533         }
534         return result;
535     }
536
537     public JavaConstructor constructor(IRubyObject[] args) {
538         try {
539             Class JavaDoc[] parameterTypes = buildClassArgs(args);
540             Constructor JavaDoc constructor;
541             constructor = javaClass().getConstructor(parameterTypes);
542             return new JavaConstructor(getRuntime(), constructor);
543         } catch (NoSuchMethodException JavaDoc nsme) {
544             throw getRuntime().newNameError("no matching java constructor", null);
545         }
546     }
547
548     public JavaConstructor declared_constructor(IRubyObject[] args) {
549         try {
550             Class JavaDoc[] parameterTypes = buildClassArgs(args);
551             Constructor JavaDoc constructor;
552             constructor = javaClass().getDeclaredConstructor (parameterTypes);
553             return new JavaConstructor(getRuntime(), constructor);
554         } catch (NoSuchMethodException JavaDoc nsme) {
555             throw getRuntime().newNameError("no matching java constructor", null);
556         }
557     }
558
559     private Class JavaDoc[] buildClassArgs(IRubyObject[] args) {
560         Class JavaDoc[] parameterTypes = new Class JavaDoc[args.length];
561         for (int i = 0; i < args.length; i++) {
562             String JavaDoc name = args[i].asSymbol();
563             parameterTypes[i] = getRuntime().getJavaSupport().loadJavaClass(name);
564         }
565         return parameterTypes;
566     }
567
568     public JavaClass array_class() {
569         return JavaClass.get(getRuntime(), Array.newInstance(javaClass(), 0).getClass());
570     }
571    
572     public JavaObject new_array(IRubyObject lengthArgument) {
573         if (lengthArgument instanceof RubyInteger) {
574             // one-dimensional array
575
int length = (int) ((RubyInteger) lengthArgument).getLongValue();
576         return new JavaArray(getRuntime(), Array.newInstance(javaClass(), length));
577         } else if (lengthArgument instanceof RubyArray) {
578             // n-dimensional array
579
List JavaDoc list = ((RubyArray)lengthArgument).getList();
580             int length = list.size();
581             if (length == 0) {
582                 throw getRuntime().newArgumentError("empty dimensions specifier for java array");
583     }
584             int[] dimensions = new int[length];
585             for (int i = length; --i >= 0; ) {
586                 IRubyObject dimensionLength = (IRubyObject)list.get(i);
587                 if ( !(dimensionLength instanceof RubyInteger) ) {
588                     throw getRuntime()
589                         .newTypeError(dimensionLength, getRuntime().getClass("Integer"));
590                 }
591                 dimensions[i] = (int) ((RubyInteger) dimensionLength).getLongValue();
592             }
593             return new JavaArray(getRuntime(), Array.newInstance(javaClass(), dimensions));
594         } else {
595             throw getRuntime().newArgumentError(
596                   "invalid length or dimensions specifier for java array" +
597                   " - must be Integer or Array of Integer");
598         }
599     }
600
601     public RubyArray fields() {
602         return buildFieldResults(javaClass().getFields());
603     }
604
605     public RubyArray declared_fields() {
606         return buildFieldResults(javaClass().getDeclaredFields());
607     }
608     
609     private RubyArray buildFieldResults(Field JavaDoc[] fields) {
610         RubyArray result = getRuntime().newArray(fields.length);
611         for (int i = 0; i < fields.length; i++) {
612             result.append(new JavaField(getRuntime(), fields[i]));
613         }
614         return result;
615     }
616
617     public JavaField field(IRubyObject name) {
618         String JavaDoc stringName = name.asSymbol();
619         try {
620             Field JavaDoc field = javaClass().getField(stringName);
621             return new JavaField(getRuntime(),field);
622         } catch (NoSuchFieldException JavaDoc nsfe) {
623             throw undefinedFieldError(stringName);
624         }
625     }
626
627     public JavaField declared_field(IRubyObject name) {
628         String JavaDoc stringName = name.asSymbol();
629         try {
630             Field JavaDoc field = javaClass().getDeclaredField(stringName);
631             return new JavaField(getRuntime(),field);
632         } catch (NoSuchFieldException JavaDoc nsfe) {
633             throw undefinedFieldError(stringName);
634         }
635     }
636
637     private RaiseException undefinedFieldError(String JavaDoc name) {
638         return getRuntime().newNameError("undefined field '" + name + "' for class '" + javaClass().getName() + "'", name);
639     }
640
641     public RubyArray interfaces() {
642         Class JavaDoc[] interfaces = javaClass().getInterfaces();
643         RubyArray result = getRuntime().newArray(interfaces.length);
644         for (int i = 0; i < interfaces.length; i++) {
645             result.append(JavaClass.get(getRuntime(), interfaces[i]));
646         }
647         return result;
648     }
649
650     public RubyBoolean primitive_p() {
651         return getRuntime().newBoolean(isPrimitive());
652     }
653
654     public RubyBoolean assignable_from_p(IRubyObject other) {
655         if (! (other instanceof JavaClass)) {
656             throw getRuntime().newTypeError("assignable_from requires JavaClass (" + other.getType() + " given)");
657         }
658
659         Class JavaDoc otherClass = ((JavaClass) other).javaClass();
660
661         if (!javaClass().isPrimitive() && otherClass == Void.TYPE ||
662             javaClass().isAssignableFrom(otherClass)) {
663             return getRuntime().getTrue();
664         }
665         otherClass = JavaUtil.primitiveToWrapper(otherClass);
666         Class JavaDoc thisJavaClass = JavaUtil.primitiveToWrapper(javaClass());
667         if (thisJavaClass.isAssignableFrom(otherClass)) {
668             return getRuntime().getTrue();
669         }
670         if (Number JavaDoc.class.isAssignableFrom(thisJavaClass)) {
671             if (Number JavaDoc.class.isAssignableFrom(otherClass)) {
672                 return getRuntime().getTrue();
673             }
674             if (otherClass.equals(Character JavaDoc.class)) {
675                 return getRuntime().getTrue();
676             }
677         }
678         if (thisJavaClass.equals(Character JavaDoc.class)) {
679             if (Number JavaDoc.class.isAssignableFrom(otherClass)) {
680                 return getRuntime().getTrue();
681             }
682         }
683         return getRuntime().getFalse();
684     }
685
686     private boolean isPrimitive() {
687         return javaClass().isPrimitive();
688     }
689
690     public JavaClass component_type() {
691         if (! javaClass().isArray()) {
692             throw getRuntime().newTypeError("not a java array-class");
693         }
694         return JavaClass.get(getRuntime(), javaClass().getComponentType());
695     }
696 }
697
Popular Tags