source: trunk/abcl/src/org/armedbear/lisp/Java.java @ 11490

Last change on this file since 11490 was 11488, checked in by ehuelsmann, 16 years ago

Add @Override annotations.

Patch by: Douglas Miles

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 31.8 KB
Line 
1/*
2 * Java.java
3 *
4 * Copyright (C) 2002-2006 Peter Graves, Andras Simon
5 * $Id: Java.java 11488 2008-12-27 10:50:33Z ehuelsmann $
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 * As a special exception, the copyright holders of this library give you
22 * permission to link this library with independent modules to produce an
23 * executable, regardless of the license terms of these independent
24 * modules, and to copy and distribute the resulting executable under
25 * terms of your choice, provided that you also meet, for each linked
26 * independent module, the terms and conditions of the license of that
27 * module.  An independent module is a module which is not derived from
28 * or based on this library.  If you modify this library, you may extend
29 * this exception to your version of the library, but you are not
30 * obligated to do so.  If you do not wish to do so, delete this
31 * exception statement from your version.
32 */
33
34package org.armedbear.lisp;
35
36import java.lang.reflect.Array;
37import java.lang.reflect.Constructor;
38import java.lang.reflect.Field;
39import java.lang.reflect.InvocationTargetException;
40import java.lang.reflect.Method;
41import java.lang.reflect.Modifier;
42import java.util.Map;
43import java.util.HashMap;
44
45public final class Java extends Lisp
46{
47    private static final Map<Class,Symbol> registeredExceptions =
48       new HashMap<Class,Symbol>();
49
50    private static final LispClass java_exception = LispClass.findClass(Symbol.JAVA_EXCEPTION);
51
52    private static boolean isJavaException(LispClass lc) throws ConditionThrowable
53    {
54        return lc.subclassp(java_exception);
55    }
56
57    // ### register-java-exception exception-name condition-symbol => T
58    private static final Primitive REGISTER_JAVA_EXCEPTION =
59        new Primitive("register-java-exception", PACKAGE_JAVA, true,
60                      "exception-name condition-symbol")
61    {
62        @Override
63        public LispObject execute(LispObject className, LispObject symbol)
64            throws ConditionThrowable
65        {
66            // FIXME Verify that CONDITION-SYMBOL is a symbol that names a condition.
67            // FIXME Signal a continuable error if the exception is already registered.
68            if ((symbol instanceof Symbol) && isJavaException(LispClass.findClass((Symbol) symbol))) {
69                registeredExceptions.put(classForName(className.getStringValue()),
70                                         (Symbol)symbol);
71                return T;
72            }
73            return NIL;
74        }
75    };
76
77    // ### unregister-java-exception exception-name => T or NIL
78    private static final Primitive UNREGISTER_JAVA_EXCEPTION =
79        new Primitive("unregister-java-exception", PACKAGE_JAVA, true,
80                      "exception-name")
81    {
82        @Override
83        public LispObject execute(LispObject className)
84            throws ConditionThrowable
85        {
86            // FIXME Verify that EXCEPTION-NAME designates a subclass of Throwable.
87            return registeredExceptions.remove(classForName(className.getStringValue())) == null ? NIL : T;
88        }
89    };
90
91    private static Symbol getCondition(Class cl) throws ConditionThrowable
92    {
93  Class o = classForName("java.lang.Object");
94      for (Class c = cl ; c != o ; c = c.getSuperclass()) {
95            Object object = registeredExceptions.get(c);
96            if (object != null && isJavaException(LispClass.findClass((Symbol) object))) {
97                return (Symbol) object;
98            }
99        }
100        return null;
101    }
102
103    // ### jclass name-or-class-ref => class-ref
104    private static final Primitive JCLASS =
105        new Primitive(Symbol.JCLASS, "name-or-class-ref",
106"Returns a reference to the Java class designated by NAME-OR-CLASS-REF.")
107    {
108        @Override
109        public LispObject execute(LispObject arg) throws ConditionThrowable
110        {
111            return new JavaObject(javaClass(arg));
112        }
113    };
114
115    // ### jfield - retrieve or modify a field in a Java class or instance.
116    //
117    // Supported argument patterns:
118    //
119    //   Case 1: class-ref  field-name:
120    //               to retrieve the value of a static field.
121    //
122    //   Case 2: class-ref  field-name  instance-ref:
123    //               to retrieve the value of a class field of the instance.
124    //
125    //   Case 3: class-ref  field-name  primitive-value:
126    //               to store primitive-value in a static field.
127    //
128    //   Case 4: class-ref  field-name  instance-ref  value:
129    //               to store value in a class field of the instance.
130    //
131    //   Case 5: class-ref  field-name  nil  value:
132    //               to store value in a static field (when value may be
133    //               confused with an instance-ref).
134    //
135    //   Case 6: field-name  instance:
136    //               to retrieve the value of a field of the instance. The
137    //               class is derived from the instance.
138    //
139    //   Case 7: field-name  instance  value:
140    //               to store value in a field of the instance. The class is
141    //               derived from the instance.
142    //
143    private static final Primitive JFIELD =
144        new Primitive("jfield", PACKAGE_JAVA, true,
145                      "class-ref-or-field field-or-instance &optional instance value")
146    {
147        @Override
148        public LispObject execute(LispObject[] args) throws ConditionThrowable
149        {
150            return makeLispObject((JFIELD_RAW.execute(args)).javaInstance());
151        }
152    };
153
154    // ### jfield-raw - retrieve or modify a field in a Java class or instance.
155    private static final Primitive JFIELD_RAW =
156        new Primitive("jfield-raw", PACKAGE_JAVA, true,
157                      "class-ref-or-field field-or-instance &optional instance value")
158    {
159        @Override
160        public LispObject execute(LispObject[] args) throws ConditionThrowable
161        {
162            if (args.length < 2 || args.length > 4)
163                error(new WrongNumberOfArgumentsException(this));
164            String fieldName = null;
165            Class c;
166            Field f;
167            Class fieldType;
168            Object instance = null;
169            try {
170                if (args[1] instanceof AbstractString) {
171                    // Cases 1-5.
172                    fieldName = args[1].getStringValue();
173                    c = javaClass(args[0]);
174                } else {
175                    // Cases 6 and 7.
176                    fieldName = args[0].getStringValue();
177                    instance = JavaObject.getObject(args[1]);
178                    c = instance.getClass();
179                }
180                f = c.getField(fieldName);
181                fieldType = f.getType();
182                switch (args.length) {
183                    case 2:
184                        // Cases 1 and 6.
185                        break;
186                    case 3:
187                        // Cases 2,3, and 7.
188                        if (instance == null) {
189                            // Cases 2 and 3.
190                            if (args[2] instanceof JavaObject) {
191                                // Case 2.
192                                instance = JavaObject.getObject(args[2]);
193                                break;
194                            } else {
195                                // Case 3.
196                                f.set(null,args[2].javaInstance(fieldType));
197                                return args[2];
198                            }
199                        } else {
200                            // Case 7.
201                            f.set(instance,args[2].javaInstance(fieldType));
202                            return args[2];
203                        }
204                    case 4:
205                        // Cases 4 and 5.
206                        if (args[2] != NIL) {
207                            // Case 4.
208                            instance = JavaObject.getObject(args[2]);
209                        }
210                        f.set(instance,args[3].javaInstance(fieldType));
211                        return args[3];
212                }
213                return new JavaObject(f.get(instance));
214            }
215            catch (NoSuchFieldException e) {
216                error(new LispError("no such field"));
217            }
218            catch (SecurityException e) {
219                error(new LispError("inaccessible field"));
220            }
221            catch (IllegalAccessException e) {
222                error(new LispError("illegal access"));
223            }
224            catch (IllegalArgumentException e) {
225                error(new LispError("illegal argument"));
226            }
227            catch (Throwable t) {
228                error(new LispError(getMessage(t)));
229            }
230            // Not reached.
231            return NIL;
232        }
233    };
234
235    // ### jconstructor class-ref &rest parameter-class-refs
236    private static final Primitive JCONSTRUCTOR =
237        new Primitive("jconstructor", PACKAGE_JAVA, true,
238                      "class-ref &rest parameter-class-refs")
239    {
240        @Override
241        public LispObject execute(LispObject[] args) throws ConditionThrowable
242        {
243            if (args.length < 1)
244                error(new WrongNumberOfArgumentsException(this));
245            try {
246                final Class c = javaClass(args[0]);
247                int argCount = 0;
248                if (args.length == 2 && args[1] instanceof Fixnum) {
249                    argCount = Fixnum.getValue(args[1]);
250                } else {
251                    Class[] parameterTypes = new Class[args.length-1];
252                    for (int i = 1; i < args.length; i++) {
253                        parameterTypes[i-1] = javaClass(args[i]);
254                    }
255                    return new JavaObject(c.getConstructor(parameterTypes));
256                }
257                // Parameter types not explicitly specified.
258                Constructor[] constructors = c.getConstructors();
259                for (int i = 0; i < constructors.length; i++) {
260                    Constructor constructor = constructors[i];
261                    if (constructor.getParameterTypes().length == argCount)
262                        return new JavaObject(constructor);
263                }
264                throw new NoSuchMethodException();
265            }
266            catch (NoSuchMethodException e) {
267                error(new LispError("no such constructor"));
268            }
269            catch (ConditionThrowable e) {
270                throw e;
271            }
272            catch (Throwable t) {
273                error(new LispError(getMessage(t)));
274            }
275            // Not reached.
276            return NIL;
277        }
278    };
279
280    // ### jmethod class-ref name &rest parameter-class-refs
281    private static final Primitive JMETHOD =
282        new Primitive("jmethod", PACKAGE_JAVA, true,
283                      "class-ref name &rest parameter-class-refs")
284    {
285        @Override
286        public LispObject execute(LispObject[] args) throws ConditionThrowable
287        {
288            if (args.length < 2)
289                error(new WrongNumberOfArgumentsException(this));
290            final Class c = javaClass(args[0]);
291            String methodName = args[1].getStringValue();
292            try {
293                int argCount = 0;
294                if (args.length == 3 && args[2] instanceof Fixnum) {
295                    argCount = ((Fixnum)args[2]).value;
296                } else {
297                    Class[] parameterTypes = new Class[args.length-2];
298                    for (int i = 2; i < args.length; i++)
299                        parameterTypes[i-2] = javaClass(args[i]);
300                    return new JavaObject(c.getMethod(methodName,
301                                                      parameterTypes));
302                }
303                // Parameter types were not explicitly specified.
304                Method[] methods = c.getMethods();
305                for (int i = 0; i < methods.length; i++) {
306                    Method method = methods[i];
307                    if (method.getName().equals(methodName) &&
308                        method.getParameterTypes().length == argCount)
309                        return new JavaObject(method);
310                }
311                throw new NoSuchMethodException();
312            }
313            catch (NoSuchMethodException e) {
314                FastStringBuffer sb = new FastStringBuffer("No such method: ");
315                sb.append(c.getName());
316                sb.append('.');
317                sb.append(methodName);
318                sb.append('(');
319                for (int i = 2; i < args.length; i++) {
320                    sb.append(args[i].writeToString());
321                    if (i < args.length - 1)
322                        sb.append(',');
323                }
324                sb.append(')');
325                error(new LispError(sb.toString()));
326            }
327            catch (ConditionThrowable e) {
328                throw e;
329            }
330            catch (Throwable t) {
331                error(new LispError(getMessage(t)));
332            }
333            // Not reached.
334            return NIL;
335        }
336    };
337
338    // ### jstatic method class &rest args
339    private static final Primitive JSTATIC =
340        new Primitive("jstatic", PACKAGE_JAVA, true, "method class &rest args")
341    {
342        @Override
343        public LispObject execute(LispObject[] args) throws ConditionThrowable
344        {
345            return makeLispObject((JSTATIC_RAW.execute(args)).javaInstance());
346        }
347    };
348
349    // ### jstatic-raw method class &rest args
350    private static final Primitive JSTATIC_RAW =
351        new Primitive("jstatic-raw", PACKAGE_JAVA, true,
352                      "method class &rest args")
353    {
354        @Override
355        public LispObject execute(LispObject[] args) throws ConditionThrowable
356        {
357            if (args.length < 2)
358                error(new WrongNumberOfArgumentsException(this));
359            try {
360                Method m = null;
361                LispObject methodRef = args[0];
362                if (methodRef instanceof JavaObject) {
363                    Object obj = ((JavaObject)methodRef).getObject();
364                    if (obj instanceof Method)
365                        m = (Method) obj;
366                } else if (methodRef instanceof AbstractString) {
367                    Class c = javaClass(args[1]);
368                    if (c != null) {
369                        String methodName = methodRef.getStringValue();
370                        Method[] methods = c.getMethods();
371                        int argCount = args.length - 2;
372                        for (int i = 0; i < methods.length; i++) {
373                            Method method = methods[i];
374                            if (!Modifier.isStatic(method.getModifiers())
375                                || method.getParameterTypes().length != argCount)
376                                continue;
377                            if (method.getName().equals(methodName)) {
378                                m = method;
379                                break;
380                            }
381                        }
382                        if (m == null)
383                            error(new LispError("no such method"));
384                    }
385                } else
386                    error(new TypeError("wrong type: " + methodRef));
387                Object[] methodArgs = new Object[args.length-2];
388                Class[] argTypes = m.getParameterTypes();
389                for (int i = 2; i < args.length; i++) {
390                    LispObject arg = args[i];
391                    if (arg == NIL)
392                        methodArgs[i-2] = null;
393                    else
394                        methodArgs[i-2] = arg.javaInstance(argTypes[i-2]);
395                }
396                Object result = m.invoke(null, methodArgs);
397                return new JavaObject(result);
398            }
399            catch (Throwable t) {
400                if (t instanceof InvocationTargetException)
401                    t = t.getCause();
402                Symbol condition = getCondition(t.getClass());
403                if (condition == null)
404                    error(new JavaException(t));
405                else
406                    Symbol.SIGNAL.execute(
407                        condition,
408                        Keyword.CAUSE,
409                        new JavaObject(t),
410                        Keyword.FORMAT_CONTROL,
411                        new SimpleString(getMessage(t)));
412            }
413            // Not reached.
414            return NIL;
415        }
416    };
417
418    // ### jnew constructor &rest args
419    private static final Primitive JNEW =
420        new Primitive("jnew", PACKAGE_JAVA, true, "constructor &rest args")
421    {
422        @Override
423        public LispObject execute(LispObject[] args) throws ConditionThrowable
424        {
425            if (args.length < 1)
426                error(new WrongNumberOfArgumentsException(this));
427            LispObject classRef = args[0];
428            try {
429                Constructor constructor = (Constructor) JavaObject.getObject(classRef);
430                Class[] argTypes = constructor.getParameterTypes();
431                Object[] initargs = new Object[args.length-1];
432                for (int i = 1; i < args.length; i++) {
433                    LispObject arg = args[i];
434                    if (arg == NIL)
435                        initargs[i-1] = null;
436                    else {
437                        initargs[i-1] = arg.javaInstance(argTypes[i-1]);
438                    }
439                }
440                return new JavaObject(constructor.newInstance(initargs));
441            }
442            catch (Throwable t) {
443                if (t instanceof InvocationTargetException)
444                    t = t.getCause();
445                Symbol condition = getCondition(t.getClass());
446                if (condition == null)
447                    error(new JavaException(t));
448                else
449                    Symbol.SIGNAL.execute(
450                        condition,
451                        Keyword.CAUSE,
452                        new JavaObject(t),
453                        Keyword.FORMAT_CONTROL,
454                        new SimpleString(getMessage(t)));
455            }
456            // Not reached.
457            return NIL;
458        }
459    };
460
461    // ### jnew-array element-type &rest dimensions
462    private static final Primitive JNEW_ARRAY =
463        new Primitive("jnew-array", PACKAGE_JAVA, true,
464                      "element-type &rest dimensions")
465    {
466        @Override
467        public LispObject execute(LispObject[] args) throws ConditionThrowable
468        {
469            if (args.length < 2)
470                error(new WrongNumberOfArgumentsException(this));
471            try {
472                Class c = javaClass(args[0]);
473                int[] dimensions = new int[args.length - 1];
474                for (int i = 1; i < args.length; i++)
475                    dimensions[i-1] = ((Integer)args[i].javaInstance()).intValue();
476                return new JavaObject(Array.newInstance(c, dimensions));
477            }
478            catch (Throwable t) {
479                error(new JavaException(t));
480            }
481            // Not reached.
482            return NIL;
483        }
484    };
485
486    // ### jarray-ref java-array &rest indices
487    private static final Primitive JARRAY_REF =
488        new Primitive("jarray-ref", PACKAGE_JAVA, true,
489                      "java-array &rest indices")
490    {
491        @Override
492        public LispObject execute(LispObject[] args) throws ConditionThrowable
493        {
494            return makeLispObject((JARRAY_REF_RAW.execute(args)).javaInstance());
495        }
496    };
497
498    // ### jarray-ref-raw java-array &rest indices
499    private static final Primitive JARRAY_REF_RAW =
500        new Primitive("jarray-ref-raw", PACKAGE_JAVA, true,
501                      "java-array &rest indices")
502    {
503        @Override
504        public LispObject execute(LispObject[] args) throws ConditionThrowable
505        {
506            if (args.length < 2)
507                error(new WrongNumberOfArgumentsException(this));
508            try {
509                Object a = args[0].javaInstance();
510                for (int i = 1; i<args.length - 1; i++)
511                    a = Array.get(a, ((Integer)args[i].javaInstance()).intValue());
512                return new JavaObject(Array.get(a, ((Integer)args[args.length - 1].javaInstance()).intValue()));
513            }
514            catch (Throwable t) {
515                Symbol condition = getCondition(t.getClass());
516                if (condition == null)
517                    error(new JavaException(t));
518                else
519                    Symbol.SIGNAL.execute(
520                        condition,
521                        Keyword.CAUSE,
522                        new JavaObject(t),
523                        Keyword.FORMAT_CONTROL,
524                        new SimpleString(getMessage(t)));
525            }
526            // Not reached.
527            return NIL;
528        }
529    };
530
531    // ### jarray-set java-array new-value &rest indices
532    private static final Primitive JARRAY_SET =
533        new Primitive("jarray-set", PACKAGE_JAVA, true,
534                      "java-array new-value &rest indices")
535    {
536        @Override
537        public LispObject execute(LispObject[] args) throws ConditionThrowable
538        {
539            if (args.length < 3)
540                error(new WrongNumberOfArgumentsException(this));
541            try {
542                Object a = args[0].javaInstance();
543                LispObject v = args[1];
544                for (int i = 2; i<args.length - 1; i++)
545                    a = Array.get(a, ((Integer)args[i].javaInstance()).intValue());
546                Array.set(a, ((Integer)args[args.length - 1].javaInstance()).intValue(), v.javaInstance());
547                return v;
548            }
549            catch (Throwable t) {
550                Symbol condition = getCondition(t.getClass());
551                if (condition == null)
552                    error(new JavaException(t));
553                else
554                    Symbol.SIGNAL.execute(
555                        condition,
556                        Keyword.CAUSE,
557                        new JavaObject(t),
558                        Keyword.FORMAT_CONTROL,
559                        new SimpleString(getMessage(t)));
560            }
561            // Not reached.
562            return NIL;
563        }
564    };
565
566    // ### jcall method instance &rest args
567    // Calls makeLispObject() to convert the result to an appropriate Lisp type.
568    private static final Primitive JCALL =
569        new Primitive(Symbol.JCALL, "method-ref instance &rest args")
570    {
571        @Override
572        public LispObject execute(LispObject[] args) throws ConditionThrowable
573        {
574            if (args.length < 2)
575                error(new WrongNumberOfArgumentsException(this));
576            return makeLispObject(jcall(args));
577        }
578    };
579
580    // ### jcall-raw method instance &rest args
581    // Does no type conversion. The result of the call is simply wrapped in a
582    // JavaObject.
583    private static final Primitive JCALL_RAW =
584        new Primitive(Symbol.JCALL_RAW, "method-ref instance &rest args")
585    {
586        @Override
587        public LispObject execute(LispObject[] args) throws ConditionThrowable
588        {
589            if (args.length < 2)
590                error(new WrongNumberOfArgumentsException(this));
591            return new JavaObject(jcall(args));
592        }
593    };
594
595    private static Object jcall(LispObject[] args) throws ConditionThrowable
596    {
597        Debug.assertTrue(args.length >= 2); // Verified by callers.
598        final LispObject methodArg = args[0];
599        final LispObject instanceArg = args[1];
600        final Object instance;
601        if (instanceArg instanceof AbstractString)
602            instance = instanceArg.getStringValue();
603        else if (instanceArg instanceof JavaObject)
604            instance = ((JavaObject)instanceArg).getObject();
605        else {
606            type_error(instanceArg,
607                            list3(Symbol.OR, Symbol.STRING, Symbol.JAVA_OBJECT));
608            // Not reached.
609            return null;
610        }
611        try {
612            final Method method;
613            if (methodArg instanceof AbstractString) {
614                String methodName = methodArg.getStringValue();
615                Class c = instance.getClass();
616                // FIXME Use the actual args, not just the count!
617                method = findMethod(c, methodName, args.length - 2);
618            } else
619                method = (Method) JavaObject.getObject(methodArg);
620            Class[] argTypes = method.getParameterTypes();
621            Object[] methodArgs = new Object[args.length - 2];
622            for (int i = 2; i < args.length; i++) {
623                LispObject arg = args[i];
624                if (arg == NIL)
625                    methodArgs[i-2] = null;
626                else
627                    methodArgs[i-2] = arg.javaInstance(argTypes[i-2]);
628            }
629            return method.invoke(instance, methodArgs);
630        }
631        catch (ConditionThrowable t) {
632            throw t;
633        }
634        catch (Throwable t) {
635            if (t instanceof InvocationTargetException)
636                t = t.getCause();
637            Symbol condition = getCondition(t.getClass());
638            if (condition == null)
639                error(new JavaException(t));
640            else
641                Symbol.SIGNAL.execute(
642                    condition,
643                    Keyword.CAUSE,
644                    new JavaObject(t),
645                    Keyword.FORMAT_CONTROL,
646                    new SimpleString(getMessage(t)));
647        }
648        // Not reached.
649        return null;
650    }
651
652    // FIXME This just returns the first matching method that it finds. Allegro
653    // signals a continuable error if there are multiple matching methods.
654    private static Method findMethod(Class c, String methodName, int argCount)
655    {
656        Method[] methods = c.getMethods();
657        for (int i = methods.length; i-- > 0;) {
658            Method method = methods[i];
659            if (method.getName().equals(methodName))
660                if (method.getParameterTypes().length == argCount)
661                    return method;
662        }
663        return null;
664    }
665
666    // ### make-immediate-object object &optional type
667    private static final Primitive MAKE_IMMEDIATE_OBJECT =
668        new Primitive("make-immediate-object", PACKAGE_JAVA, true,
669                      "object &optional type")
670    {
671        @Override
672        public LispObject execute(LispObject[] args) throws ConditionThrowable
673        {
674            if (args.length < 1)
675                error(new WrongNumberOfArgumentsException(this));
676            LispObject object = args[0];
677            try {
678                if (args.length > 1) {
679                    LispObject type = args[1];
680                    if (type == Keyword.BOOLEAN) {
681                        if (object == NIL)
682                            return new JavaObject(Boolean.FALSE);
683                        else
684                            return new JavaObject(Boolean.TRUE);
685                    }
686                    if (type == Keyword.REF) {
687                        if (object == NIL)
688                            return new JavaObject(null);
689                        else
690                            throw new Error();
691                    }
692                    // other special cases come here
693                }
694                return new JavaObject(object.javaInstance());
695            }
696            catch (Throwable t) {
697                error(new LispError("MAKE-IMMEDIATE-OBJECT: not implemented"));
698            }
699            // Not reached.
700            return NIL;
701        }
702    };
703
704    // ### java-object-p
705    private static final Primitive JAVA_OBJECT_P =
706        new Primitive("java-object-p", PACKAGE_JAVA, true, "object")
707    {
708        @Override
709        public LispObject execute(LispObject arg) throws ConditionThrowable
710        {
711            return (arg instanceof JavaObject) ? T : NIL;
712        }
713    };
714
715    // ### jobject-lisp-value java-object
716    private static final Primitive JOBJECT_LISP_VALUE =
717        new Primitive("jobject-lisp-value", PACKAGE_JAVA, true, "java-object")
718    {
719        @Override
720        public LispObject execute(LispObject arg) throws ConditionThrowable
721        {
722            return makeLispObject(arg.javaInstance());
723        }
724    };
725
726    private static Class classForName(String className) throws ConditionThrowable
727    {
728        try {
729            return Class.forName(className);
730        }
731        catch (ClassNotFoundException e) {
732            try {
733                return Class.forName(className, true, JavaClassLoader.getPersistentInstance());
734            }
735            catch (ClassNotFoundException ex) {
736                error(new LispError("Class not found: " + className));
737                // Not reached.
738                return null;
739            }
740        }
741    }
742
743    // Supports Java primitive types too.
744    private static Class javaClass(LispObject obj) throws ConditionThrowable
745    {
746        if (obj instanceof AbstractString || obj instanceof Symbol) {
747            String s = javaString(obj);
748            if (s.equals("boolean"))
749                return Boolean.TYPE;
750            if (s.equals("byte"))
751                return Byte.TYPE;
752            if (s.equals("char"))
753                return Character.TYPE;
754            if (s.equals("short"))
755                return Short.TYPE;
756            if (s.equals("int"))
757                return Integer.TYPE;
758            if (s.equals("long"))
759                return Long.TYPE;
760            if (s.equals("float"))
761                return Float.TYPE;
762            if (s.equals("double"))
763                return Double.TYPE;
764            // Not a primitive Java type.
765            return classForName(s);
766        }
767        // It's not a string, so it must be a JavaObject.
768        final JavaObject javaObject;
769        try {
770            javaObject = (JavaObject) obj;
771        }
772        catch (ClassCastException e) {
773            type_error(obj, list3(Symbol.OR, Symbol.STRING,
774                                       Symbol.JAVA_OBJECT));
775            // Not reached.
776            return null;
777        }
778        try {
779            return (Class) javaObject.getObject();
780        }
781        catch (ClassCastException e) {
782            error(new LispError(obj.writeToString() + " does not designate a Java class."));
783            return null;
784        }
785    }
786
787    private static final LispObject makeLispObject(Object obj)
788        throws ConditionThrowable
789    {
790        if (obj == null)
791            return NIL;
792        if (obj instanceof Boolean)
793            return ((Boolean)obj).booleanValue() ? T : NIL;
794        if (obj instanceof Byte)
795            return new Fixnum(((Byte)obj).intValue());
796        if (obj instanceof Integer)
797            return new Fixnum(((Integer)obj).intValue());
798        if (obj instanceof Short)
799            return new Fixnum(((Short)obj).shortValue());
800        if (obj instanceof Long)
801            return new Bignum(((Long)obj).longValue());
802        if (obj instanceof Float)
803            return new SingleFloat(((Float)obj).floatValue());
804        if (obj instanceof Double)
805            return new DoubleFloat(((Double)obj).doubleValue());
806        if (obj instanceof String)
807            return new SimpleString((String)obj);
808        if (obj instanceof Character)
809            return LispCharacter.getInstance(((Character)obj).charValue());
810        if (obj instanceof Object[]) {
811            Object[] array = (Object[]) obj;
812            SimpleVector v = new SimpleVector(array.length);
813            for (int i = array.length; i-- > 0;)
814                v.aset(i, new JavaObject(array[i]));
815            return v;
816        }
817        if (obj instanceof LispObject)
818            return (LispObject) obj;
819        return new JavaObject(obj);
820    }
821
822    private static final String getMessage(Throwable t)
823    {
824        String message = t.getMessage();
825        if (message == null || message.length() == 0)
826            message = t.getClass().getName();
827        return message;
828    }
829}
Note: See TracBrowser for help on using the repository browser.