[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