[armedbear-cvs] r12081 - trunk/abcl/src/org/armedbear/lisp
Alessio Stalla
astalla at common-lisp.net
Fri Jul 31 23:48:55 UTC 2009
Author: astalla
Date: Fri Jul 31 19:48:53 2009
New Revision: 12081
Log:
#58 inspection of Java objects
Modified:
trunk/abcl/src/org/armedbear/lisp/JavaObject.java
Modified: trunk/abcl/src/org/armedbear/lisp/JavaObject.java
==============================================================================
--- trunk/abcl/src/org/armedbear/lisp/JavaObject.java (original)
+++ trunk/abcl/src/org/armedbear/lisp/JavaObject.java Fri Jul 31 19:48:53 2009
@@ -33,8 +33,12 @@
package org.armedbear.lisp;
+import java.lang.reflect.*;
+
import java.math.BigInteger;
+import java.util.*;
+
public final class JavaObject extends LispObject
{
private final Object obj;
@@ -154,7 +158,7 @@
Object[] array = (Object[]) obj;
SimpleVector v = new SimpleVector(array.length);
for (int i = array.length; i-- > 0;)
- v.aset(i, JavaObject.getInstance(array[i]));
+ v.aset(i, JavaObject.getInstance(array[i], translated));
return v;
}
// TODO
@@ -171,9 +175,13 @@
}
@Override
- public Object javaInstance(Class c)
- {
- return javaInstance();
+ public Object javaInstance(Class c) throws ConditionThrowable {
+ if(obj != null && !c.isAssignableFrom(obj.getClass())) {
+ return error(new LispError("The value " + obj +
+ " is not of class " + c.getName()));
+ } else {
+ return javaInstance();
+ }
}
/** Returns the encapsulated Java object for
@@ -222,11 +230,194 @@
{
if (obj instanceof ConditionThrowable)
return obj.toString();
- final FastStringBuffer sb =
- new FastStringBuffer(Symbol.JAVA_OBJECT.writeToString());
- sb.append(' ');
- sb.append(obj == null ? "null" : obj.getClass().getName());
- return unreadableString(sb.toString());
+ final String s;
+ if(obj != null) {
+ Class<?> c = obj.getClass();
+ FastStringBuffer sb
+ = new FastStringBuffer(c.isArray() ? "jarray" : c.getName());
+ sb.append(' ');
+ String ts = obj.toString();
+ if(ts.length() > 32) { //random value, should be chosen sensibly
+ sb.append(ts.substring(0, 32) + "...");
+ } else {
+ sb.append(ts);
+ }
+ s = sb.toString();
+ } else {
+ s = "null";
+ }
+ return unreadableString(s);
+ }
+
+ @Override
+ public LispObject getDescription() throws ConditionThrowable {
+ return new SimpleString(describeJavaObject(this));
+ }
+
+ @Override
+ public LispObject getParts() throws ConditionThrowable {
+ if(obj != null) {
+ LispObject parts = NIL;
+ if(obj.getClass().isArray()) {
+ SimpleString empty = new SimpleString("");
+ int length = Array.getLength(obj);
+ for(int i = 0; i < length; i++) {
+ parts = parts.push
+ (new Cons(empty, new JavaObject(Array.get(obj, i))));
+ }
+ parts = parts.nreverse();
+ } else {
+ parts = parts.push(new Cons("Java class",
+ new JavaObject(obj.getClass())));
+ parts = Symbol.NCONC.execute(parts, getInspectedFields());
+ }
+ return parts;
+ } else {
+ return NIL;
+ }
+ }
+
+ private LispObject getInspectedFields()
+ throws ConditionThrowable {
+ final LispObject[] acc = new LispObject[] { NIL };
+ doClassHierarchy(obj.getClass(), new Function() {
+ @Override
+ public LispObject execute(LispObject arg)
+ throws ConditionThrowable {
+ Class<?> c = (Class) arg.javaInstance(Class.class);
+ for(Field f : c.getDeclaredFields()) {
+ LispObject value = NIL;
+ try {
+ if(!f.isAccessible()) {
+ f.setAccessible(true);
+ }
+ value = JavaObject.getInstance(f.get(obj));
+ } catch(Exception e) {}
+ acc[0] = acc[0].push(new Cons(f.getName(), value));
+ }
+ return acc[0];
+ }
+ });
+ return acc[0].nreverse();
+ }
+
+ /**
+ * Executes a function repeatedly over the minimal subtree of the
+ * Java class hierarchy which contains every class in <classes>.
+ */
+ private static void doClassHierarchy(Collection<Class<?>> classes,
+ LispObject callback,
+ Set<Class<?>> visited)
+ throws ConditionThrowable {
+ Collection<Class<?>> newClasses = new LinkedList<Class<?>>();
+ for(Class<?> clss : classes) {
+ if(clss == null) {
+ continue;
+ }
+ if(!visited.contains(clss)) {
+ callback.execute(JavaObject.getInstance(clss, true));
+ visited.add(clss);
+ }
+ if(!visited.contains(clss.getSuperclass())) {
+ newClasses.add(clss.getSuperclass());
+ }
+ for(Class<?> iface : clss.getInterfaces()) {
+ if (!visited.contains(iface)) {
+ newClasses.add(iface);
+ }
+ }
+ }
+ if(!newClasses.isEmpty()) {
+ doClassHierarchy(newClasses, callback, visited);
+ }
+ }
+
+ /**
+ * Executes a function recursively over <clss> and its superclasses and
+ * interfaces.
+ */
+ public static void doClassHierarchy(Class<?> clss, LispObject callback)
+ throws ConditionThrowable {
+ if (clss != null) {
+ Set<Class<?>> visited = new HashSet<Class<?>>();
+ Collection<Class<?>> classes = new ArrayList<Class<?>>(1);
+ classes.add(clss);
+ doClassHierarchy(classes, callback, visited);
+ }
+ }
+
+ public static LispObject mapcarClassHierarchy(Class<?> clss,
+ final LispObject fn)
+ throws ConditionThrowable {
+ final LispObject[] acc = new LispObject[] { NIL };
+ doClassHierarchy(clss, new Function() {
+ @Override
+ public LispObject execute(LispObject arg)
+ throws ConditionThrowable {
+ acc[0] = acc[0].push(fn.execute(arg));
+ return acc[0];
+ }
+ });
+ return acc[0].nreverse();
+ }
+
+ public static String describeJavaObject(final JavaObject javaObject)
+ throws ConditionThrowable {
+ final Object obj = javaObject.getObject();
+ final FastStringBuffer sb =
+ new FastStringBuffer(javaObject.writeToString());
+ sb.append(" is an object of type ");
+ sb.append(Symbol.JAVA_OBJECT.writeToString());
+ sb.append(".");
+ sb.append(System.getProperty("line.separator"));
+ sb.append("The wrapped Java object is ");
+ if (obj == null) {
+ sb.append("null.");
+ } else {
+ sb.append("an ");
+ final Class c = obj.getClass();
+ String className = c.getName();
+ if (c.isArray()) {
+ sb.append("array of ");
+ if (className.startsWith("[L") && className.endsWith(";")) {
+ className = className.substring(1, className.length() - 1);
+ sb.append(className);
+ sb.append(" objects");
+ } else if (className.startsWith("[") && className.length() > 1) {
+ char descriptor = className.charAt(1);
+ final String type;
+ switch (descriptor) {
+ case 'B': type = "bytes"; break;
+ case 'C': type = "chars"; break;
+ case 'D': type = "doubles"; break;
+ case 'F': type = "floats"; break;
+ case 'I': type = "ints"; break;
+ case 'J': type = "longs"; break;
+ case 'S': type = "shorts"; break;
+ case 'Z': type = "booleans"; break;
+ default:
+ type = "unknown type";
+ }
+ sb.append(type);
+ }
+ sb.append(" with ");
+ final int length = java.lang.reflect.Array.getLength(obj);
+ sb.append(length);
+ sb.append(" element");
+ if (length != 1)
+ sb.append('s');
+ sb.append('.');
+ } else {
+ sb.append("instance of ");
+ sb.append(className);
+ sb.append(':');
+ sb.append(System.getProperty("line.separator"));
+ sb.append(" \"");
+ sb.append(obj.toString());
+ sb.append('"');
+ }
+ }
+ return sb.toString();
}
// ### describe-java-object
@@ -241,61 +432,7 @@
return type_error(first, Symbol.JAVA_OBJECT);
final Stream stream = checkStream(second);
final JavaObject javaObject = (JavaObject) first;
- final Object obj = javaObject.getObject();
- final FastStringBuffer sb =
- new FastStringBuffer(javaObject.writeToString());
- sb.append(" is an object of type ");
- sb.append(Symbol.JAVA_OBJECT.writeToString());
- sb.append(".");
- sb.append(System.getProperty("line.separator"));
- sb.append("The wrapped Java object is ");
- if (obj == null) {
- sb.append("null.");
- } else {
- sb.append("an ");
- final Class c = obj.getClass();
- String className = c.getName();
- if (c.isArray()) {
- sb.append("array of ");
- if (className.startsWith("[L") && className.endsWith(";")) {
- className = className.substring(1, className.length() - 1);
- sb.append(className);
- sb.append(" objects");
- } else if (className.startsWith("[") && className.length() > 1) {
- char descriptor = className.charAt(1);
- final String type;
- switch (descriptor) {
- case 'B': type = "bytes"; break;
- case 'C': type = "chars"; break;
- case 'D': type = "doubles"; break;
- case 'F': type = "floats"; break;
- case 'I': type = "ints"; break;
- case 'J': type = "longs"; break;
- case 'S': type = "shorts"; break;
- case 'Z': type = "booleans"; break;
- default:
- type = "unknown type";
- }
- sb.append(type);
- }
- sb.append(" with ");
- final int length = java.lang.reflect.Array.getLength(obj);
- sb.append(length);
- sb.append(" element");
- if (length != 1)
- sb.append('s');
- sb.append('.');
- } else {
- sb.append("instance of ");
- sb.append(className);
- sb.append(':');
- sb.append(System.getProperty("line.separator"));
- sb.append(" \"");
- sb.append(obj.toString());
- sb.append('"');
- }
- }
- stream._writeString(sb.toString());
+ stream._writeString(describeJavaObject(javaObject));
return LispThread.currentThread().nothing();
}
};
More information about the armedbear-cvs
mailing list