(defmacro crack-abstract "implements the abstract methods of a class by forwarding calls to a generated interface." [klass-sym method-prefix interface-name additional-methods factory-name] (let [klass (resolve klass-sym) methods (->> klass (.getMethods)) method-names (->> methods (filter #(java.lang.reflect.Modifier/isAbstract (.getModifiers %))) (map #(.getName %)) (into (set (map name additional-methods)))) required-impls (for [method methods :when (contains? method-names (.getName method))] method) impl (with-meta (gensym 'impl) {:tag interface-name}) ctor-argcs (->> klass (.getDeclaredConstructors) (map #(.getParameterCount %)) (distinct) (sort))] `(do (definterface ~interface-name ~@(doall (map first (vals (group-by first (for [method required-impls :let [argc (.getParameterCount method) params (take argc (repeatedly gensym))]] `(~(symbol (str (name method-prefix) (.getName method) (.getParameterCount method))) ~(vec params)))))))) (defn ~factory-name ~@(doall (for [ctor-argc ctor-argcs :let [params (take ctor-argc (repeatedly gensym))]] `([~@(cons impl params)] (proxy [~klass-sym clojure.lang.IDeref] [~@params] (deref [] [~impl ~@params]) ~@(doall (for [[method-name methods] (group-by #(.getName %) required-impls)] `(~(symbol method-name) ~@(doall (for [argc (distinct (map #(.getParameterCount %) methods)) :let [params (take argc (repeatedly gensym)) forward-method-name (symbol (str (name method-prefix) method-name argc))]] `(~(vec params) (. ~impl (~forward-method-name ~@params))))))))))))))))
Generated At 2025-03-01T17:35:54-0800 original