Version 3 (modified by Mark Evenson, 11 years ago) (diff)

Updated to latest working code

Dynamically Creating Java Interfaces

As of r13078, one can use the classwriter in the JVM package to dynamically create a Java interface.

An example of work in progress to use dynamically created Java interfaces for callbacks in JNA with CFFI:

(jvm::define-class-name +callback-object+ "com.sun.jna.Callback")
(defconstant +dynamic-callback-package+ "org/armedbear/jna/dynamic/callbacks")

TEST: (define-jinterface :int '(foo) '(:int))

(defun define-interface (rettype arg-names arg-types)
  "Returns the Java byte[] array of a class representing a Java interface."
  (declare (ignore rettype arg-names arg-types)) ;; XXX unimplemented
  (let* ((class-name-string (format nil "~A/~A" 
                                    +dynamic-callback-package+ (symbol-name (gensym))))
         (class-name (jvm::make-jvm-class-name class-name-string))
         (class (jvm::make-class-interface-file class-name))
         (method (jvm::make-jvm-method "callback" :int '(:int) 
                                       :flags '(:public :abstract))))
    (jvm::class-add-superinterface class +callback-object+)
    (jvm::class-add-method class method)
    (jvm::finalize-class-file class)
    (let ((s (sys::%make-byte-array-output-stream)))
      (jvm::write-class-file class s)
      (sys::%get-output-stream-bytes s))))

(defun load-class (class-bytes) 
  "Load the Java byte[] array CLASS-BYTES as a Java class."
  (let ((load-class-method 
         (jmethod "org.armedbear.lisp.JavaClassLoader"
                  "loadClassFromByteArray" "[B")))
    (jcall load-class-method java::*classloader* class-bytes)))

(defun write-class (class-bytes pathname)
  "Write the Java byte[] array CLASS-BYTES to PATHNAME."
  (with-open-file (stream pathname 
                          :direction :output 
                          :element-type '(signed-byte 8))
    (dotimes (i (jarray-length class-bytes))
      (write-byte (jarray-ref class-bytes i) stream))))