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

Last change on this file was 13461, checked in by ehuelsmann, 14 years ago

Print expected minimum and maximum argument list lengths in
WrongNumberOfArguments? program errors.

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