Skip to content

Instantly share code, notes, and snippets.

@matthewdowney
Created December 12, 2021 02:29
Show Gist options
  • Save matthewdowney/8afefae6fd65b33966d17175322d0770 to your computer and use it in GitHub Desktop.
Save matthewdowney/8afefae6fd65b33966d17175322d0770 to your computer and use it in GitHub Desktop.
Load a java .class file from disk directly into Clojure ... at your own risk obviously
(ns load-class
(:import (java.lang.reflect Array)
(java.io FileInputStream)))
;; ClassLoader/defineClass is protected, and calling it from the proxy requires
;; reflection.
(def ^:private classloader-define-class
(let [primitive-bytes (.getClass (Array/newInstance Byte/TYPE 0))
args [String primitive-bytes Integer/TYPE Integer/TYPE]]
(doto
(.getDeclaredMethod ClassLoader "defineClass" (into-array Class args))
(.setAccessible true))))
;; Read the primitive byte array and define a new class
(defn- define-class [class-loader ^String class-name class-bytes]
(let [args [class-name class-bytes (int 0) (int (count class-bytes))]]
(.invoke classloader-define-class class-loader (object-array args))))
;; Create a new class loader
(defn load-class! [{:keys [^String path ^String class-name]}]
(.loadClass
(proxy [ClassLoader] []
(loadClass [clazz]
;; Use custom logic for the specific class to load, use default for
;; other classes
(if (= clazz path)
(define-class this class-name (.readAllBytes (FileInputStream. path)))
(proxy-super loadClass clazz))))
path))
(comment
;; E.g. take some java source code
(def src
"package x;
public class AClass {
private final String someField;
public AClass(String someField) {
this.someField = someField;
}
public String toString () {
return \"AClass[\" + someField + \"]\";
}
}")
;; Compile it to a *.class file
(do
(spit "AClass.java" src)
(clojure.java.shell/sh "javac" "AClass.java"))
;; And then finally load it in
(let [loaded (load-class!
{:path "AClass.class"
:class-name "x.AClass"})
ctr (-> loaded .getConstructors first)]
(.newInstance ctr (object-array ["foo"])))
;=> #object[x.AClass 0x4dacea49 "AClass[foo]"]
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment