Changeset 11389


Ignore:
Timestamp:
11/10/08 22:34:36 (13 years ago)
Author:
astalla
Message:
  • Added support for lisp-this for interface implementations
  • Correctly implemented package-based jmake-proxy
  • Passed only the method name to lisp functions implementing java interfaces, instead of the full blown method metaobject
Location:
branches/scripting/j/src/org/armedbear/lisp
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • branches/scripting/j/src/org/armedbear/lisp/JProxy.java

    r11379 r11389  
    125125    //NEW IMPLEMENTATION by Alessio Stalla
    126126 
     127    private static final Map<Object, LispObject> proxyMap = new WeakHashMap<Object, LispObject>();
     128 
    127129    public static class LispInvocationHandler implements InvocationHandler {
    128130     
     
    149151    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    150152        if(hashCodeMethod.equals(method)) {
    151           return proxy.hashCode();
     153          return System.identityHashCode(proxy);
    152154        }
    153155        if(equalsMethod.equals(method)) {
    154           return proxy.equals(args[0]);
     156          return proxy == args[0];
    155157        }
    156158        if(toStringMethod.equals(method)) {
    157           return proxy.toString();
     159          return proxy.getClass().getName() + '@' + Integer.toHexString(proxy.hashCode());
    158160        }
    159161       
     
    162164        }
    163165      LispObject[] lispArgs = new LispObject[args.length + 2];
    164       lispArgs[0] = toLispObject(proxy);
    165       lispArgs[1] = new JavaObject(method);
     166      synchronized(proxyMap) {
     167        lispArgs[0] = toLispObject(proxyMap.get(proxy));
     168      }
     169      lispArgs[1] = new SimpleString(method.getName());
    166170      for(int i = 0; i < args.length; i++) {
    167171        lispArgs[i + 2] = toLispObject(args[i]);
     
    188192              return error(new TypeError(args[0], Symbol.FUNCTION));
    189193            }
    190            
    191194            return new JavaObject(new LispInvocationHandler((Function) args[0]));
    192195          }
     
    199202          public LispObject execute(final LispObject[] args) throws ConditionThrowable {
    200203            int length = args.length;
    201             if (length != 2) {
     204            if (length != 3) {
    202205              return error(new WrongNumberOfArgumentsException(this));
    203206            }
     
    208211            if(!(args[1] instanceof JavaObject) ||
    209212               !(((JavaObject) args[1]).javaInstance() instanceof InvocationHandler)) {
    210                 return error(new TypeError(args[1], new SimpleString(InvocationHandler.class.getName())));
    211               }
     213              return error(new TypeError(args[1], new SimpleString(InvocationHandler.class.getName())));
     214            }
    212215            Class<?> iface = (Class<?>) ((JavaObject) args[0]).javaInstance();
    213             InvocationHandler invocationHandler = (InvocationHandler) ((JavaObject) args[1]).javaInstance(); 
     216            InvocationHandler invocationHandler = (InvocationHandler) ((JavaObject) args[1]).javaInstance();
    214217            Object proxy = Proxy.newProxyInstance(
    215218                iface.getClassLoader(),
    216219                new Class[] { iface },
    217220                invocationHandler);
     221            synchronized(proxyMap) {
     222              proxyMap.put(proxy, args[2]);
     223            }
    218224            return new JavaObject(proxy);
    219225          }
  • branches/scripting/j/src/org/armedbear/lisp/java.lisp

    r11379 r11389  
    7070  (fmakunbound 'jmake-proxy))
    7171
    72 (defgeneric jmake-proxy (interface implementation))
    73 
    74 ;(defun jmake-proxy (interface implementation)
    75 ;  (jmake-proxy-impl interface implementation))
    76 
    77 (defmethod jmake-proxy (interface invocation-handler)
    78   (%jmake-proxy (jclass interface) invocation-handler))
    79 
    80 (defmethod jmake-proxy (interface (implementation function))
    81   (%jmake-proxy (jclass interface) (jmake-invocation-handler implementation)))
    82 
    83 #|
    84 TODO java->lisp wrong (coding at night has nasty effects)
    85 (defmethod jmake-proxy (interface (implementation package))
     72(defgeneric jmake-proxy (interface implementation &optional lisp-this)
     73  (:documentation "Returns a proxy Java object implementing the provided interface using methods implemented in Lisp - typically closures, but implementations are free to provide other mechanisms. You can pass an optional 'lisp-this' object that will be passed to the implementing methods as their first argument. If you don't provide this object, NIL will be used. The second argument of the Lisp methods is the name of the Java method being implemented. This has the implication that overloaded methods are merged, so you have to manually discriminate them if you want to. The remaining arguments are java-objects wrapping the method's parameters."))
     74
     75(defmethod jmake-proxy (interface invocation-handler &optional lisp-this)
     76  "Basic implementation that directly uses an invocation handler."
     77  (%jmake-proxy (jclass interface) invocation-handler lisp-this))
     78
     79(defmethod jmake-proxy (interface (implementation function) &optional lisp-this)
     80  "Implements a Java interface forwarding method calls to a Lisp function."
     81  (%jmake-proxy (jclass interface) (jmake-invocation-handler implementation) lisp-this))
     82
     83(defmethod jmake-proxy (interface (implementation package) &optional lisp-this)
     84  "Implements a Java interface mapping Java method names to symbols in a given package. javaMethodName is mapped to a JAVA-METHOD-NAME symbol. An error is signaled if no such symbol exists in the package, or if the symbol exists but does not name a function."
    8685  (flet ((java->lisp (name)
    87      (substitute #\- #\. (string-upcase name))))
     86     (with-output-to-string (str)
     87       (let ((last-lower-p nil))
     88         (map nil (lambda (char)
     89        (let ((upper-p (char= (char-upcase char) char)))
     90          (when (and last-lower-p upper-p)
     91            (princ "-" str))
     92          (setf last-lower-p (not upper-p))
     93          (princ (char-upcase char) str)))
     94        name)))))
    8895    (%jmake-proxy (jclass interface)
    8996      (jmake-invocation-handler
    9097       (lambda (obj method &rest args)
    91          (let* ((sym (find-symbol (java->lisp (jmethod-name method))))
    92           (fn (symbol-function sym)))
    93            (if fn
    94          (apply fn obj args)
    95          (error "Function ~A, implementation of method ~A, not found in ~A"
    96           sym (jmethod-name method) implementation))))))))
    97 |#
    98 (defmethod jmake-proxy (interface (implementation hash-table))
     98         (let ((sym (find-symbol
     99         (java->lisp method)
     100         implementation)))
     101           (unless sym
     102       (error "Symbol ~A, implementation of method ~A, not found in ~A"
     103          (java->lisp method)
     104          method
     105          implementation))
     106       (if (fboundp sym)
     107           (apply (symbol-function sym) obj method args)
     108           (error "Function ~A, implementation of method ~A, not found in ~A"
     109            sym method implementation)))))
     110      lisp-this)))
     111
     112(defmethod jmake-proxy (interface (implementation hash-table) &optional lisp-this)
     113  "Implements a Java interface using closures in an hash-table keyed by Java method name."
    99114  (%jmake-proxy (jclass interface)
    100115    (jmake-invocation-handler
    101116     (lambda (obj method &rest args)
    102        (let ((fn (gethash (jmethod-name method) implementation)))
     117       (let ((fn (gethash method implementation)))
    103118         (if fn
    104119       (apply fn obj args)
    105120       (error "Implementation for method ~A not found in ~A"
    106         (jmethod-name method) implementation)))))))
     121        method implementation)))))
     122    lisp-this))
    107123
    108124(defun jobject-class (obj)
  • branches/scripting/j/src/org/armedbear/lisp/scripting/AbclScriptEngine.java

    r11370 r11389  
    279279      out = new WriterOutputStream(ctx.getWriter());
    280280      Stream outStream = new Stream(out, Symbol.CHARACTER);
     281      Stream inStream  = new Stream(in,  Symbol.CHARACTER);
    281282      retVal = evalScript.execute(makeBindings(ctx.getBindings(ScriptContext.GLOBAL_SCOPE)),
    282283                    makeBindings(ctx.getBindings(ScriptContext.ENGINE_SCOPE)),
    283                     new Stream(in, Symbol.CHARACTER),
    284                     outStream,
     284                    inStream, outStream,
    285285                    new SimpleString(code), new JavaObject(ctx));
    286       outStream._finishOutput();
    287       out.flush();
    288       //in.close();
    289       out.close();
    290286      return toJava(retVal);
    291287    } catch (ConditionThrowable e) {
     
    323319  private static Object toJava(LispObject lispObject) throws ConditionThrowable {
    324320    return lispObject.javaInstance();
    325     /*
    326     if(lispObject instanceof JavaObject) {
    327       return ((JavaObject) lispObject).getObject();
    328     } else if(lispObject instanceof SingleFloat) {
    329       return ((SingleFloat) lispObject).value;
    330     } else if(lispObject instanceof DoubleFloat) {
    331       return ((DoubleFloat) lispObject).value;
    332     } else if(lispObject instanceof LispCharacter) {
    333       return ((LispCharacter) lispObject).value;
    334     } else if(lispObject instanceof Bignum) {
    335       return ((Bignum) lispObject).value;
    336     } else if(lispObject instanceof Fixnum) {
    337       return ((Fixnum) lispObject).value;
    338     } else if(lispObject instanceof SimpleString) {
    339       return ((SimpleString) lispObject).javaInstance();
    340     } else {
    341       return lispObject;
    342     }*/
    343321  }
    344322 
     
    386364  @Override
    387365  public <T> T getInterface(Class<T> clasz) {
    388     //return getInterface(Lisp.NIL, clasz);
    389     throw new UnsupportedOperationException("Not implemented");
     366    try {
     367      return getInterface(eval("(cl:find-package '#:ABCL-SCRIPT-USER)"), clasz);
     368    } catch (ScriptException e) {
     369      throw new Error(e);
     370    }
    390371  }
    391372
     
    395376    try {
    396377      Symbol s = findSymbol("jmake-proxy", "JAVA");
    397       LispObject f = s.getSymbolFunction();
    398378      JavaObject iface = new JavaObject(clasz);
    399       return (T) ((JavaObject) f.execute(iface, (LispObject) thiz)).javaInstance();
     379      return (T) ((JavaObject) s.execute(iface, (LispObject) thiz)).javaInstance();
    400380    } catch (ConditionThrowable e) {
    401381      throw new Error(e);
  • branches/scripting/j/src/org/armedbear/lisp/scripting/lisp/abcl-script.lisp

    r11379 r11389  
    1818
    1919(in-package :abcl-script)
    20 
    21 (defvar *java-interface-implementations* (make-hash-table :test #'equal))
    2220
    2321(defconstant +global-scope+
Note: See TracChangeset for help on using the changeset viewer.