comparison src/luan/LuanJavaFunction.java @ 48:64ecb7a3aad7

rename Lua to Luan git-svn-id: https://luan-java.googlecode.com/svn/trunk@49 21e917c8-12df-6dd8-5cb6-c86387c605b9
author fschmidt@gmail.com <fschmidt@gmail.com@21e917c8-12df-6dd8-5cb6-c86387c605b9>
date Fri, 28 Dec 2012 03:29:12 +0000
parents src/luan/LuaJavaFunction.java@659c7139e903
children 8ede219cd111
comparison
equal deleted inserted replaced
47:659c7139e903 48:64ecb7a3aad7
1 package luan;
2
3 import java.lang.reflect.Array;
4 import java.lang.reflect.Method;
5 import java.lang.reflect.Constructor;
6 import java.lang.reflect.InvocationTargetException;
7 import java.util.List;
8 import java.util.Map;
9 import java.util.Set;
10
11
12 public final class LuanJavaFunction extends LuanFunction {
13 private final JavaMethod method;
14 private final Object obj;
15 private final RtnConverter rtnConverter;
16 private final boolean takesLuaState;
17 private final ArgConverter[] argConverters;
18 private final Class<?> varArgCls;
19
20 public LuanJavaFunction(Method method,Object obj) {
21 this( JavaMethod.of(method), obj );
22 }
23
24 public LuanJavaFunction(Constructor constr,Object obj) {
25 this( JavaMethod.of(constr), obj );
26 }
27
28 LuanJavaFunction(JavaMethod method,Object obj) {
29 this.method = method;
30 this.obj = obj;
31 this.rtnConverter = getRtnConverter(method);
32 this.takesLuaState = takesLuaState(method);
33 this.argConverters = getArgConverters(takesLuaState,method);
34 if( method.isVarArgs() ) {
35 Class<?>[] paramTypes = method.getParameterTypes();
36 this.varArgCls = paramTypes[paramTypes.length-1].getComponentType();
37 } else {
38 this.varArgCls = null;
39 }
40 }
41
42 public Class<?>[] getParameterTypes() {
43 return method.getParameterTypes();
44 }
45
46 @Override public Object[] call(LuanState lua,Object[] args) throws LuanException {
47 args = fixArgs(lua,args);
48 Object rtn;
49 try {
50 rtn = method.invoke(obj,args);
51 } catch(IllegalArgumentException e) {
52 checkArgs(lua,args);
53 throw e;
54 } catch(IllegalAccessException e) {
55 throw new RuntimeException(e);
56 } catch(InvocationTargetException e) {
57 Throwable cause = e.getCause();
58 if( cause instanceof Error )
59 throw (Error)cause;
60 if( cause instanceof RuntimeException )
61 throw (RuntimeException)cause;
62 if( cause instanceof LuanException )
63 throw (LuanException)cause;
64 throw new RuntimeException(e);
65 } catch(InstantiationException e) {
66 throw new RuntimeException(e);
67 }
68 return rtnConverter.convert(rtn);
69 }
70
71 private void checkArgs(LuanState lua,Object[] args) throws LuanException {
72 Class<?>[] a = getParameterTypes();
73 for( int i=0; i<a.length; i++ ) {
74 if( !a[i].isInstance(args[i]) ) {
75 String got = args[i].getClass().getName();
76 String expected = a[i].getName();
77 if( !takesLuaState )
78 i++;
79 throw new LuanException(lua,LuanElement.JAVA,"bad argument #"+i+" ("+expected+" expected, got "+got+")");
80 }
81 }
82 }
83
84 private Object[] fixArgs(LuanState lua,Object[] args) {
85 int n = argConverters.length;
86 Object[] rtn;
87 int start = 0;
88 if( !takesLuaState && varArgCls==null && args.length == n ) {
89 rtn = args;
90 } else {
91 if( takesLuaState )
92 n++;
93 rtn = new Object[n];
94 if( takesLuaState ) {
95 rtn[start++] = lua;
96 }
97 n = argConverters.length;
98 if( varArgCls != null ) {
99 n--;
100 if( args.length < argConverters.length ) {
101 rtn[rtn.length-1] = Array.newInstance(varArgCls,0);
102 } else {
103 int len = args.length - n;
104 Object varArgs = Array.newInstance(varArgCls,len);
105 ArgConverter ac = argConverters[n];
106 for( int i=0; i<len; i++ ) {
107 Array.set( varArgs, i, ac.convert(args[n+i]) );
108 }
109 rtn[rtn.length-1] = varArgs;
110 }
111 }
112 System.arraycopy(args,0,rtn,start,Math.min(args.length,n));
113 }
114 for( int i=0; i<n; i++ ) {
115 rtn[start+i] = argConverters[i].convert(rtn[start+i]);
116 }
117 return rtn;
118 }
119
120
121 private interface RtnConverter {
122 public Object[] convert(Object obj);
123 }
124
125 private static final RtnConverter RTN_EMPTY = new RtnConverter() {
126 public Object[] convert(Object obj) {
127 return EMPTY_RTN;
128 }
129 };
130
131 private static final RtnConverter RTN_ARRAY = new RtnConverter() {
132 public Object[] convert(Object obj) {
133 if( obj == null )
134 return NULL_RTN;
135 return (Object[])obj;
136 }
137 };
138
139 private static final RtnConverter RTN_ONE = new RtnConverter() {
140 public Object[] convert(Object obj) {
141 return new Object[]{obj};
142 }
143 };
144
145 private static final Object[] NULL_RTN = new Object[1];
146
147 private static final RtnConverter RTN_NUMBER_ARRAY = new RtnConverter() {
148 public Object[] convert(Object obj) {
149 if( obj == null )
150 return NULL_RTN;
151 Object[] rtn = new Object[Array.getLength(obj)];
152 for( int i=0; i<rtn.length; i++ ) {
153 rtn[i] = Array.get(obj,i);
154 }
155 return rtn;
156 }
157 };
158
159 private static RtnConverter getRtnConverter(JavaMethod m) {
160 Class<?> rtnType = m.getReturnType();
161 if( rtnType == Void.TYPE )
162 return RTN_EMPTY;
163 if( rtnType.isArray() ) {
164 rtnType = rtnType.getComponentType();
165 if( isNumber(rtnType) )
166 return RTN_NUMBER_ARRAY;
167 return RTN_ARRAY;
168 }
169 return RTN_ONE;
170 }
171
172 private static boolean isNumber(Class<?> rtnType) {
173 return rtnType == Byte.TYPE
174 || rtnType == Short.TYPE
175 || rtnType == Integer.TYPE
176 || rtnType == Long.TYPE
177 || rtnType == Float.TYPE
178 || rtnType == Double.TYPE
179 ;
180 }
181
182 private interface ArgConverter {
183 public Object convert(Object obj);
184 }
185
186 private static final ArgConverter ARG_SAME = new ArgConverter() {
187 public Object convert(Object obj) {
188 return obj;
189 }
190 };
191
192 private static final ArgConverter ARG_DOUBLE = new ArgConverter() {
193 public Object convert(Object obj) {
194 if( obj instanceof Double )
195 return obj;
196 if( obj instanceof Number ) {
197 Number n = (Number)obj;
198 return n.doubleValue();
199 }
200 if( obj instanceof String ) {
201 String s = (String)obj;
202 try {
203 return Double.valueOf(s);
204 } catch(NumberFormatException e) {}
205 }
206 return obj;
207 }
208 };
209
210 private static final ArgConverter ARG_FLOAT = new ArgConverter() {
211 public Object convert(Object obj) {
212 if( obj instanceof Float )
213 return obj;
214 if( obj instanceof Number ) {
215 Number n = (Number)obj;
216 float r = n.floatValue();
217 if( r==n.doubleValue() )
218 return r;
219 }
220 if( obj instanceof String ) {
221 String s = (String)obj;
222 try {
223 return Float.valueOf(s);
224 } catch(NumberFormatException e) {}
225 }
226 return obj;
227 }
228 };
229
230 private static final ArgConverter ARG_LONG = new ArgConverter() {
231 public Object convert(Object obj) {
232 if( obj instanceof Long )
233 return obj;
234 if( obj instanceof Number ) {
235 Number n = (Number)obj;
236 long r = n.longValue();
237 if( r==n.doubleValue() )
238 return r;
239 }
240 else if( obj instanceof String ) {
241 String s = (String)obj;
242 try {
243 return Long.valueOf(s);
244 } catch(NumberFormatException e) {}
245 }
246 return obj;
247 }
248 };
249
250 private static final ArgConverter ARG_INTEGER = new ArgConverter() {
251 public Object convert(Object obj) {
252 if( obj instanceof Integer )
253 return obj;
254 if( obj instanceof Number ) {
255 Number n = (Number)obj;
256 int r = n.intValue();
257 if( r==n.doubleValue() )
258 return r;
259 }
260 else if( obj instanceof String ) {
261 String s = (String)obj;
262 try {
263 return Integer.valueOf(s);
264 } catch(NumberFormatException e) {}
265 }
266 return obj;
267 }
268 };
269
270 private static final ArgConverter ARG_SHORT = new ArgConverter() {
271 public Object convert(Object obj) {
272 if( obj instanceof Short )
273 return obj;
274 if( obj instanceof Number ) {
275 Number n = (Number)obj;
276 short r = n.shortValue();
277 if( r==n.doubleValue() )
278 return r;
279 }
280 else if( obj instanceof String ) {
281 String s = (String)obj;
282 try {
283 return Short.valueOf(s);
284 } catch(NumberFormatException e) {}
285 }
286 return obj;
287 }
288 };
289
290 private static final ArgConverter ARG_BYTE = new ArgConverter() {
291 public Object convert(Object obj) {
292 if( obj instanceof Byte )
293 return obj;
294 if( obj instanceof Number ) {
295 Number n = (Number)obj;
296 byte r = n.byteValue();
297 if( r==n.doubleValue() )
298 return r;
299 }
300 else if( obj instanceof String ) {
301 String s = (String)obj;
302 try {
303 return Byte.valueOf(s);
304 } catch(NumberFormatException e) {}
305 }
306 return obj;
307 }
308 };
309
310 private static final ArgConverter ARG_TABLE = new ArgConverter() {
311 public Object convert(Object obj) {
312 if( obj instanceof List ) {
313 @SuppressWarnings("unchecked")
314 List<Object> list = (List<Object>)obj;
315 return new LuanTable(list);
316 }
317 if( obj instanceof Map ) {
318 @SuppressWarnings("unchecked")
319 Map<Object,Object> map = (Map<Object,Object>)obj;
320 return new LuanTable(map);
321 }
322 if( obj instanceof Set ) {
323 @SuppressWarnings("unchecked")
324 Set<Object> set = (Set<Object>)obj;
325 return new LuanTable(set);
326 }
327 return obj;
328 }
329 };
330
331 private static final ArgConverter ARG_MAP = new ArgConverter() {
332 public Object convert(Object obj) {
333 if( obj instanceof LuanTable ) {
334 LuanTable t = (LuanTable)obj;
335 return t.asMap();
336 }
337 return obj;
338 }
339 };
340
341 private static final ArgConverter ARG_LIST = new ArgConverter() {
342 public Object convert(Object obj) {
343 if( obj instanceof LuanTable ) {
344 LuanTable t = (LuanTable)obj;
345 if( t.isList() )
346 return t.asList();
347 }
348 return obj;
349 }
350 };
351
352 private static final ArgConverter ARG_SET = new ArgConverter() {
353 public Object convert(Object obj) {
354 if( obj instanceof LuanTable ) {
355 LuanTable t = (LuanTable)obj;
356 if( t.isSet() )
357 return t.asSet();
358 }
359 return obj;
360 }
361 };
362
363 private static boolean takesLuaState(JavaMethod m) {
364 Class<?>[] paramTypes = m.getParameterTypes();
365 return paramTypes.length > 0 && paramTypes[0].equals(LuanState.class);
366 }
367
368 private static ArgConverter[] getArgConverters(boolean takesLuaState,JavaMethod m) {
369 final boolean isVarArgs = m.isVarArgs();
370 Class<?>[] paramTypes = m.getParameterTypes();
371 if( takesLuaState ) {
372 Class<?>[] t = new Class<?>[paramTypes.length-1];
373 System.arraycopy(paramTypes,1,t,0,t.length);
374 paramTypes = t;
375 }
376 ArgConverter[] a = new ArgConverter[paramTypes.length];
377 for( int i=0; i<a.length; i++ ) {
378 Class<?> paramType = paramTypes[i];
379 if( isVarArgs && i == a.length-1 )
380 paramType = paramType.getComponentType();
381 a[i] = getArgConverter(paramType);
382 }
383 return a;
384 }
385
386 private static ArgConverter getArgConverter(Class<?> cls) {
387 if( cls == Double.TYPE || cls.equals(Double.class) )
388 return ARG_DOUBLE;
389 if( cls == Float.TYPE || cls.equals(Float.class) )
390 return ARG_FLOAT;
391 if( cls == Long.TYPE || cls.equals(Long.class) )
392 return ARG_LONG;
393 if( cls == Integer.TYPE || cls.equals(Integer.class) )
394 return ARG_INTEGER;
395 if( cls == Short.TYPE || cls.equals(Short.class) )
396 return ARG_SHORT;
397 if( cls == Byte.TYPE || cls.equals(Byte.class) )
398 return ARG_BYTE;
399 if( cls.equals(LuanTable.class) )
400 return ARG_TABLE;
401 if( cls.equals(Map.class) )
402 return ARG_MAP;
403 if( cls.equals(List.class) )
404 return ARG_LIST;
405 if( cls.equals(Set.class) )
406 return ARG_SET;
407 return ARG_SAME;
408 }
409
410
411
412 private static abstract class JavaMethod {
413 abstract boolean isVarArgs();
414 abstract Class<?>[] getParameterTypes();
415 abstract Object invoke(Object obj,Object... args)
416 throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException;
417 abstract Class<?> getReturnType();
418
419 static JavaMethod of(final Method m) {
420 return new JavaMethod() {
421 @Override boolean isVarArgs() {
422 return m.isVarArgs();
423 }
424 @Override Class<?>[] getParameterTypes() {
425 return m.getParameterTypes();
426 }
427 @Override Object invoke(Object obj,Object... args)
428 throws IllegalAccessException, IllegalArgumentException, InvocationTargetException
429 {
430 return m.invoke(obj,args);
431 }
432 @Override Class<?> getReturnType() {
433 return m.getReturnType();
434 }
435 @Override public String toString() {
436 return m.toString();
437 }
438 };
439 }
440
441 static JavaMethod of(final Constructor c) {
442 return new JavaMethod() {
443 @Override boolean isVarArgs() {
444 return c.isVarArgs();
445 }
446 @Override Class<?>[] getParameterTypes() {
447 return c.getParameterTypes();
448 }
449 @Override Object invoke(Object obj,Object... args)
450 throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException
451 {
452 return c.newInstance(args);
453 }
454 @Override Class<?> getReturnType() {
455 return c.getDeclaringClass();
456 }
457 @Override public String toString() {
458 return c.toString();
459 }
460 };
461 }
462
463 }
464
465 }