source: branches/streams/abcl/src/org/armedbear/lisp/Java.java

Last change on this file was 14694, checked in by Mark Evenson, 11 years ago

Convert Lisp truth values to Java equivalents in JCALL/JSTATIC.

We now convert CL:T and CL:NIL to JAVA:+TRUE+ and JAVA:+FALSE+
respectively when invoking JVM methods through the JAVA package,
establishing the "natural" equivalence for boolean truth values. This
may break some existing usage in that previously CL:NIL was converted
to a Java 'null' reference. Users now need to specify JAVA:+NULL+
explicitly when desiring to pass 'null' Java references as an argument
in invoking JVM methods.

Addresses <http://abcl.org/trac/ticket/84> (#84) and
<http://abcl.org/trac/ticket/339> (#339).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 51.3 KB
Line 
1/*
2 * Java.java
3 *
4 * Copyright (C) 2002-2006 Peter Graves, Andras Simon
5 * $Id: Java.java 14694 2014-04-25 07:55:53Z mevenson $
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 static org.armedbear.lisp.Lisp.*;
37
38import java.lang.reflect.Array;
39import java.lang.reflect.Constructor;
40import java.lang.reflect.Field;
41import java.lang.reflect.InvocationTargetException;
42import java.lang.reflect.Method;
43import java.lang.reflect.Modifier;
44import java.text.MessageFormat;
45import java.util.*;
46
47public final class Java
48{
49    static final Map<Class,Symbol> registeredExceptions =
50       new HashMap<Class,Symbol>();
51
52    private static final LispClass java_exception = LispClass.findClass(Symbol.JAVA_EXCEPTION);
53
54    static boolean isJavaException(LispClass lc)
55    {
56        return lc.subclassp(java_exception);
57    }
58
59    private static final Primitive ENSURE_JAVA_OBJECT = new pf_ensure_java_object();
60    @DocString(name="ensure-java-object", args="obj",
61    doc="Ensures OBJ is wrapped in a JAVA-OBJECT, wrapping it if necessary.")
62    private static final class pf_ensure_java_object extends Primitive
63    {
64        pf_ensure_java_object()
65        {
66            super("ensure-java-object", PACKAGE_JAVA, true);
67        }
68
69        @Override
70        public LispObject execute(LispObject obj) {
71            return obj instanceof JavaObject ? obj : new JavaObject(obj);
72        }
73    };
74
75    private static final Primitive REGISTER_JAVA_EXCEPTION = new pf_register_java_exception();
76    @DocString(name="register-java-exception", // => T
77    args="exception-name condition-symbol",
78    doc="Registers the Java Throwable named by the symbol EXCEPTION-NAME as the condition " +
79        "designated by CONDITION-SYMBOL.  Returns T if successful, NIL if not.")
80    private static final class pf_register_java_exception extends Primitive
81    {
82        pf_register_java_exception()
83        {
84            super("register-java-exception", PACKAGE_JAVA, true);
85        }
86
87        @Override
88        public LispObject execute(LispObject className, LispObject symbol)
89
90        {
91            LispClass lispClass = (LispClass) LispClass.findClass(symbol, true);
92            // FIXME Signal a continuable error if the exception is already registered.
93            if (isJavaException(lispClass)) {
94                registeredExceptions.put(classForName(className.getStringValue()),
95                                         (Symbol)symbol);
96                return T;
97            }
98            return NIL;
99        }
100    };
101
102    private static final Primitive UNREGISTER_JAVA_EXCEPTION = new pf_unregister_java_exception();
103    @DocString(name="unregister-java-exception", args="exception-name",
104    doc="Unregisters the Java Throwable EXCEPTION-NAME previously registered" +
105        " by REGISTER-JAVA-EXCEPTION.")
106    private static final class pf_unregister_java_exception extends Primitive
107    {
108        pf_unregister_java_exception()
109        {
110            super("unregister-java-exception", PACKAGE_JAVA, true);
111        }
112
113        @Override
114        public LispObject execute(LispObject className)
115
116        {
117            // FIXME Verify that EXCEPTION-NAME designates a subclass of Throwable.
118            return registeredExceptions.remove(classForName(className.getStringValue())) == null ? NIL : T;
119        }
120    };
121
122    static Symbol getCondition(Class cl) {
123        Class o = classForName("java.lang.Object");
124        for (Class c = cl ; c != o ; c = c.getSuperclass()) {
125            Object object = registeredExceptions.get(c);
126            if (object instanceof Symbol) {
127                LispClass lispClass = (LispClass) LispClass.findClass((Symbol) object, true);
128                if(isJavaException(lispClass)) {
129                    return (Symbol) object;
130                }
131            }
132        }
133        return null;
134    }
135
136    private static final Primitive JCLASS = new pf_jclass();
137    @DocString(name="jclass", args="name-or-class-ref &optional class-loader",
138    doc="Returns a reference to the Java class designated by" +
139        " NAME-OR-CLASS-REF. If the CLASS-LOADER parameter is passed, the" +
140        " class is resolved with respect to the given ClassLoader.")
141    private static final class pf_jclass extends Primitive
142    {
143
144        pf_jclass() 
145        {
146            super(Symbol.JCLASS);
147        }
148
149        @Override
150        public LispObject execute(LispObject arg)
151        {
152      return JavaObject.getInstance(javaClass(arg, JavaClassLoader.getCurrentClassLoader()));
153        }
154
155        @Override
156        public LispObject execute(LispObject className, LispObject classLoader)
157        {
158      ClassLoader loader = (ClassLoader) classLoader.javaInstance(ClassLoader.class);
159      return JavaObject.getInstance(javaClass(className, loader));
160        }
161    };
162
163    static final LispObject jfield(Primitive fun, LispObject[] args, boolean translate)
164
165    {
166        if (args.length < 2 || args.length > 4)
167            error(new WrongNumberOfArgumentsException(fun, 2, 4));
168        String fieldName = null;
169        Class c;
170        Field f;
171        Class fieldType;
172        Object instance = null;
173        try {
174            if (args[1] instanceof AbstractString) {
175                // Cases 1-5.
176                fieldName = args[1].getStringValue();
177                c = javaClass(args[0]);
178            } else {
179                // Cases 6 and 7.
180                fieldName = args[0].getStringValue();
181                instance = JavaObject.getObject(args[1]);
182                c = instance.getClass();
183            }
184            f = c.getField(fieldName);
185            fieldType = f.getType();
186            switch (args.length) {
187                case 2:
188                    // Cases 1 and 6.
189                    break;
190                case 3:
191                    // Cases 2,3, and 7.
192                    if (instance == null) {
193                        // Cases 2 and 3.
194                        if (args[2] instanceof JavaObject) {
195                            // Case 2.
196                            instance = JavaObject.getObject(args[2]);
197                            break;
198                        } else {
199                            // Case 3.
200                            f.set(null,args[2].javaInstance(fieldType));
201                            return args[2];
202                        }
203                    } else {
204                        // Case 7.
205                        f.set(instance,args[2].javaInstance(fieldType));
206                        return args[2];
207                    }
208                case 4:
209                    // Cases 4 and 5.
210                    if (args[2] != NIL) {
211                        // Case 4.
212                        instance = JavaObject.getObject(args[2]);
213                    }
214                    f.set(instance,args[3].javaInstance(fieldType));
215                    return args[3];
216            }
217            return JavaObject.getInstance(f.get(instance), translate, f.getType());
218        }
219        catch (NoSuchFieldException e) {
220            error(new LispError("no such field"));
221        }
222        catch (SecurityException e) {
223            error(new LispError("inaccessible field"));
224        }
225        catch (IllegalAccessException e) {
226            error(new LispError("illegal access"));
227        }
228        catch (IllegalArgumentException e) {
229            error(new LispError("illegal argument"));
230        }
231        catch (Throwable t) { // no code -> no ControlTransfer
232            error(new LispError(getMessage(t)));
233        }
234        // Not reached.
235        return NIL;
236    }
237
238
239    private static final Primitive JFIELD = new pf_jfield();
240    @DocString(name="jfield",
241    args="class-ref-or-field field-or-instance &optional instance value",
242    doc="Retrieves or modifies a field in a Java class or instance.\n\n"+
243        "Supported argument patterns:\n\n"+
244        "   Case 1: class-ref  field-name:\n"+
245        "      Retrieves the value of a static field.\n\n"+
246        "   Case 2: class-ref  field-name  instance-ref:\n"+
247        "      Retrieves the value of a class field of the instance.\n\n"+
248        "   Case 3: class-ref  field-name  primitive-value:\n"+
249        "      Stores a primitive-value in a static field.\n\n"+
250        "   Case 4: class-ref  field-name  instance-ref  value:\n"+
251        "      Stores value in a class field of the instance.\n\n"+
252        "   Case 5: class-ref  field-name  nil  value:\n"+
253        "      Stores value in a static field (when value may be\n"+
254        "      confused with an instance-ref).\n\n"+
255        "   Case 6: field-name  instance:\n"+
256        "      Retrieves the value of a field of the instance. The\n"+
257        "      class is derived from the instance.\n\n"+
258        "   Case 7: field-name  instance  value:\n"+
259        "      Stores value in a field of the instance. The class is\n"+
260        "      derived from the instance.\n\n"
261        )
262    private static final class pf_jfield extends Primitive
263    {
264        pf_jfield() 
265        {
266            super("jfield", PACKAGE_JAVA, true);
267        }
268
269        @Override
270        public LispObject execute(LispObject[] args)
271        {
272            return jfield(this, args, true);
273        }
274    };
275
276    private static final Primitive JFIELD_RAW = new pf_jfield_raw();
277    @DocString(name="jfield",
278    args="class-ref-or-field field-or-instance &optional instance value",
279    doc="Retrieves or modifies a field in a Java class or instance. Does not\n"+
280        "attempt to coerce its value or the result into a Lisp object.\n\n"+
281        "Supported argument patterns:\n\n"+
282        "   Case 1: class-ref  field-name:\n"+
283        "      Retrieves the value of a static field.\n\n"+
284        "   Case 2: class-ref  field-name  instance-ref:\n"+
285        "      Retrieves the value of a class field of the instance.\n\n"+
286        "   Case 3: class-ref  field-name  primitive-value:\n"+
287        "      Stores a primitive-value in a static field.\n\n"+
288        "   Case 4: class-ref  field-name  instance-ref  value:\n"+
289        "      Stores value in a class field of the instance.\n\n"+
290        "   Case 5: class-ref  field-name  nil  value:\n"+
291        "      Stores value in a static field (when value may be\n"+
292        "      confused with an instance-ref).\n\n"+
293        "   Case 6: field-name  instance:\n"+
294        "      Retrieves the value of a field of the instance. The\n"+
295        "      class is derived from the instance.\n\n"+
296        "   Case 7: field-name  instance  value:\n"+
297        "      Stores value in a field of the instance. The class is\n"+
298        "      derived from the instance.\n\n"
299        )
300    private static final class pf_jfield_raw extends Primitive
301    {
302        pf_jfield_raw() 
303        {
304            super("jfield-raw", PACKAGE_JAVA, true);
305        }
306
307        @Override
308        public LispObject execute(LispObject[] args)
309        {
310            return jfield(this, args, false);
311        }
312    };
313
314    private static final Primitive JCONSTRUCTOR = new pf_jconstructor();
315    @DocString(name="jconstructor", args="class-ref &rest parameter-class-refs",
316    doc="Returns a reference to the Java constructor of CLASS-REF with the" +
317        " given PARAMETER-CLASS-REFS.")
318    private static final class pf_jconstructor extends Primitive
319    {
320        pf_jconstructor() 
321        {
322            super("jconstructor", PACKAGE_JAVA, true);
323        }
324
325        @Override
326        public LispObject execute(LispObject[] args)
327        {
328            if (args.length < 1)
329                error(new WrongNumberOfArgumentsException(this, 1, -1));
330            try {
331                final Class<?> c = javaClass(args[0]);
332                int argCount = 0;
333                if (args.length == 2 && args[1] instanceof Fixnum) {
334                    argCount = Fixnum.getValue(args[1]);
335                } else {
336                    Class<?>[] parameterTypes = new Class[args.length-1];
337                    for (int i = 1; i < args.length; i++) {
338                        parameterTypes[i-1] = javaClass(args[i]);
339                    }
340                    return JavaObject.getInstance(c.getConstructor(parameterTypes));
341                }
342                // Parameter types not explicitly specified.
343                Constructor[] constructors = c.getConstructors();
344                for (int i = 0; i < constructors.length; i++) {
345                    Constructor constructor = constructors[i];
346                    if (constructor.getParameterTypes().length == argCount)
347                        return JavaObject.getInstance(constructor);
348                }
349                throw new NoSuchMethodException();
350            }
351            catch (NoSuchMethodException e) {
352                error(new LispError("no such constructor"));
353            }
354            catch (ControlTransfer e) {
355                throw e;
356            }
357            catch (Throwable t) { // ControlTransfer addressed above
358                error(new LispError(getMessage(t)));
359            }
360            // Not reached.
361            return NIL;
362        }
363    };
364
365    private static final Primitive JMETHOD = new pf_jmethod();
366
367    @DocString(name="jmethod", args="class-ref method-name &rest parameter-class-refs",
368    doc="Returns a reference to the Java method METHOD-NAME of CLASS-REF with the" +
369        " given PARAMETER-CLASS-REFS.")
370    private static final class pf_jmethod extends Primitive
371    {
372        pf_jmethod() 
373        {
374            super("jmethod", PACKAGE_JAVA, true);
375        }
376
377        @Override
378        public LispObject execute(LispObject[] args)
379        {
380            if (args.length < 2)
381                error(new WrongNumberOfArgumentsException(this, 2, -1));
382            final Class<?> c = javaClass(args[0]);
383            String methodName = args[1].getStringValue();
384            try {
385                int argCount = 0;
386                if (args.length == 3 && args[2] instanceof Fixnum) {
387                    argCount = ((Fixnum)args[2]).value;
388                } else {
389                    Class<?>[] parameterTypes = new Class[args.length-2];
390                    for (int i = 2; i < args.length; i++)
391                        parameterTypes[i-2] = javaClass(args[i]);
392                    return JavaObject.getInstance(c.getMethod(methodName,
393                                                              parameterTypes));
394                }
395                // Parameter types were not explicitly specified.
396                Method[] methods = c.getMethods();
397                for (int i = 0; i < methods.length; i++) {
398                    Method method = methods[i];
399                    if (method.getName().equals(methodName) &&
400                        method.getParameterTypes().length == argCount)
401                        return JavaObject.getInstance(method);
402                }
403                throw new NoSuchMethodException();
404            }
405            catch (NoSuchMethodException e) {
406                StringBuilder sb = new StringBuilder("No such method: ");
407                sb.append(c.getName());
408                sb.append('.');
409                sb.append(methodName);
410                sb.append('(');
411                for (int i = 2; i < args.length; i++) {
412                    sb.append(args[i].princToString());
413                    if (i < args.length - 1)
414                        sb.append(',');
415                }
416                sb.append(')');
417                error(new LispError(sb.toString()));
418            }
419            catch (ControlTransfer e) {
420                throw e;
421            }
422            catch (Throwable t) { // ControlTransfer addressed above
423                error(new LispError(getMessage(t)));
424            }
425            // Not reached.
426            return NIL;
427        }
428    };
429
430    static final LispObject jstatic(Primitive fun, LispObject[] args, boolean translate)
431
432    {
433        if (args.length < 2)
434            error(new WrongNumberOfArgumentsException(fun, 2, -1));
435        try {
436            Method m = null;
437            LispObject methodRef = args[0];
438            if (methodRef instanceof JavaObject) {
439                Object obj = ((JavaObject)methodRef).getObject();
440                if (obj instanceof Method)
441                    m = (Method) obj;
442            } else if (methodRef instanceof AbstractString) {
443                Class c = javaClass(args[1]);
444                if (c != null) {
445                    String methodName = methodRef.getStringValue();
446                    Method[] methods = c.getMethods();
447                    List<Method> staticMethods = new ArrayList<Method>();
448                    int argCount = args.length - 2;
449                    for(Method m1 : methods) {
450                        if(Modifier.isStatic(m1.getModifiers())) {
451                            staticMethods.add(m1);
452                        }
453                    }
454                    if(staticMethods.size() > 0) {
455                        m = findMethod(staticMethods.toArray(new Method[staticMethods.size()]), methodName, args, 2);
456                    }
457                    if (m == null)
458                        error(new LispError("no such method"));
459                }
460            } else {
461              type_error(methodRef, Symbol.STRING);
462            }
463            Object[] methodArgs = new Object[args.length-2];
464            Class[] argTypes = m.getParameterTypes();
465            for (int i = 2; i < args.length; i++) {
466                LispObject arg = args[i];
467                if (arg.equals(NIL)) {
468                  methodArgs[i-2] = false;
469                } else if (arg.equals(T)) {
470                  methodArgs[i-2] = true;
471                } else {
472                  methodArgs[i-2] = arg.javaInstance(argTypes[i-2]);
473                }
474            }
475            m.setAccessible(true);
476            Object result = m.invoke(null, methodArgs);
477      return JavaObject.getInstance(result, translate, m.getReturnType());
478        }
479        catch (ControlTransfer c) {
480            throw c;
481        }
482        catch (Throwable t) { // ControlTransfer handled above
483            if (t instanceof InvocationTargetException)
484                t = t.getCause();
485            Symbol condition = getCondition(t.getClass());
486            if (condition == null)
487                error(new JavaException(t));
488            else
489                Symbol.SIGNAL.execute(
490                    condition,
491                    Keyword.CAUSE,
492                    JavaObject.getInstance(t),
493                    Keyword.FORMAT_CONTROL,
494                    new SimpleString(getMessage(t)));
495        }
496        // Not reached.
497        return NIL;
498    }
499
500    private static final Primitive JSTATIC = new pf_jstatic();
501    @DocString(name="jstatic", args="method class &rest args",
502    doc="Invokes the static method METHOD on class CLASS with ARGS.")
503    private static final class pf_jstatic extends Primitive
504    {
505        pf_jstatic() 
506        {
507            super("jstatic", PACKAGE_JAVA, true);
508        }
509
510        @Override
511        public LispObject execute(LispObject[] args)
512        {
513            return jstatic(this, args, true);
514        }
515    };
516
517    private static final Primitive JSTATIC_RAW = new pf_jstatic_raw();
518    @DocString(name="jstatic-raw", args="method class &rest args",
519    doc="Invokes the static method METHOD on class CLASS with ARGS. Does not "+
520        "attempt to coerce the arguments or result into a Lisp object.")
521    private static final class pf_jstatic_raw extends Primitive
522    {
523        pf_jstatic_raw() 
524        {
525            super("jstatic-raw", PACKAGE_JAVA, true);
526        }
527
528        @Override
529        public LispObject execute(LispObject[] args)
530        {
531            return jstatic(this, args, false);
532        }
533    };
534
535    private static final Primitive JNEW = new pf_jnew();
536    @DocString(name="jnew", args="constructor &rest args",
537    doc="Invokes the Java constructor CONSTRUCTOR with the arguments ARGS.")
538    private static final class pf_jnew extends Primitive
539    {
540        pf_jnew()
541        {
542            super("jnew", PACKAGE_JAVA, true);
543        }
544
545        @Override
546        public LispObject execute(LispObject[] args)
547        {
548            if (args.length < 1)
549                error(new WrongNumberOfArgumentsException(this, 1, -1));
550            LispObject classRef = args[0];
551            try {
552                Constructor constructor;
553    if(classRef instanceof AbstractString) {
554        constructor = findConstructor(javaClass(classRef), args);
555    } else {
556        Object object = JavaObject.getObject(classRef);
557        if(object instanceof Constructor) {
558      constructor = (Constructor) object;
559        } else if(object instanceof Class<?>) {
560      constructor = findConstructor((Class<?>) object, args);
561        } else {
562      return error(new LispError(classRef.princToString() + " is neither a Constructor nor a Class"));
563        }
564    }
565                Class[] argTypes = constructor.getParameterTypes();
566                Object[] initargs = new Object[args.length-1];
567                for (int i = 1; i < args.length; i++) {
568                    LispObject arg = args[i];
569                    if (arg.equals(NIL)) {
570                      initargs[i-1] = false ;
571                    } else if (arg.equals(T)) {
572                      initargs[i-1] = true;
573                    } else {
574                      initargs[i-1] = arg.javaInstance(argTypes[i-1]);
575                    }
576                }
577                return JavaObject.getInstance(constructor.newInstance(initargs));
578            }
579            catch (ControlTransfer c) {
580                throw c;
581            }
582            catch (Throwable t) { // ControlTransfer handled above
583                if (t instanceof InvocationTargetException)
584                    t = t.getCause();
585                Symbol condition = getCondition(t.getClass());
586                if (condition == null)
587                    error(new JavaException(t));
588                else
589                    Symbol.SIGNAL.execute(
590                        condition,
591                        Keyword.CAUSE,
592                        JavaObject.getInstance(t),
593                        Keyword.FORMAT_CONTROL,
594                        new SimpleString(getMessage(t)));
595            }
596            // Not reached.
597            return NIL;
598        }
599    };
600
601    private static final Primitive JNEW_ARRAY = new pf_jnew_array();
602    @DocString(name="jnew-array", args="element-type &rest dimensions",
603    doc="Creates a new Java array of type ELEMENT-TYPE, with the given" +
604        " DIMENSIONS.")
605    private static final class pf_jnew_array extends Primitive
606    {
607        pf_jnew_array()
608        {
609            super("jnew-array", PACKAGE_JAVA, true);
610        }
611
612        @Override
613        public LispObject execute(LispObject[] args)
614        {
615            if (args.length < 2)
616                error(new WrongNumberOfArgumentsException(this, 2, -1));
617            try {
618                Class c = javaClass(args[0]);
619                int[] dimensions = new int[args.length - 1];
620                for (int i = 1; i < args.length; i++)
621                    dimensions[i-1] = ((Integer)args[i].javaInstance()).intValue();
622                return JavaObject.getInstance(Array.newInstance(c, dimensions));
623            }
624            catch (Throwable t) { // no code -> no ControlTransfer
625                error(new JavaException(t));
626            }
627            // Not reached.
628            return NIL;
629        }
630    };
631
632    static final LispObject jarray_ref(Primitive fun, LispObject[] args, boolean translate)
633
634    {
635        if (args.length < 2)
636            error(new WrongNumberOfArgumentsException(fun, 2, -1));
637        try {
638            Object a = args[0].javaInstance();
639            for (int i = 1; i<args.length - 1; i++)
640                a = Array.get(a, ((Integer)args[i].javaInstance()).intValue());
641            return JavaObject.getInstance(Array.get(a,
642                    ((Integer)args[args.length - 1].javaInstance()).intValue()), translate);
643        }
644        catch (Throwable t) { // no code -> no ControlTransfer
645            Symbol condition = getCondition(t.getClass());
646            if (condition == null)
647                error(new JavaException(t));
648            else
649                Symbol.SIGNAL.execute(
650                    condition,
651                    Keyword.CAUSE,
652                    JavaObject.getInstance(t),
653                    Keyword.FORMAT_CONTROL,
654                    new SimpleString(getMessage(t)));
655        }
656        // Not reached.
657        return NIL;
658    }
659
660    private static final Primitive JARRAY_REF = new pf_jarray_ref();
661    @DocString(name="jarray-ref", args="java-array &rest indices",
662    doc="Dereferences the Java array JAVA-ARRAY using the given INDICIES, " +
663        "coercing the result into a Lisp object, if possible.")
664    private static final class pf_jarray_ref extends Primitive
665    {
666        pf_jarray_ref()
667        {
668            super("jarray-ref", PACKAGE_JAVA, true);
669        }
670
671        @Override
672        public LispObject execute(LispObject[] args)
673        {
674            return jarray_ref(this, args, true);
675        }
676    };
677
678    private static final Primitive JARRAY_REF_RAW = new pf_jarray_ref_raw();
679    @DocString(name="jarray-ref-raw", args="java-array &rest indices",
680    doc="Dereference the Java array JAVA-ARRAY using the given INDICIES. " +
681        "Does not attempt to coerce the result into a Lisp object.")
682    private static final class pf_jarray_ref_raw extends Primitive
683    {
684        pf_jarray_ref_raw() 
685        {
686            super("jarray-ref-raw", PACKAGE_JAVA, true);
687        }
688
689        @Override
690        public LispObject execute(LispObject[] args)
691        {
692            return jarray_ref(this, args, false);
693        }
694    };
695
696    private static final Primitive JARRAY_SET = new pf_jarray_set();
697    @DocString(name="jarray-set", args="java-array new-value &rest indices",
698    doc="Stores NEW-VALUE at the given index in JAVA-ARRAY.")
699    private static final class pf_jarray_set extends Primitive
700    {
701        pf_jarray_set()
702        {
703            super("jarray-set", PACKAGE_JAVA, true);
704        }
705
706        @Override
707        public LispObject execute(LispObject[] args)
708        {
709            if (args.length < 3)
710                error(new WrongNumberOfArgumentsException(this, 3, -1));
711            try {
712                Object a = args[0].javaInstance();
713                LispObject v = args[1];
714                for (int i = 2; i<args.length - 1; i++)
715                    a = Array.get(a, ((Integer)args[i].javaInstance()).intValue());
716                Object value = v.javaInstance();
717                int index = ((Integer)args[args.length - 1].javaInstance()).intValue();
718                if (value instanceof java.lang.Number
719                    && a.getClass().getComponentType().equals(Byte.TYPE)) {
720                    Array.setByte(a, index, ((java.lang.Number)value).byteValue());
721                } else {
722                    Array.set(a, index, value);
723                }
724                return v;
725            }
726            catch (Throwable t) { // no code -> no ControlTransfer
727                Symbol condition = getCondition(t.getClass());
728                if (condition == null)
729                    error(new JavaException(t));
730                else
731                    Symbol.SIGNAL.execute(
732                        condition,
733                        Keyword.CAUSE,
734                        JavaObject.getInstance(t),
735                        Keyword.FORMAT_CONTROL,
736                        new SimpleString(getMessage(t)));
737            }
738            // Not reached.
739            return NIL;
740        }
741    };
742
743    /**  Calls makeLispObject() to convert the result to an appropriate Lisp type. */
744    private static final Primitive JCALL = new pf_jcall();
745    @DocString(name="jcall", args="method-ref instance &rest args",
746    doc="Invokes the Java method METHOD-REF on INSTANCE with arguments ARGS," +
747        " coercing the result into a Lisp object, if possible.")
748    private static final class pf_jcall extends Primitive
749    {
750        pf_jcall()
751        {
752            super(Symbol.JCALL);
753        }
754
755        @Override
756        public LispObject execute(LispObject[] args)
757        {
758            return jcall(this, args, true);
759        }
760    };
761
762    /**
763     * Does no type conversion. The result of the call is simply wrapped in a
764     *   JavaObject.
765     */
766    private static final Primitive JCALL_RAW = new pf_jcall_raw();
767    @DocString(name="jcall-raw", args="method-ref instance &rest args",
768    doc="Invokes the Java method METHOD-REF on INSTANCE with arguments ARGS." +
769        " Does not attempt to coerce the result into a Lisp object.")
770    private static final class pf_jcall_raw extends Primitive
771    {
772        pf_jcall_raw()
773        {
774            super(Symbol.JCALL_RAW);
775        }
776
777        @Override
778        public LispObject execute(LispObject[] args)
779        {
780            return jcall(this, args, false);
781        }
782    };
783
784    private static final Primitive JRESOLVE_METHOD = new pf_jresolve_method();
785    @DocString(name="jresolve-method", args="method-name instance &rest args",
786    doc="Finds the most specific Java method METHOD-NAME on INSTANCE " +
787        "applicable to arguments ARGS. Returns NIL if no suitable method is " +
788        "found. The algorithm used for resolution is the same used by JCALL " +
789        "when it is called with a string as the first parameter (METHOD-REF).")
790    private static final class pf_jresolve_method extends Primitive {
791        pf_jresolve_method() {
792            super(Symbol.JRESOLVE_METHOD);
793        }
794
795        @Override
796        public LispObject execute(LispObject[] args) {
797            if (args.length < 2) {
798                error(new WrongNumberOfArgumentsException(this, 2, -1));
799            }
800            final LispObject methodArg = args[0];
801            final LispObject instanceArg = args[1];
802            final Object instance;
803            Class<?> intendedClass = null;
804            if (instanceArg instanceof AbstractString) {
805                instance = instanceArg.getStringValue();
806            } else if (instanceArg instanceof JavaObject) {
807                JavaObject jobj = ((JavaObject)instanceArg);
808                instance = jobj.getObject();
809                intendedClass = jobj.getIntendedClass();
810            } else {
811                instance = instanceArg.javaInstance();
812            }
813            if(instance == null) {
814                return program_error("JRESOLVE-METHOD: instance must not be null.");
815            }
816            String methodName = methodArg.getStringValue();
817            Object[] methodArgs = translateMethodArguments(args, 2);
818            Method method = findMethod(instance, intendedClass, methodName, methodArgs);
819            if (method != null) {
820                return JavaObject.getInstance(method);
821            } else if (instanceArg instanceof JavaObject) {
822                // Sometimes JavaObject.intendedClass has the default
823                // value java.lang.Object, so we try again to resolve
824                // the method using a dynamically requested value for
825                // java.lang.Class.
826                intendedClass = ((JavaObject)instanceArg).getObject().getClass();
827                method = findMethod(instance, intendedClass, methodName, methodArgs);
828            } else {
829                return NIL;
830            }
831            if (method != null) {
832                return JavaObject.getInstance(method);
833            } else {
834                return NIL;
835            }
836        }
837    };
838
839    static LispObject jcall(Primitive fun, LispObject[] args, boolean translate)
840
841    {
842        if (args.length < 2)
843            error(new WrongNumberOfArgumentsException(fun, 2, -1));
844        try {
845            final LispObject methodArg = args[0];
846            final LispObject instanceArg = args[1];
847            final Object instance;
848            Method method;
849            Object[] methodArgs;
850            Class<?> intendedClass = null;
851            if (instanceArg instanceof AbstractString) {
852                instance = instanceArg.getStringValue();
853            } else if (instanceArg instanceof JavaObject) {
854                JavaObject jobj = ((JavaObject)instanceArg);
855                instance = jobj.getObject();
856                intendedClass = jobj.getIntendedClass();
857            } else {
858                instance = instanceArg.javaInstance();
859            }
860            if(instance == null) {
861                throw new NullPointerException(); //Handled below
862            }
863            if (methodArg instanceof AbstractString) {
864                String methodName = methodArg.getStringValue();
865                methodArgs = translateMethodArguments(args, 2);
866                method = findMethod(instance, intendedClass, methodName, methodArgs);
867                if (method == null) {
868                    if (intendedClass == null) {
869                        String msg = MessageFormat.format("No instance method named {0} found for type {1}", methodName, instance.getClass().getName());
870                        throw new NoSuchMethodException(msg);
871                    }
872                    String classes = intendedClass.getName();
873                    Class<?> actualClass = instance.getClass();
874                    if(actualClass != intendedClass) {
875                        classes += " or " + actualClass.getName();
876                    }
877                    throw new NoSuchMethodException("No applicable method named " + methodName + " found in " + classes);
878                }
879            } else
880                method = (Method) JavaObject.getObject(methodArg);
881            Class<?>[] argTypes = (Class<?>[])method.getParameterTypes();
882      if(argTypes.length != args.length - 2) {
883    return error(new WrongNumberOfArgumentsException("Wrong number of arguments for " + method + ": expected " + argTypes.length + ", got " + (args.length - 2)));
884      }
885            methodArgs = new Object[argTypes.length];
886            for (int i = 2; i < args.length; i++) {
887              LispObject arg = args[i];
888              if (arg.equals(NIL)) {
889                methodArgs[i-2] = false;
890              } else if (arg.equals(T)) {
891                methodArgs[i-2] = true;
892              } else {
893                methodArgs[i-2] = arg.javaInstance(argTypes[i-2]);
894              }
895            }
896            if (!method.isAccessible()) {
897                 // Possible for static member classes: see #229
898                 if (Modifier.isPublic(method.getModifiers())) { 
899                    method.setAccessible(true);
900                 }
901      }
902            return JavaObject.getInstance(method.invoke(instance, methodArgs),
903                                          translate,
904                                          method.getReturnType());
905        }
906        catch (ControlTransfer t) {
907            throw t;
908        }
909        catch (Throwable t) { // ControlTransfer handled above
910            if (t instanceof InvocationTargetException)
911                t = t.getCause();
912            Symbol condition = getCondition(t.getClass());
913            if (condition == null)
914                error(new JavaException(t));
915            else
916                Symbol.SIGNAL.execute(
917                    condition,
918                    Keyword.CAUSE,
919                    JavaObject.getInstance(t),
920                    Keyword.FORMAT_CONTROL,
921                    new SimpleString(getMessage(t)));
922        }
923        // Not reached.
924        return null;
925    }
926
927    private static Object[] translateMethodArguments(LispObject[] args) {
928  return translateMethodArguments(args, 0);
929    }
930
931    private static Object[] translateMethodArguments(LispObject[] args, int offs) {
932  int argCount = args.length - offs;
933        Object[] javaArgs = new Object[argCount];
934        for (int i = 0; i < argCount; ++i) {
935          Object x = args[i + offs];
936          if (x.equals(NIL)) {
937            javaArgs[i] = false;
938          } else if (x.equals(T)) {
939            javaArgs[i] = true;
940          } else {
941            javaArgs[i] = ((LispObject) x).javaInstance();
942          }
943        }
944  return javaArgs;
945    }
946
947    private static Method findMethod(Method[] methods, String methodName, Object[] javaArgs) {
948        int argCount = javaArgs.length;
949        Method result = null;
950        for (int i = methods.length; i-- > 0;) {
951            Method method = methods[i];
952            if (!method.getName().equals(methodName)) {
953                continue;
954            }
955            if (method.getParameterTypes().length != argCount) {
956                continue;
957            }
958            Class<?>[] methodTypes = (Class<?>[]) method.getParameterTypes();
959            if (!isApplicableMethod(methodTypes, javaArgs)) {
960                continue;
961            }
962            if (result == null || isMoreSpecialized(methodTypes, result.getParameterTypes())) {
963                result = method;
964            }
965        }
966        return result;
967    }
968
969    private static Method findMethod(Object instance, Class<?> intendedClass, String methodName, Object[] methodArgs) {
970        if(intendedClass == null) {
971            intendedClass = instance.getClass();
972        }
973        Method method = findMethod(intendedClass, methodName, methodArgs);
974        Class actualClass = null;
975        if(method == null) {
976            actualClass = instance.getClass();
977            if(intendedClass != actualClass) { 
978                method = findMethod(actualClass, methodName, methodArgs);
979    if (method != null) {
980       if (isMethodCallableOnInstance(actualClass, method)) {
981          return method;
982       }
983    }
984            }
985        }
986        return method;
987    }
988   
989    private static boolean isMethodCallableOnInstance(Class instance, Method method) {
990       if (Modifier.isPublic(method.getModifiers())) {
991    return true;
992       }
993       if (instance.isMemberClass()) {
994    return isMethodCallableOnInstance(instance.getEnclosingClass(), method);
995       }
996       return false;
997    }
998
999    private static Method findMethod(Class<?> c, String methodName, Object[] javaArgs) {
1000        Method[] methods = c.getMethods();
1001        return findMethod(methods, methodName, javaArgs);
1002    }
1003
1004    private static Method findMethod(Class<?> c, String methodName, LispObject[] args, int offset) {
1005        Object[] javaArgs = translateMethodArguments(args, offset);
1006        return findMethod(c, methodName, javaArgs);
1007    }
1008
1009    private static Method findMethod(Method[] methods, String methodName, LispObject[] args, int offset) {
1010        Object[] javaArgs = translateMethodArguments(args, offset);
1011        return findMethod(methods, methodName, javaArgs);
1012    }
1013
1014    static Constructor findConstructor(Class<?> c, LispObject[] args) throws NoSuchMethodException {
1015        int argCount = args.length - 1;
1016        Object[] javaArgs = translateMethodArguments(args, 1);
1017        Constructor[] ctors = c.getConstructors();
1018        Constructor result = null;
1019        for (int i = ctors.length; i-- > 0;) {
1020            Constructor ctor = ctors[i];
1021            if (ctor.getParameterTypes().length != argCount) {
1022                continue;
1023            }
1024            Class<?>[] methodTypes = (Class<?>[]) ctor.getParameterTypes();
1025            if (!isApplicableMethod(methodTypes, javaArgs)) {
1026                continue;
1027            }
1028            if (result == null || isMoreSpecialized(methodTypes, result.getParameterTypes())) {
1029                result = ctor;
1030            }
1031        }
1032        if (result == null) {
1033      StringBuilder sb = new StringBuilder(c.getSimpleName());
1034      sb.append('(');
1035      boolean first = true;
1036      for(Object o : javaArgs) {
1037    if(first) {
1038        first = false;
1039    } else {
1040        sb.append(", ");
1041    }
1042    if(o != null) {
1043        sb.append(o.getClass().getName());
1044    } else {
1045        sb.append("<null>");
1046    }
1047      }
1048      sb.append(')');
1049            throw new NoSuchMethodException(sb.toString());
1050        }
1051        return result;
1052    }
1053
1054    private static boolean isAssignable(Class<?> from, Class<?> to) {
1055        from = maybeBoxClass(from);
1056        to = maybeBoxClass(to);
1057        if (to.isAssignableFrom(from)) {
1058            return true;
1059        }
1060        if (Byte.class.equals(from)) {
1061            return Short.class.equals(to) || Integer.class.equals(to) || Long.class.equals(to) || Float.class.equals(to) || Double.class.equals(to);
1062        } else if (Short.class.equals(from) || Character.class.equals(from)) {
1063            return Integer.class.equals(to) || Long.class.equals(to) || Float.class.equals(to) || Double.class.equals(to);
1064        } else if (Integer.class.equals(from)) {
1065            return Long.class.equals(to) || Float.class.equals(to) || Double.class.equals(to);
1066        } else if (Long.class.equals(from)) {
1067            return Float.class.equals(to) || Double.class.equals(to);
1068        } else if (Float.class.equals(from)) {
1069            return Double.class.equals(to);
1070        }
1071        return false;
1072    }
1073
1074    private static boolean isApplicableMethod(Class<?>[] methodTypes,
1075            Object[] args) {
1076        for (int i = 0; i < methodTypes.length; ++i) {
1077            Class<?> methodType = methodTypes[i];
1078            Object arg = args[i];
1079            if (arg == null) {
1080                return !methodType.isPrimitive();
1081            } else if (!isAssignable(arg.getClass(), methodType)) {
1082                return false;
1083            }
1084        }
1085        return true;
1086    }
1087
1088    private static boolean isMoreSpecialized(Class<?>[] xtypes, Class<?>[] ytypes) {
1089        for (int i = 0; i < xtypes.length; ++i) {
1090            Class<?> xtype = maybeBoxClass(xtypes[i]);
1091            Class<?> ytype = maybeBoxClass(ytypes[i]);
1092            if (xtype.equals(ytype)) {
1093                continue;
1094            }
1095            if (isAssignable(xtype, ytype)) {
1096                return true;
1097            }
1098        }
1099        return false;
1100    }
1101
1102    public static Class<?> maybeBoxClass(Class<?> clazz) {
1103  if(clazz.isPrimitive()) {
1104      return getBoxedClass(clazz);
1105  } else {
1106      return clazz;
1107  }
1108    }
1109   
1110    private static Class<?> getBoxedClass(Class<?> clazz) {
1111        if (clazz.equals(int.class)) {
1112            return Integer.class;
1113        } else if (clazz.equals(boolean.class)) {
1114            return Boolean.class;
1115        } else if (clazz.equals(byte.class)) {
1116            return Byte.class;
1117        } else if (clazz.equals(char.class)) {
1118            return Character.class;
1119        } else if (clazz.equals(long.class)) {
1120            return Long.class;
1121        } else if (clazz.equals(float.class)) {
1122            return Float.class;
1123        } else if (clazz.equals(double.class)) {
1124            return Double.class;
1125        } else if (clazz.equals(short.class)) {
1126            return Short.class;
1127        } else { // if (methodType.equals(void.class))
1128            return Void.class;
1129        }
1130    }
1131
1132    // DEPRECATED Remove MAKE-IMMEDIATE-OBJECT in abcl-0.29
1133    private static final Primitive MAKE_IMMEDIATE_OBJECT = new pf_make_immediate_object();
1134    @DocString(name="make-immediate-object", args="object &optional type",
1135    doc="Attempts to coerce a given Lisp object into a java-object of the\n"
1136      + "given type.  If type is not provided, works as jobject-lisp-value.\n"
1137      + "Currently, type may be :BOOLEAN, treating the object as a truth value,\n"
1138      + "or :REF, which returns Java null if NIL is provided.\n"
1139      + "\n"
1140      + "Deprecated.  Please use JAVA:+NULL+, JAVA:+TRUE+, and JAVA:+FALSE+ for\n"
1141      + "constructing wrapped primitive types, JAVA:JOBJECT-LISP-VALUE for converting a\n"
1142      + "JAVA:JAVA-OBJECT to a Lisp value, or JAVA:JNULL-REF-P to distinguish a wrapped\n"
1143      + "null JAVA-OBJECT from NIL.")
1144    private static final class pf_make_immediate_object extends Primitive
1145    {
1146        pf_make_immediate_object()
1147        {
1148            super("make-immediate-object", PACKAGE_JAVA, true);
1149        }
1150
1151        @Override
1152        public LispObject execute(LispObject[] args)
1153        {
1154            Symbol.WARN.getSymbolFunction()
1155                .execute(new SimpleString("JAVA:MAKE-IMMEDIATE-OBJECT is deprecated."));
1156            if (args.length < 1)
1157                error(new WrongNumberOfArgumentsException(this, 1, -1));
1158            LispObject object = args[0];
1159            if (args.length > 1) {
1160                LispObject type = args[1];
1161                if (type == Keyword.BOOLEAN) {
1162                    if (object == NIL)
1163                        return JavaObject.getInstance(Boolean.FALSE);
1164                    else
1165                        return JavaObject.getInstance(Boolean.TRUE);
1166                }
1167                if (type == Keyword.REF) {
1168                    if (object == NIL)
1169                        return JavaObject.getInstance(null);
1170                    else
1171                        error(new LispError("MAKE-IMMEDIATE-OBJECT: not implemented"));
1172                }
1173                // other special cases come here
1174            }
1175            return JavaObject.getInstance(object.javaInstance());
1176        }
1177    };
1178
1179    private static final Primitive JNULL_REF_P = new pf_jnull_ref_p();
1180    @DocString(name="jnull-ref-p", args="object",
1181    doc="Returns a non-NIL value when the JAVA-OBJECT `object` is `null`,\n"
1182            + "or signals a TYPE-ERROR condition if the object isn't of\n"
1183            + "the right type.")
1184    private static final class pf_jnull_ref_p extends Primitive
1185    {
1186        pf_jnull_ref_p()
1187        {
1188            super("jnull-ref-p", PACKAGE_JAVA, true);
1189        }
1190
1191        @Override
1192        public LispObject execute(LispObject ref)
1193        {
1194            if (ref instanceof JavaObject)
1195            {
1196                JavaObject jref = (JavaObject)ref;
1197                return (jref.javaInstance() == null) ? T : NIL;
1198            } else
1199                return Lisp.type_error(ref, Symbol.JAVA_OBJECT);
1200        }
1201    };
1202
1203
1204    private static final Primitive JAVA_OBJECT_P = new pf_java_object_p();
1205    @DocString(name="java-object-p", args="object",
1206    doc="Returns T if OBJECT is a JAVA-OBJECT.")
1207    private static final class pf_java_object_p extends Primitive
1208    {
1209        pf_java_object_p() 
1210        {
1211            super("java-object-p", PACKAGE_JAVA, true);
1212        }
1213
1214        @Override
1215        public LispObject execute(LispObject arg)
1216        {
1217            return (arg instanceof JavaObject) ? T : NIL;
1218        }
1219    };
1220
1221    private static final Primitive JOBJECT_LISP_VALUE = new pf_jobject_lisp_value();
1222    @DocString(name="jobject-lisp-value", args="java-object",
1223    doc="Attempts to coerce JAVA-OBJECT into a Lisp object.")
1224    private static final class pf_jobject_lisp_value extends Primitive
1225    {
1226        pf_jobject_lisp_value()
1227        {
1228            super("jobject-lisp-value", PACKAGE_JAVA, true, "java-object");
1229        }
1230
1231        @Override
1232        public LispObject execute(LispObject arg)
1233        {
1234            return JavaObject.getInstance(arg.javaInstance(), true);
1235        }
1236    };
1237
1238    private static final Primitive JCOERCE = new pf_jcoerce();
1239    @DocString(name="jcoerce", args="object intended-class",
1240    doc="Attempts to coerce OBJECT into a JavaObject of class INTENDED-CLASS." +
1241        "  Raises a TYPE-ERROR if no conversion is possible.")
1242    private static final class pf_jcoerce extends Primitive
1243    {
1244        pf_jcoerce()
1245        {
1246            super("jcoerce", PACKAGE_JAVA, true);
1247        }
1248
1249        @Override
1250        public LispObject execute(LispObject javaObject, LispObject intendedClass)
1251        {
1252      Object o = javaObject.javaInstance();
1253      Class<?> c = javaClass(intendedClass);
1254      try {
1255    return JavaObject.getInstance(o, c);
1256      } catch(ClassCastException e) {
1257          return type_error(javaObject, new SimpleString(c.getName()));
1258      }
1259        }
1260    };
1261
1262    private static final Primitive JRUN_EXCEPTION_PROTECTED = new pf_jrun_exception_protected();
1263    @DocString(name="jrun-exception-protected", args="closure",
1264    doc="Invokes the function CLOSURE and returns the result.  "+
1265        "Signals an error if stack or heap exhaustion occurs.")
1266    private static final class pf_jrun_exception_protected extends Primitive
1267    {
1268        pf_jrun_exception_protected()
1269        {
1270            super("jrun-exception-protected", PACKAGE_JAVA, true);
1271        }
1272
1273        @Override
1274        public LispObject execute(LispObject closure) {
1275            Function fun = checkFunction(closure);
1276
1277            try {
1278                return LispThread.currentThread().execute(closure);
1279            }
1280            catch (OutOfMemoryError oom) {
1281                return error(new StorageCondition("Out of memory " + oom.getMessage()));
1282            }
1283            catch (StackOverflowError oos) {
1284                oos.printStackTrace();
1285                return error(new StorageCondition("Stack overflow."));
1286            }
1287        }
1288    };
1289
1290    private static Class classForName(String className) {
1291  return classForName(className, JavaClassLoader.getPersistentInstance());
1292    }
1293
1294    private static Class classForName(String className, ClassLoader classLoader) {
1295        try {
1296            return Class.forName(className, true, classLoader);
1297        }
1298        catch (ClassNotFoundException e) {
1299      error(new LispError("Class not found: " + className));
1300      // Not reached.
1301      return null;
1302        }
1303    }
1304
1305    private static Class javaClass(LispObject obj) {
1306  return javaClass(obj, JavaClassLoader.getCurrentClassLoader());
1307    }
1308
1309    // Supports Java primitive types too.
1310    static Class javaClass(LispObject obj, ClassLoader classLoader)
1311    {
1312        if (obj instanceof AbstractString || obj instanceof Symbol) {
1313            String s = javaString(obj);
1314            if (s.equals("boolean"))
1315                return Boolean.TYPE;
1316            if (s.equals("byte"))
1317                return Byte.TYPE;
1318            if (s.equals("char"))
1319                return Character.TYPE;
1320            if (s.equals("short"))
1321                return Short.TYPE;
1322            if (s.equals("int"))
1323                return Integer.TYPE;
1324            if (s.equals("long"))
1325                return Long.TYPE;
1326            if (s.equals("float"))
1327                return Float.TYPE;
1328            if (s.equals("double"))
1329                return Double.TYPE;
1330            // Not a primitive Java type.
1331            Class c;
1332      c = classForName(s, classLoader);
1333            if (c == null)
1334                error(new LispError(s + " does not designate a Java class."));
1335
1336            return c;
1337        }
1338        // It's not a string, so it must be a JavaObject.
1339        final JavaObject javaObject;
1340        if (obj instanceof JavaObject) {
1341            javaObject = (JavaObject) obj;
1342        }
1343        else {
1344            type_error(obj, list(Symbol.OR, Symbol.STRING,
1345                                       Symbol.JAVA_OBJECT));
1346            // Not reached.
1347            return null;
1348        }
1349        final Object javaObjectgetObject = javaObject.getObject();
1350        if (javaObjectgetObject instanceof Class) {
1351            return (Class) javaObjectgetObject;
1352        }
1353            error(new LispError(obj.princToString() + " does not designate a Java class."));
1354            return null;
1355    }
1356
1357    static final String getMessage(Throwable t)
1358    {
1359        String message = t.getMessage();
1360        if (message == null || message.length() == 0)
1361            message = t.getClass().getName();
1362        return message;
1363    }
1364}
Note: See TracBrowser for help on using the repository browser.