added JSReflection.Wrap
[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[]) throw new JSExn("Reflection onto Object[] not supported yet");
20         return new Wrapper(o);
21     }
22
23     public static class Wrapper extends JS.Immutable {
24         private final Object o;
25         public Wrapper(Object o) { this.o = o; }
26         public Object unwrap() { return o; }
27         public Enumeration keys() throws JSExn { throw new JSExn("JSReflection.keys() not supported yet"); }
28         public JS get(JS key) throws JSExn {
29             String k = JSU.toString(key);
30             Class c = o.getClass();
31             while(c != null) {
32                 try {
33                     Field f = c.getField(k);
34                     if (f != null) return wrap(f.get(o));
35                 } catch (NoSuchFieldException nfe) {
36                 } catch (IllegalAccessException nfe) {
37                 } catch (SecurityException nfe) { }
38                 c = c.getSuperclass();
39             }
40             
41             try {
42                 java.lang.reflect.Method[] methods = o.getClass().getMethods();
43                 for(int i=0; i<methods.length; i++) if (methods[i].getName().equals(k)) return METHOD;
44             } catch (SecurityException nfe) { }
45             return null;
46         }
47         
48         public void put(JS key, JS val) throws JSExn { throw new JSExn("put() not supported yet"); }
49         
50         public JS call(JS method, JS[] args) throws JSExn {
51             String k = JSU.toString(method);
52             try {
53                 java.lang.reflect.Method[] methods = o.getClass().getMethods();
54                 for(int j=0; j<methods.length; j++) {
55                     if (methods[j].getName().equals(k) &&
56                         methods[j].getParameterTypes().length == args.length) {
57                         return wrap(methods[j].invoke(o, (Object[])args));
58                     }
59                 }
60             } catch (IllegalAccessException nfe) {
61             } catch (InvocationTargetException it) {
62                 Throwable ite = it.getTargetException();
63                 if (ite instanceof JSExn) throw ((JSExn)ite);
64                 JSU.warn(ite);
65                 throw new JSExn("unhandled reflected exception: " + ite.toString());
66             } catch (SecurityException nfe) { }
67             throw new JSExn("called a reflection method with the wrong number of arguments");
68         }
69     }
70
71     public static class Array extends JS.Immutable {
72         final Object[] arr;
73         public Array(Object[] arr) { this.arr = arr; }
74         // FEATURE: Add a JSCounterEnumeration
75         public Enumeration keys() throws JSExn {
76             return new Enumeration(null) {
77                 private int n = 0;
78                 public boolean _hasNext() { return n < arr.length; }
79                 public JS _next() { return JSU.N(n++); }
80             };
81         }
82         public JS get(JS key) throws JSExn { return wrap(arr[JSU.toInt(key)]); }
83     }
84
85     public Enumeration keys() throws JSExn { throw new JSExn("JSReflection.keys() not supported yet"); }
86
87     public JS get(JS key) throws JSExn {
88         String k = JSU.toString(key);
89         Class c = this.getClass();
90         while(c != null) {
91             try {
92                 Field f = c.getField(k);
93                 if (f != null) return wrap(f.get(this));
94             } catch (NoSuchFieldException nfe) {
95             } catch (IllegalAccessException nfe) {
96             } catch (SecurityException nfe) { }
97             c = c.getSuperclass();
98         }
99
100         try {
101             java.lang.reflect.Method[] methods = this.getClass().getMethods();
102             for(int i=0; i<methods.length; i++) if (methods[i].getName().equals(k)) return METHOD;
103         } catch (SecurityException nfe) { }
104         return null;
105     }
106
107     public void put(JS key, JS val) throws JSExn {
108         throw new JSExn("put() not supported yet");
109     }
110
111     public JS call(JS method, JS[] args) throws JSExn {
112         String k = JSU.toString(method);
113         try {
114             java.lang.reflect.Method[] methods = this.getClass().getMethods();
115             for(int j=0; j<methods.length; j++) {
116                 if (methods[j].getName().equals(k) &&
117                     methods[j].getParameterTypes().length == args.length) {
118                     return wrap(methods[j].invoke(this, (Object[])args));
119                 }
120             }
121         } catch (IllegalAccessException nfe) {
122         } catch (InvocationTargetException it) {
123             Throwable ite = it.getTargetException();
124             if (ite instanceof JSExn) throw ((JSExn)ite);
125             JSU.warn(ite);
126             throw new JSExn("unhandled reflected exception: " + ite.toString());
127         } catch (SecurityException nfe) { }
128         throw new JSExn("called a reflection method with the wrong number of arguments");
129     }
130