KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > armedbear > lisp > Java


1 /*
2  * Java.java
3  *
4  * Copyright (C) 2002-2004 Peter Graves
5  * $Id: Java.java,v 1.44 2004/08/10 22:28:13 asimon Exp $
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20  */

21
22 package org.armedbear.lisp;
23
24 import java.lang.reflect.Constructor JavaDoc;
25 import java.lang.reflect.InvocationTargetException JavaDoc;
26 import java.lang.reflect.Method JavaDoc;
27 import java.lang.reflect.Field JavaDoc;
28 import java.lang.reflect.Modifier JavaDoc;
29 import java.lang.reflect.Array JavaDoc;
30
31 public final class Java extends Lisp
32 {
33     // ### jclass
34
private static final Primitive1 JCLASS = new Primitive1("jclass", PACKAGE_JAVA, true, "name")
35     {
36         public LispObject execute(LispObject arg) throws ConditionThrowable
37         {
38             String JavaDoc className = arg.getStringValue();
39             try {
40                 return new JavaObject(classForName(className));
41             }
42             catch (ClassNotFoundException JavaDoc e) {
43                 signal(new LispError("class not found: " + className));
44             }
45             catch (Throwable JavaDoc t) {
46                 signal(new LispError(getMessage(t)));
47             }
48             // Not reached.
49
return NIL;
50         }
51     };
52
53     // ### jfield - retrieve or modify a field in a Java class or instance.
54
/*
55      * Supported argument patterns:
56      *
57      * Case 1: class-ref field-name:
58      * to retrieve the value of a static field.
59      *
60      * Case 2: class-ref field-name instance-ref:
61      * to retrieve the value of a class field of the instance.
62      *
63      * Case 3: class-ref field-name primitive-value:
64      * to store primitive-value in a static field.
65      *
66      * Case 4: class-ref field-name instance-ref value:
67      * to store value in a class field of the instance.
68      *
69      * Case 5: class-ref field-name nil value:
70      * to store value in a static field (when value may be
71      * confused with an instance-ref).
72      *
73      * Case 6: field-name instance:
74      * to retrieve the value of a field of the instance. The
75      * class is derived from the instance.
76      *
77      * Case 7: field-name instance value:
78      * to store value in a field of the instance. The class is
79      * derived from the instance.
80      */

81     private static final Primitive JFIELD =
82         new Primitive("jfield", PACKAGE_JAVA, true,
83                       "class-ref-or-field field-or-instance &optional instance value")
84     {
85         public LispObject execute(LispObject[] args) throws ConditionThrowable
86         {
87             return makeLispObject((JFIELD_RAW.execute(args)).javaInstance());
88         }
89     };
90
91     // ### jfield-raw - retrieve or modify a field in a Java class or instance.
92
private static final Primitive JFIELD_RAW =
93         new Primitive("jfield-raw", PACKAGE_JAVA, true,
94                       "class-ref-or-field field-or-instance &optional instance value")
95     {
96         public LispObject execute(LispObject[] args) throws ConditionThrowable
97         {
98             if (args.length < 2 || args.length > 4)
99                 signal(new WrongNumberOfArgumentsException(this));
100             String JavaDoc fieldName = null;
101             Class JavaDoc c;
102             Field JavaDoc f;
103             Class JavaDoc fieldType;
104             Object JavaDoc instance = null;
105             try {
106                 if (args[1] instanceof AbstractString) {
107                     // Cases 1-5.
108
fieldName = args[1].getStringValue();
109                     c = forClassRef(args[0]);
110                 } else {
111                     // Cases 6 and 7.
112
fieldName = args[0].getStringValue();
113                     instance = JavaObject.getObject(args[1]);
114                     c = instance.getClass();
115                 }
116                 f = c.getField(fieldName);
117                 fieldType = f.getType();
118                 switch (args.length) {
119                     case 2:
120                         // Cases 1 and 6.
121
break;
122                     case 3:
123                         // Cases 2,3, and 7.
124
if (instance == null) {
125                             // Cases 2 and 3.
126
if (args[2] instanceof JavaObject) {
127                                 // Case 2.
128
instance = JavaObject.getObject(args[2]);
129                                 break;
130                             } else {
131                                 // Case 3.
132
f.set(null,args[2].javaInstance(fieldType));
133                                 return args[2];
134                             }
135                         } else {
136                             // Case 7.
137
f.set(instance,args[2].javaInstance(fieldType));
138                             return args[2];
139                         }
140                     case 4:
141                         // Cases 4 and 5.
142
if (args[2] != NIL) {
143                             // Case 4.
144
instance = JavaObject.getObject(args[2]);
145                         }
146                         f.set(instance,args[3].javaInstance(fieldType));
147                         return args[3];
148                 }
149                 return new JavaObject(f.get(instance));
150             }
151             catch (ClassNotFoundException JavaDoc e) {
152                 signal(new LispError("class not found: " + e.getMessage()));
153             }
154             catch (NoSuchFieldException JavaDoc e) {
155                 signal(new LispError("no such field"));
156             }
157             catch (SecurityException JavaDoc e) {
158                 signal(new LispError("inaccessible field"));
159             }
160             catch (IllegalAccessException JavaDoc e) {
161                 signal(new LispError("illegal access"));
162             }
163             catch (IllegalArgumentException JavaDoc e) {
164                 signal(new LispError("illegal argument"));
165             }
166             catch (Throwable JavaDoc t) {
167                 signal(new LispError(getMessage(t)));
168             }
169             // Not reached.
170
return NIL;
171         }
172     };
173
174     // ### jconstructor
175
// jconstructor class-ref &rest parameter-class-refs
176
private static final Primitive JCONSTRUCTOR =
177         new Primitive("jconstructor", PACKAGE_JAVA, true, "class-ref &rest parameter-class-refs")
178     {
179         public LispObject execute(LispObject[] args) throws ConditionThrowable
180         {
181             if (args.length < 1)
182                 signal(new WrongNumberOfArgumentsException(this));
183             try {
184                 final Class JavaDoc c = forClassRef(args[0]);
185                 int argCount = 0;
186                 if (args.length == 2 && args[1] instanceof Fixnum) {
187                     argCount = Fixnum.getValue(args[1]);
188                 } else {
189                     Class JavaDoc[] parameterTypes = new Class JavaDoc[args.length-1];
190                     for (int i = 1; i < args.length; i++) {
191                         parameterTypes[i-1] = forClassRef(args[i]);
192                     }
193                     return new JavaObject(c.getConstructor(parameterTypes));
194                 }
195                 // Parameter types not explicitly specified.
196
Constructor JavaDoc[] constructors = c.getConstructors();
197                 for (int i = 0; i < constructors.length; i++) {
198                     Constructor JavaDoc constructor = constructors[i];
199                     if (constructor.getParameterTypes().length == argCount)
200                         return new JavaObject(constructor);
201                 }
202                 throw new NoSuchMethodException JavaDoc();
203             }
204             catch (ClassNotFoundException JavaDoc e) {
205                 signal(new LispError("class not found: " + e.getMessage()));
206             }
207             catch (NoSuchMethodException JavaDoc e) {
208                 signal(new LispError("no such constructor"));
209             }
210             catch (ConditionThrowable e) {
211                 throw e;
212             }
213             catch (Throwable JavaDoc t) {
214                 signal(new LispError(getMessage(t)));
215             }
216             // Not reached.
217
return NIL;
218         }
219     };
220
221     // ### jmethod
222
// jmethod class-ref name &rest parameter-class-refs
223
private static final Primitive JMETHOD =
224         new Primitive("jmethod", PACKAGE_JAVA, true,
225                       "class-ref name &rest parameter-class-refs")
226     {
227         public LispObject execute(LispObject[] args) throws ConditionThrowable
228         {
229             if (args.length < 2)
230                 signal(new WrongNumberOfArgumentsException(this));
231             String JavaDoc methodName = args[1].getStringValue();
232             try {
233                 final Class JavaDoc c = forClassRef(args[0]);
234                 int argCount = 0;
235                 if (args.length == 3 && args[2] instanceof Fixnum) {
236                     argCount = Fixnum.getValue(args[2]);
237                 } else {
238                     Class JavaDoc[] parameterTypes = new Class JavaDoc[args.length-2];
239                     for (int i = 2; i < args.length; i++) {
240                         parameterTypes[i-2] = forClassRef(args[i]);
241                     }
242                     return new JavaObject(c.getMethod(methodName,
243                                                       parameterTypes));
244                 }
245                 // Parameter types not explicitly specified.
246
Method JavaDoc[] methods = c.getMethods();
247                 for (int i = 0; i < methods.length; i++) {
248                     Method JavaDoc method = methods[i];
249                     if (method.getName().equals(methodName)
250                         && method.getParameterTypes().length == argCount)
251                         return new JavaObject(method);
252                 }
253                 throw new NoSuchMethodException JavaDoc();
254             }
255             catch (ClassNotFoundException JavaDoc e) {
256                 signal(new LispError("class not found: " + e.getMessage()));
257             }
258             catch (NoSuchMethodException JavaDoc e) {
259                 signal(new LispError("no such method: " + methodName));
260             }
261             catch (ConditionThrowable e) {
262                 throw e;
263             }
264             catch (Throwable JavaDoc t) {
265                 signal(new LispError(getMessage(t)));
266             }
267             // Not reached.
268
return NIL;
269         }
270     };
271
272     // ### jstatic
273
// jstatic method class &rest args
274
private static final Primitive JSTATIC = new Primitive("jstatic", PACKAGE_JAVA, true,
275                                                            "method class &rest args")
276     {
277         public LispObject execute(LispObject[] args) throws ConditionThrowable
278         {
279             return makeLispObject((JSTATIC_RAW.execute(args)).javaInstance());
280         }
281     };
282
283
284     // ### jstatic-raw
285
// jstatic-raw method class &rest args
286
private static final Primitive JSTATIC_RAW = new Primitive("jstatic-raw", PACKAGE_JAVA, true,
287                                                                "method class &rest args")
288     {
289         public LispObject execute(LispObject[] args) throws ConditionThrowable
290         {
291             if (args.length < 2)
292                 signal(new WrongNumberOfArgumentsException(this));
293             try {
294                 Method JavaDoc m = null;
295                 LispObject methodRef = args[0];
296                 if (methodRef instanceof JavaObject) {
297                     Object JavaDoc obj = ((JavaObject)methodRef).getObject();
298                     if (obj instanceof Method JavaDoc)
299                         m = (Method JavaDoc) obj;
300                 } else if (methodRef instanceof AbstractString) {
301                     Class JavaDoc c = forClassRef(args[1]);
302                     if (c != null) {
303                         String JavaDoc methodName = methodRef.getStringValue();
304                         Method JavaDoc[] methods = c.getMethods();
305                         int argCount = args.length - 2;
306                         for (int i = 0; i < methods.length; i++) {
307                             Method JavaDoc method = methods[i];
308                             if (!Modifier.isStatic(method.getModifiers())
309                                 || method.getParameterTypes().length != argCount)
310                     continue;
311                             if (method.getName().equals(methodName)) {
312                                 m = method;
313                                 break;
314                             }
315                         }
316                         if (m == null)
317                             signal(new LispError("no such method"));
318                     }
319                 } else
320                     signal(new TypeError("wrong type: " + methodRef));
321                 Object JavaDoc[] methodArgs = new Object JavaDoc[args.length-2];
322                 Class JavaDoc[] argTypes = m.getParameterTypes();
323                 for (int i = 2; i < args.length; i++) {
324                     LispObject arg = args[i];
325                     if (arg == NIL)
326                         methodArgs[i-2] = null;
327                     else
328                         methodArgs[i-2] = arg.javaInstance(argTypes[i-2]);
329                 }
330                 Object JavaDoc result = m.invoke(null, methodArgs);
331                 return new JavaObject(result);
332             }
333             catch (Throwable JavaDoc t) {
334                 signal(new LispError(getMessage(t)));
335             }
336             // Not reached.
337
return NIL;
338         }
339     };
340
341     // ### jnew
342
// jnew constructor &rest args
343
private static final Primitive JNEW = new Primitive("jnew", PACKAGE_JAVA, true,
344                                                         "constructor &rest args")
345     {
346         public LispObject execute(LispObject[] args) throws ConditionThrowable
347         {
348             if (args.length < 1)
349                 signal(new WrongNumberOfArgumentsException(this));
350             LispObject classRef = args[0];
351             try {
352                 Constructor JavaDoc constructor = (Constructor JavaDoc) JavaObject.getObject(classRef);
353                 Class JavaDoc[] argTypes = constructor.getParameterTypes();
354                 Object JavaDoc[] initargs = new Object JavaDoc[args.length-1];
355                 for (int i = 1; i < args.length; i++) {
356                     LispObject arg = args[i];
357                     if (arg == NIL)
358                         initargs[i-1] = null;
359                     else {
360                         initargs[i-1] = arg.javaInstance(argTypes[i-1]);
361                     }
362                 }
363                 return new JavaObject(constructor.newInstance(initargs));
364             }
365             catch (Throwable JavaDoc t) {
366                 signal(new LispError(getMessage(t)));
367             }
368             // Not reached.
369
return NIL;
370         }
371     };
372
373     // ### jnew-array
374
// jnew-array element-type &rest dimensions
375
private static final Primitive JNEW_ARRAY = new Primitive("jnew-array", PACKAGE_JAVA, true,
376                                                               "element-type &rest dimensions")
377     {
378         public LispObject execute(LispObject[] args) throws ConditionThrowable
379         {
380             if (args.length < 2)
381                 signal(new WrongNumberOfArgumentsException(this));
382             try {
383                 Class JavaDoc c = forClassRef(args[0]);
384                 int[] dimensions = new int[args.length - 1];
385                 for (int i = 1; i < args.length; i++)
386                     dimensions[i-1] = ((Integer JavaDoc)args[i].javaInstance()).intValue();
387                 return new JavaObject(Array.newInstance(c, dimensions));
388             }
389             catch (ClassNotFoundException JavaDoc e) {
390                 signal(new LispError("class not found: " + e.getMessage()));
391             }
392             catch (Throwable JavaDoc t) {
393                 signal(new LispError(getMessage(t)));
394             }
395             // Not reached.
396
return NIL;
397         }
398     };
399
400     // ### jarray-ref
401
// jarray-ref java-array &rest indices
402
private static final Primitive JARRAY_REF = new Primitive("jarray-ref", PACKAGE_JAVA, true,
403                                                               "java-array &rest indices")
404     {
405         public LispObject execute(LispObject[] args) throws ConditionThrowable
406         {
407             return makeLispObject((JARRAY_REF_RAW.execute(args)).javaInstance());
408         }
409     };
410
411     // ### jarray-ref-raw
412
// jarray-ref-raw java-array &rest indices
413
private static final Primitive JARRAY_REF_RAW = new Primitive("jarray-ref-raw", PACKAGE_JAVA, true,
414                                                                   "java-array &rest indices")
415     {
416         public LispObject execute(LispObject[] args) throws ConditionThrowable
417         {
418             if (args.length < 2)
419                 signal(new WrongNumberOfArgumentsException(this));
420             try {
421                 Object JavaDoc a = args[0].javaInstance();
422                 for (int i = 1; i<args.length - 1; i++)
423                     a = Array.get(a, ((Integer JavaDoc)args[i].javaInstance()).intValue());
424                 return new JavaObject(Array.get(a, ((Integer JavaDoc)args[args.length - 1].javaInstance()).intValue()));
425             }
426             catch (Throwable JavaDoc t) {
427                 signal(new LispError(getMessage(t)));
428             }
429             // Not reached.
430
return NIL;
431         }
432     };
433
434     // ### jarray-set
435
// jarray-set java-array new-value &rest indices
436
private static final Primitive JARRAY_SET = new Primitive("jarray-set", PACKAGE_JAVA, true,
437                                                               "java-array new-value &rest indices")
438     {
439         public LispObject execute(LispObject[] args) throws ConditionThrowable
440         {
441             if (args.length < 3)
442                 signal(new WrongNumberOfArgumentsException(this));
443             try {
444                 Object JavaDoc a = args[0].javaInstance();
445                 LispObject v = args[1];
446                 for (int i = 2; i<args.length - 1; i++)
447                     a = Array.get(a, ((Integer JavaDoc)args[i].javaInstance()).intValue());
448                 Array.set(a, ((Integer JavaDoc)args[args.length - 1].javaInstance()).intValue(), v.javaInstance());
449                 return v;
450             }
451             catch (Throwable JavaDoc t) {
452                 signal(new LispError(getMessage(t)));
453             }
454             // Not reached.
455
return NIL;
456         }
457     };
458
459     // ### jcall
460
// jcall method instance &rest args
461
private static final Primitive JCALL = new Primitive("jcall", PACKAGE_JAVA, true,
462                                                          "method instance &rest args")
463     {
464         public LispObject execute(LispObject[] args) throws ConditionThrowable
465         {
466             return makeLispObject((JCALL_RAW.execute(args)).javaInstance());
467         }
468     };
469
470     // ### jcall-raw
471
// jcall-raw method instance &rest args
472
private static final Primitive JCALL_RAW = new Primitive("jcall-raw", PACKAGE_JAVA, true,
473                                                              "method instance &rest args")
474     {
475         public LispObject execute(LispObject[] args) throws ConditionThrowable
476         {
477             if (args.length < 2)
478                 signal(new WrongNumberOfArgumentsException(this));
479             try {
480                 Method JavaDoc method = (Method JavaDoc) JavaObject.getObject(args[0]);
481                 Class JavaDoc[] argTypes = method.getParameterTypes();
482                 Object JavaDoc instance;
483                 if (args[1] instanceof AbstractString)
484                     instance = args[1].getStringValue();
485                 else
486                     instance = JavaObject.getObject(args[1]);
487                 Object JavaDoc[] methodArgs = new Object JavaDoc[args.length-2];
488                 for (int i = 2; i < args.length; i++) {
489                     LispObject arg = args[i];
490                     if (arg == NIL)
491                         methodArgs[i-2] = null;
492                     else
493                         methodArgs[i-2] = arg.javaInstance(argTypes[i-2]);
494                 }
495                 Object JavaDoc result = method.invoke(instance, methodArgs);
496                 return new JavaObject(result);
497             }
498             catch (Throwable JavaDoc t) {
499                 signal(new LispError(getMessage(t)));
500             }
501             // Not reached.
502
return NIL;
503         }
504     };
505
506     // ### make-immediate-object
507
// make-immediate-object object &optional type
508
private static final Primitive MAKE_IMMEDIATE_OBJECT =
509         new Primitive("make-immediate-object", PACKAGE_JAVA, true, "object &optional type")
510     {
511         public LispObject execute(LispObject[] args) throws ConditionThrowable
512         {
513             if (args.length < 1)
514                 signal(new WrongNumberOfArgumentsException(this));
515             LispObject object = args[0];
516             try {
517                 if (args.length > 1) {
518                     LispObject type = args[1];
519                     if (type == Keyword.BOOLEAN) {
520                         if (object == NIL)
521                             return new JavaObject(Boolean.FALSE);
522                         else
523                             return new JavaObject(Boolean.TRUE);
524                     }
525                     if (type == Keyword.REF) {
526                         if (object == NIL)
527                             return new JavaObject(null);
528                         else
529                             throw new Error JavaDoc();
530                     }
531                     // other special cases come here
532
}
533                 return new JavaObject(object.javaInstance());
534             }
535             catch (Throwable JavaDoc t) {
536                 signal(new LispError("MAKE-IMMEDIATE-OBJECT: not implemented"));
537             }
538             // Not reached.
539
return NIL;
540         }
541     };
542
543     private static final Primitive1 JAVA_OBJECT_P = new Primitive1("java-object-p", PACKAGE_JAVA, true,
544                                                                    "object")
545     {
546         public LispObject execute(LispObject arg) throws ConditionThrowable
547         {
548             return (arg instanceof JavaObject) ? T : NIL;
549         }
550     };
551
552     // ### jobject-lisp-value
553
// jobject-lisp-value java-object
554
private static final Primitive1 JOBJECT_LISP_VALUE =
555         new Primitive1("jobject-lisp-value", PACKAGE_JAVA, true, "java-object")
556     {
557         public LispObject execute(LispObject arg) throws ConditionThrowable
558         {
559             return makeLispObject(arg.javaInstance());
560         }
561     };
562
563     private static Class JavaDoc classForName(String JavaDoc className) throws ClassNotFoundException JavaDoc
564     {
565         try {
566             return Class.forName(className);
567         }
568         catch (ClassNotFoundException JavaDoc e) {
569             return Class.forName(className, true, JavaClassLoader.getPersistentInstance());
570         }
571     }
572
573     // Supports Java primitive types too.
574
private static Class JavaDoc forClassRef(LispObject classRef) throws ClassNotFoundException JavaDoc, ConditionThrowable
575     {
576         if (classRef instanceof AbstractString) {
577             String JavaDoc className = classRef.getStringValue();
578             if (className.equals("boolean"))
579                 return Boolean.TYPE;
580             if (className.equals("byte"))
581                 return Byte.TYPE;
582             if (className.equals("char"))
583                 return Character.TYPE;
584             if (className.equals("short"))
585                 return Short.TYPE;
586             if (className.equals("int"))
587                 return Integer.TYPE;
588             if (className.equals("long"))
589                 return Long.TYPE;
590             if (className.equals("float"))
591                 return Float.TYPE;
592             if (className.equals("double"))
593                 return Double.TYPE;
594             // Not a primitive Java type.
595
return classForName(className);
596         } else
597             try {
598                 return (Class JavaDoc)JavaObject.getObject(classRef);
599             }
600         catch (ClassCastException JavaDoc e) {
601             signal(new TypeError(classRef, "Java class"));
602         }
603         catch (ConditionThrowable e) {
604             throw new ClassNotFoundException JavaDoc(e.getMessage());
605         }
606         // Not reached.
607
return null;
608     }
609
610     private static final LispObject makeLispObject(Object JavaDoc obj) throws ConditionThrowable
611     {
612         if (obj == null)
613             return NIL;
614         if (obj instanceof Boolean JavaDoc)
615             return ((Boolean JavaDoc)obj).booleanValue() ? T : NIL;
616         if (obj instanceof Integer JavaDoc)
617             return new Fixnum(((Integer JavaDoc)obj).intValue());
618         if (obj instanceof Long JavaDoc)
619             return new Bignum(((Long JavaDoc)obj).longValue());
620         if (obj instanceof Double JavaDoc || obj instanceof Float JavaDoc)
621             return new LispFloat(((Number JavaDoc)obj).doubleValue());
622         if (obj instanceof String JavaDoc)
623             return new SimpleString((String JavaDoc)obj);
624         if (obj instanceof Character JavaDoc)
625             return LispCharacter.getInstance(((Character JavaDoc)obj).charValue());
626         if (obj instanceof Object JavaDoc[]) {
627             Object JavaDoc[] array = (Object JavaDoc[]) obj;
628             SimpleVector v = new SimpleVector(array.length);
629             for (int i = array.length; i-- > 0;)
630                 v.setRowMajor(i, new JavaObject(array[i]));
631             return v;
632         }
633         if (obj instanceof LispObject)
634             return (LispObject) obj;
635         return new JavaObject(obj);
636     }
637
638     private static final String JavaDoc getMessage(Throwable JavaDoc t)
639     {
640         if (t instanceof InvocationTargetException JavaDoc) {
641             try {
642                 Method JavaDoc method =
643                     Throwable JavaDoc.class.getMethod("getCause", new Class JavaDoc[0]);
644                 if (method != null) {
645                     Throwable JavaDoc cause = (Throwable JavaDoc) method.invoke(t,
646                                                                 new Object JavaDoc[0]);
647                     if (cause != null)
648                         t = cause;
649                 }
650             }
651             catch (NoSuchMethodException JavaDoc e) {
652                 Debug.trace(e);
653             }
654             catch (Exception JavaDoc e) {
655                 Debug.trace(e);
656             }
657         }
658         String JavaDoc message = t.getMessage();
659         if (message == null || message.length() == 0)
660             message = t.getClass().getName();
661         return message;
662     }
663 }
664
Popular Tags