comparison src/luan/lib/JavaLib.java @ 37:8a57ebfdfd78

add JavaLib git-svn-id: https://luan-java.googlecode.com/svn/trunk@38 21e917c8-12df-6dd8-5cb6-c86387c605b9
author fschmidt@gmail.com <fschmidt@gmail.com@21e917c8-12df-6dd8-5cb6-c86387c605b9>
date Thu, 20 Dec 2012 02:36:07 +0000
parents
children e3624b7cd603
comparison
equal deleted inserted replaced
36:2a35154aec14 37:8a57ebfdfd78
1 package luan.lib;
2
3 import java.lang.reflect.Array;
4 import java.lang.reflect.Member;
5 import java.lang.reflect.Field;
6 import java.lang.reflect.Method;
7 import java.lang.reflect.Constructor;
8 import java.lang.reflect.Modifier;
9 import java.util.Map;
10 import java.util.HashMap;
11 import java.util.List;
12 import java.util.ArrayList;
13 import java.util.Iterator;
14 import luan.LuaNumber;
15 import luan.LuaState;
16 import luan.LuaTable;
17 import luan.MetatableGetter;
18 import luan.LuaException;
19 import luan.LuaFunction;
20 import luan.LuaJavaFunction;
21
22
23 public final class JavaLib {
24
25 public static void register(LuaState lua) {
26 lua.addMetatableGetter(mg);
27 LuaTable module = new LuaTable();
28 LuaTable global = lua.global();
29 global.put("java",module);
30 try {
31 global.put( "import", new LuaJavaFunction(JavaLib.class.getMethod("importClass",LuaState.class,String.class),null) );
32 module.put( "class", new LuaJavaFunction(JavaLib.class.getMethod("getClass",String.class),null) );
33 } catch(NoSuchMethodException e) {
34 throw new RuntimeException(e);
35 }
36 add( global, "ipairs", Object.class );
37 add( global, "pairs", Object.class );
38 }
39
40 private static final LuaTable mt = new LuaTable();
41 static {
42 add( mt, "__index", Object.class, Object.class );
43 }
44
45 private static void add(LuaTable t,String method,Class<?>... parameterTypes) {
46 try {
47 t.put( method, new LuaJavaFunction(JavaLib.class.getMethod(method,parameterTypes),null) );
48 } catch(NoSuchMethodException e) {
49 throw new RuntimeException(e);
50 }
51 }
52
53 private static final MetatableGetter mg = new MetatableGetter() {
54 public LuaTable getMetatable(Object obj) {
55 if( obj==null )
56 return null;
57 return mt;
58 }
59 };
60
61 public static Object __index(Object obj,Object key) throws LuaException {
62 if( obj instanceof Static ) {
63 if( key instanceof String ) {
64 String name = (String)key;
65 Static st = (Static)obj;
66 Class cls = st.cls;
67 if( "class".equals(name) ) {
68 return cls;
69 } else if( "new".equals(name) ) {
70 Constructor<?>[] constructors = cls.getConstructors();
71 if( constructors.length > 0 ) {
72 if( constructors.length==1 ) {
73 return new LuaJavaFunction(constructors[0],null);
74 } else {
75 List<LuaJavaFunction> fns = new ArrayList<LuaJavaFunction>();
76 for( Constructor constructor : constructors ) {
77 fns.add(new LuaJavaFunction(constructor,null));
78 }
79 return new AmbiguousJavaFunction(fns);
80 }
81 }
82 } else {
83 List<Member> members = getStaticMembers(cls,name);
84 if( !members.isEmpty() ) {
85 return member(null,members);
86 }
87 }
88 }
89 throw new LuaException("invalid index for java class: "+key);
90 }
91 Class cls = obj.getClass();
92 if( cls.isArray() ) {
93 if( "length".equals(key) ) {
94 return Array.getLength(obj);
95 }
96 if( key instanceof LuaNumber ) {
97 LuaNumber n = (LuaNumber)key;
98 double d = n.value();
99 int i = (int)d;
100 if( d==i ) {
101 return Array.get(obj,i);
102 }
103 }
104 throw new LuaException("invalid index for java array: "+key);
105 }
106 if( key instanceof String ) {
107 String name = (String)key;
108 if( "instanceof".equals(name) ) {
109 return new LuaJavaFunction(instanceOf,new InstanceOf(obj));
110 } else {
111 List<Member> members = getMembers(cls,name);
112 if( !members.isEmpty() ) {
113 return member(obj,members);
114 }
115 }
116 }
117 throw new LuaException("invalid index for java object: "+key);
118 }
119
120 private static Object member(Object obj,List<Member> members) throws LuaException {
121 try {
122 if( members.size()==1 ) {
123 Member member = members.get(0);
124 if( member instanceof Field ) {
125 Field field = (Field)member;
126 Object value = field.get(obj);
127 if( value instanceof Number ) {
128 Number n = (Number)value;
129 value = new LuaNumber(n.doubleValue());
130 }
131 return value;
132 } else {
133 Method method = (Method)member;
134 return new LuaJavaFunction(method,obj);
135 }
136 } else {
137 List<LuaJavaFunction> fns = new ArrayList<LuaJavaFunction>();
138 for( Member member : members ) {
139 Method method = (Method)member;
140 fns.add(new LuaJavaFunction(method,obj));
141 }
142 return new AmbiguousJavaFunction(fns);
143 }
144 } catch(IllegalAccessException e) {
145 throw new RuntimeException(e);
146 }
147 }
148
149 private static Map<Class,Map<String,List<Member>>> memberMap = new HashMap<Class,Map<String,List<Member>>>();
150
151 private static synchronized List<Member> getMembers(Class cls,String name) {
152 Map<String,List<Member>> clsMap = memberMap.get(cls);
153 if( clsMap == null ) {
154 clsMap = new HashMap<String,List<Member>>();
155 for( Field field : cls.getFields() ) {
156 String s = field.getName();
157 List<Member> list = clsMap.get(s);
158 if( list == null ) {
159 list = new ArrayList<Member>();
160 clsMap.put(s,list);
161 }
162 list.add(field);
163 }
164 for( Method method : cls.getMethods() ) {
165 String s = method.getName();
166 List<Member> list = clsMap.get(s);
167 if( list == null ) {
168 list = new ArrayList<Member>();
169 clsMap.put(s,list);
170 }
171 list.add(method);
172 }
173 memberMap.put(cls,clsMap);
174 }
175 return clsMap.get(name);
176 }
177
178 private static synchronized List<Member> getStaticMembers(Class cls,String name) {
179 List<Member> staticMembers = new ArrayList<Member>();
180 for( Member m : getMembers(cls,name) ) {
181 if( Modifier.isStatic(m.getModifiers()) )
182 staticMembers.add(m);
183 }
184 return staticMembers;
185 }
186
187 static class Static {
188 final Class cls;
189
190 Static(Class cls) {
191 this.cls = cls;
192 }
193 }
194
195 public static Static getClass(String name) throws LuaException {
196 try {
197 return new Static( Class.forName(name) );
198 } catch(ClassNotFoundException e) {
199 throw new LuaException(e);
200 }
201 }
202
203 public static void importClass(LuaState lua,String name) throws LuaException {
204 lua.global().put( name.substring(name.lastIndexOf('.')+1), getClass(name) );
205 }
206
207 static class AmbiguousJavaFunction extends LuaFunction {
208 private final Map<Integer,List<LuaJavaFunction>> fnMap = new HashMap<Integer,List<LuaJavaFunction>>();
209
210 AmbiguousJavaFunction(List<LuaJavaFunction> fns) {
211 for( LuaJavaFunction fn : fns ) {
212 Integer n = fn.getParameterTypes().length;
213 List<LuaJavaFunction> list = fnMap.get(n);
214 if( list==null ) {
215 list = new ArrayList<LuaJavaFunction>();
216 fnMap.put(n,list);
217 }
218 list.add(fn);
219 }
220 }
221
222 @Override public Object[] call(LuaState lua,Object... args) throws LuaException {
223 for( LuaJavaFunction fn : fnMap.get(args.length) ) {
224 try {
225 return fn.call(lua,args);
226 } catch(IllegalArgumentException e) {}
227 }
228 throw new LuaException("no method matched args");
229 }
230 }
231
232
233 public static LuaFunction pairs(Object t) throws LuaException {
234 if( t instanceof LuaTable )
235 return BasicLib.pairs((LuaTable)t);
236 if( t instanceof Map ) {
237 @SuppressWarnings("unchecked")
238 Map<Object,Object> m = (Map<Object,Object>)t;
239 return BasicLib.pairs(m.entrySet().iterator());
240 }
241 throw new LuaException( "bad argument #1 to 'pairs' (table or Map expected)" );
242 }
243
244 private static class Iter {
245 private final Iterator iter;
246 private double i = 0.0;
247
248 Iter(Iterable t) {
249 this.iter = t.iterator();
250 }
251
252 public Object[] next() {
253 if( !iter.hasNext() )
254 return LuaFunction.EMPTY_RTN ;
255 return new Object[]{ new LuaNumber(i++), iter.next() };
256 }
257 }
258 private static final Method nextIter;
259 static {
260 try {
261 nextIter = Iter.class.getMethod("next");
262 nextIter.setAccessible(true);
263 } catch(NoSuchMethodException e) {
264 throw new RuntimeException(e);
265 }
266 }
267
268 public static LuaFunction ipairs(Object t) throws LuaException {
269 if( t instanceof LuaTable )
270 return BasicLib.ipairs((LuaTable)t);
271 if( t instanceof Iterable ) {
272 Iter ai = new Iter((Iterable)t);
273 return new LuaJavaFunction(nextIter,ai);
274 }
275 throw new LuaException( "bad argument #1 to 'ipairs' (table or Iterable expected)" );
276 }
277
278
279 private static class InstanceOf {
280 private final Object obj;
281
282 InstanceOf(Object obj) {
283 this.obj = obj;
284 }
285
286 public boolean instanceOf(Static st) {
287 return st.cls.isInstance(obj);
288 }
289 }
290 private static final Method instanceOf;
291 static {
292 try {
293 instanceOf = InstanceOf.class.getMethod("instanceOf",Static.class);
294 instanceOf.setAccessible(true);
295 } catch(NoSuchMethodException e) {
296 throw new RuntimeException(e);
297 }
298 }
299
300 }