[armedbear-cvs] r12345 - trunk/abcl/src/org/armedbear/lisp

Alessio Stalla astalla at common-lisp.net
Fri Jan 8 19:55:08 UTC 2010


Author: astalla
Date: Fri Jan  8 14:55:05 2010
New Revision: 12345

Log:
Use of the "intended class" of an object before the actual class to access it via reflection.


Modified:
   trunk/abcl/src/org/armedbear/lisp/Java.java
   trunk/abcl/src/org/armedbear/lisp/JavaObject.java

Modified: trunk/abcl/src/org/armedbear/lisp/Java.java
==============================================================================
--- trunk/abcl/src/org/armedbear/lisp/Java.java	(original)
+++ trunk/abcl/src/org/armedbear/lisp/Java.java	Fri Jan  8 14:55:05 2010
@@ -45,8 +45,7 @@
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
-import java.util.HashMap;
-import java.util.Map;
+import java.util.*;
 
 public final class Java
 {
@@ -201,7 +200,7 @@
                     f.set(instance,args[3].javaInstance(fieldType));
                     return args[3];
             }
-            return JavaObject.getInstance(f.get(instance), translate);
+            return JavaObject.getInstance(f.get(instance), translate, f.getType());
         }
         catch (NoSuchFieldException e) {
             error(new LispError("no such field"));
@@ -365,17 +364,16 @@
                 if (c != null) {
                     String methodName = methodRef.getStringValue();
                     Method[] methods = c.getMethods();
+		    List<Method> staticMethods = new ArrayList<Method>();
                     int argCount = args.length - 2;
-                    for (int i = 0; i < methods.length; i++) {
-                        Method method = methods[i];
-                        if (!Modifier.isStatic(method.getModifiers())
-                            || method.getParameterTypes().length != argCount)
-                            continue;
-                        if (method.getName().equals(methodName)) {
-                            m = method;
-                            break;
-                        }
-                    }
+		    for(Method m1 : methods) {
+			if(Modifier.isStatic(m1.getModifiers())) {
+			    staticMethods.add(m1);
+			}
+		    }
+		    if(staticMethods.size() > 0) {
+			m = findMethod(staticMethods.toArray(new Method[staticMethods.size()]), methodName, args);
+		    }
                     if (m == null)
                         error(new LispError("no such method"));
                 }
@@ -391,7 +389,7 @@
                     methodArgs[i-2] = arg.javaInstance(argTypes[i-2]);
             }
             Object result = m.invoke(null, methodArgs);
-            return JavaObject.getInstance(result, translate);
+	    return JavaObject.getInstance(result, translate, m.getReturnType());
         }
         catch (ControlTransfer c) {
             throw c;
@@ -630,26 +628,55 @@
     {
         if (args.length < 2)
             error(new WrongNumberOfArgumentsException(fun));
-        final LispObject methodArg = args[0];
-        final LispObject instanceArg = args[1];
-        final Object instance;
-        if (instanceArg instanceof AbstractString)
-            instance = instanceArg.getStringValue();
-        else if (instanceArg instanceof JavaObject)
-            instance = ((JavaObject)instanceArg).getObject();
-        else {
-	    instance = instanceArg.javaInstance();
-        }
         try {
-            final Method method;
+	    final LispObject methodArg = args[0];
+	    final LispObject instanceArg = args[1];
+	    final Object instance;
+	    Class<?> intendedClass = null;
+	    if (instanceArg instanceof AbstractString) {
+		instance = instanceArg.getStringValue();
+	    } else if (instanceArg instanceof JavaObject) {
+		JavaObject jobj = ((JavaObject)instanceArg);
+		instance = jobj.getObject();
+		intendedClass = jobj.getIntendedClass();
+	    } else {
+		instance = instanceArg.javaInstance();
+	    }
+	    if(instance == null) {
+		throw new NullPointerException(); //Handled below
+	    }
+            Method method;
+	    Object[] methodArgs;
             if (methodArg instanceof AbstractString) {
+		methodArgs = translateMethodArguments(args, 2);
                 String methodName = methodArg.getStringValue();
-                Class c = instance.getClass();
-                method = findMethod(c, methodName, args);
+		if(intendedClass == null) {
+		    intendedClass = instance.getClass();
+		}
+                method = findMethod(intendedClass, methodName, methodArgs);
+		Class actualClass = null;
+		if(method == null) {		    
+		    actualClass = instance.getClass();
+		    if(intendedClass != actualClass &&
+		       Modifier.isPublic(actualClass.getModifiers())) {
+			method = findMethod(actualClass, methodName, methodArgs);
+		    }
+		}
+		if (method == null) {
+		    String classes = intendedClass.getName();
+		    if(actualClass != null && actualClass != intendedClass) {
+			classes += " or " + actualClass.getName();
+		    }
+		    throw new NoSuchMethodException("No applicable method named " + methodName + " found in " + classes);
+		}
+
             } else
                 method = (Method) JavaObject.getObject(methodArg);
             Class<?>[] argTypes = (Class<?>[])method.getParameterTypes();
-            Object[] methodArgs = new Object[args.length - 2];
+	    if(argTypes.length != args.length - 2) {
+		return error(new WrongNumberOfArgumentsException("Wrong number of arguments for " + method + ": expected " + argTypes.length + ", got " + (args.length - 2)));
+	    }
+            methodArgs = new Object[argTypes.length];
             for (int i = 2; i < args.length; i++) {
                 LispObject arg = args[i];
                 if (arg == NIL)
@@ -658,7 +685,8 @@
                     methodArgs[i-2] = arg.javaInstance(argTypes[i-2]);
             }
             return JavaObject.getInstance(method.invoke(instance, methodArgs),
-                                          translate);
+                                          translate,
+					  method.getReturnType());
         }
         catch (ControlTransfer t) {
             throw t;
@@ -699,10 +727,8 @@
 	return javaArgs;
     }
 
-    private static Method findMethod(Class<?> c, String methodName, LispObject[] args) throws NoSuchMethodException {
-	int argCount = args.length - 2;
-        Object[] javaArgs = translateMethodArguments(args, 2);
-        Method[] methods = c.getMethods();
+    private static Method findMethod(Method[] methods, String methodName, Object[] javaArgs) {
+	int argCount = javaArgs.length;
         Method result = null;
         for (int i = methods.length; i-- > 0;) {
             Method method = methods[i];
@@ -720,12 +746,24 @@
                 result = method;
             }
         }
-        if (result == null) {
-            throw new NoSuchMethodException(methodName);
-        }
         return result;
     }
 
+    private static Method findMethod(Class<?> c, String methodName, Object[] javaArgs) {
+        Method[] methods = c.getMethods();
+	return findMethod(methods, methodName, javaArgs);
+    }
+
+    private static Method findMethod(Class<?> c, String methodName, LispObject[] args) {
+        Object[] javaArgs = translateMethodArguments(args, 2);
+	return findMethod(c, methodName, javaArgs);
+    }
+
+    private static Method findMethod(Method[] methods, String methodName, LispObject[] args) {
+        Object[] javaArgs = translateMethodArguments(args, 2);
+	return findMethod(methods, methodName, javaArgs);
+    }
+
     private static Constructor findConstructor(Class<?> c, LispObject[] args) throws NoSuchMethodException {
 	int argCount = args.length - 1;
         Object[] javaArgs = translateMethodArguments(args, 1);
@@ -877,6 +915,23 @@
             return JavaObject.getInstance(arg.javaInstance(), true);
         }
     };
+
+    // ### jcoerce java-object intended-class
+    private static final Primitive JCOERCE =
+        new Primitive("jcoerce", PACKAGE_JAVA, true, "java-object intended-class")
+    {
+        @Override
+        public LispObject execute(LispObject javaObject, LispObject intendedClass)
+        {
+	    Object o = javaObject.javaInstance();
+	    Class<?> c = javaClass(intendedClass);
+	    try {
+		return JavaObject.getInstance(o, c);
+	    } catch(ClassCastException e) {
+		return error(new TypeError(javaObject, new SimpleString(c.getName())));
+	    }
+        }
+    };
     
     private static final Primitive JGET_PROPERTY_VALUE =
 	    new Primitive("%jget-property-value", PACKAGE_JAVA, true,

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 Jan  8 14:55:05 2010
@@ -41,13 +41,30 @@
 
 import java.util.*;
 
-public final class JavaObject extends LispObject
-{
+public final class JavaObject extends LispObject {
     private final Object obj;
+    private final Class<?> intendedClass;
 
-    public JavaObject(Object obj)
-    {
+    public JavaObject(Object obj) {
         this.obj = obj;
+	this.intendedClass = obj != null ? obj.getClass() : null;
+    }
+
+    /**
+     * Constructs a Java Object with the given intended class, used to access
+     * the object reflectively.
+     * @throws ClassCastException if the object is not an instance of the
+     *                            intended class.
+     */
+    public JavaObject(Object obj, Class<?> intendedClass) {
+	if(obj != null && intendedClass == null) {
+	    intendedClass = obj.getClass();
+	}
+	if(intendedClass != null && !intendedClass.isInstance(obj)) {
+	    throw new ClassCastException(obj + " can not be cast to " + intendedClass);
+	}
+	this.obj = obj;
+	this.intendedClass = intendedClass;
     }
 
     @Override
@@ -102,6 +119,24 @@
 
     /** Encapsulates obj, if required.
      * If obj is a {@link LispObject}, it's returned as-is.
+     * If not, a java object with the specified intended class is returned.
+     * 
+     * @param obj Any java object
+     * @param intendedClass the class that shall be used to access obj
+     * @return obj or a new JavaObject encapsulating obj
+     */
+    public final static LispObject getInstance(Object obj, Class<?> intendedClass) {
+        if (obj == null)
+            return new JavaObject(null);
+        
+        if (obj instanceof LispObject)
+            return (LispObject)obj;
+
+        return new JavaObject(obj, intendedClass);
+    }
+
+    /** Encapsulates obj, if required.
+     * If obj is a {@link LispObject}, it's returned as-is.
      * If obj is of a type which can be mapped to a lisp type,
      * an object of the mapped type is returned, if translated is true.
      *
@@ -109,11 +144,29 @@
      * @param translated
      * @return a LispObject representing or encapsulating obj
      */
-    public final static LispObject getInstance(Object obj, boolean translated)
+    public final static LispObject getInstance(Object obj, boolean translated) {
+	return getInstance(obj, translated, obj != null ? obj.getClass() : null);
+    }
 
-    {
+
+
+    /** Encapsulates obj, if required.
+     * If obj is a {@link LispObject}, it's returned as-is.
+     * If obj is of a type which can be mapped to a lisp type,
+     * an object of the mapped type is returned, if translated is true.
+     *
+     * @param obj
+     * @param translated
+     * @param intendedClass the class that shall be used to reflectively 
+     *                      access obj; it is an error for obj not to be
+     *                      an instance of this class. This parameter is ignored
+     *                      if translated == true and the object can be
+     *                      converted to a Lisp object.
+     * @return a LispObject representing or encapsulating obj
+     */
+    public final static LispObject getInstance(Object obj, boolean translated, Class<?> intendedClass) {
         if (! translated)
-            return getInstance(obj);
+            return getInstance(obj, intendedClass);
 
         if (obj == null) return NIL;
 
@@ -167,18 +220,23 @@
         // We might want to handle:
         //  - streams
         //  - others?
-        return new JavaObject(obj);
+        return new JavaObject(obj, intendedClass);
     }
 
     @Override
-    public Object javaInstance()
-    {
+    public Object javaInstance() {
         return obj;
     }
 
     @Override
     public Object javaInstance(Class c) {
-	return javaInstance();
+	if(obj == null) {
+	    return obj;
+	} else if(c.isAssignableFrom(intendedClass)) {
+	    return obj;
+	} else {
+	    return error(new TypeError(intendedClass.getName() + " is not assignable to " + c.getName()));
+	}
     }
 
     /** Returns the encapsulated Java object for
@@ -191,6 +249,10 @@
         return obj;
     }
 
+    public Class<?> getIntendedClass() {
+	return intendedClass;
+    }
+
     public static final Object getObject(LispObject o)
 
     {




More information about the armedbear-cvs mailing list