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))))
Last modified 11 years ago Last modified on 12/01/10 22:48:51