fix to JSReflection for grabbing from a superclass
[org.ibex.js.git] / src / org / ibex / js / JSReflection.java
1 // Copyright 2000-2005 the Contributors, as shown in the revision logs.
2 // Licensed under the Apache Public Source License 2.0 ("the License").
3 // You may not use this file except in compliance with the License.
4
5 package org.ibex.js; 
6
7 import java.lang.reflect.*;
8
9 /** Automatic JS-ification via Reflection (not for use in the core) */
10 public class JSReflection extends JS.Immutable {
11     private static final JS.Method METHOD = new JS.Method();
12
13     public static JS wrap(Object o) throws JSExn {
14         if (o == null) return null;
15         if (o instanceof String) return JSU.S((String)o);
16         if (o instanceof Boolean) return JSU.B(((Boolean)o).booleanValue());
17         if (o instanceof Number) return JSU.N((Number)o);
18         if (o instanceof JS) return (JS)o;
19         if (o instanceof Object[]) {
20             // FIXME: get element type here
21         }
22         throw new JSExn("Reflection object tried to return a " + o.getClass().getName());
23     }
24
25     public static class Array extends JS.Immutable {
26         final Object[] arr;
27         public Array(Object[] arr) { this.arr = arr; }
28         // FEATURE: Add a JSCounterEnumeration
29         public Enumeration keys() throws JSExn {
30             return new Enumeration(null) {
31                 private int n = 0;
32                 public boolean _hasNext() { return n < arr.length; }
33                 public JS _next() { return JSU.N(n++); }
34             };
35         }
36         public JS get(JS key) throws JSExn { return wrap(arr[JSU.toInt(key)]); }
37     }
38
39     // FIXME public static class Hash { }
40     // FIXME public Enumeration keys() throws JSExn {  }
41
42     public JS get(JS key) throws JSExn {
43         String k = JSU.toString(key);
44         Class c = this.getClass();
45         while(c != null) {
46             try {
47                 Field f = c.getField(k);
48                 return wrap(f.get(this));
49             } catch (NoSuchFieldException nfe) {
50             } catch (IllegalAccessException nfe) {
51             } catch (SecurityException nfe) { }
52             c = c.getSuperclass();
53         }
54
55         try {
56             java.lang.reflect.Method[] methods = this.getClass().getMethods();
57             for(int i=0; i<methods.length; i++) if (methods[i].getName().equals(k)) return METHOD;
58         } catch (SecurityException nfe) { }
59         return null;
60     }
61
62     public void put(JS key, JS val) throws JSExn {
63         throw new JSExn("put() not supported yet");
64     }
65
66     public JS call(JS method, JS[] args) throws JSExn {
67         String k = JSU.toString(method);
68         try {
69             java.lang.reflect.Method[] methods = this.getClass().getMethods();
70             for(int j=0; j<methods.length; j++) {
71                 if (methods[j].getName().equals(k) &&
72                     methods[j].getParameterTypes().length == args.length) {
73                     return wrap(methods[j].invoke(this, (Object[])args));
74                 }
75             }
76         } catch (IllegalAccessException nfe) {
77         } catch (InvocationTargetException it) {
78             Throwable ite = it.getTargetException();
79             if (ite instanceof JSExn) throw ((JSExn)ite);
80             JSU.warn(ite);
81             throw new JSExn("unhandled reflected exception: " + ite.toString());
82         } catch (SecurityException nfe) { }
83         throw new JSExn("called a reflection method with the wrong number of arguments");
84     }
85