hara.class functions for reasoning about classes

Author: Chris Zheng  (z@caudate.me)
Date: 11 February 2018
Repository: https://github.com/zcaudate/hara
Version: 2.8.2

Add to project.clj dependencies:

[zcaudate/hara.class.enum "2.8.2"]

hara.class.enum contain functions that work with enums, turning them into more accessible data.

enum-values ^

returns all values of an enum type

v 2.2
(defn enum-values
  (let [method (.getMethod type "values" (make-array Class 0))
        values (.invoke method nil (object-array []))]
    (seq values)))
(->> (enum-values ElementType) (map str)) => (contains ["TYPE" "FIELD" "METHOD" "PARAMETER" "CONSTRUCTOR"] :in-any-order :gaps-ok)

enum? ^

check to see if class is an enum type

v 2.2
(defn enum?
  (if (-> (inheritance/ancestor-list type)
          (get java.lang.Enum))
    true false))
(enum? java.lang.annotation.ElementType) => true (enum? String) => false

1    class.inheritance

Add to project.clj dependencies:

[zcaudate/hara.class.inheritance "2.8.2"]

hara.class.inheritance contain functions that output inheritance properties of objects. It is used by many libraries including hara.reflect and hara.object.

ancestor-list ^

lists the direct ancestors of a class

v 2.1
(defn ancestor-list
  ([cls] (ancestor-list cls []))
  ([^java.lang.Class cls output]
     (if (nil? cls)
       (recur (.getSuperclass cls) (conj output cls)))))
(ancestor-list clojure.lang.PersistentHashMap) => [clojure.lang.PersistentHashMap clojure.lang.APersistentMap clojure.lang.AFn java.lang.Object]

ancestor-tree ^

lists the hierarchy of bases and interfaces of a class.

v 2.1
(defn ancestor-tree
  ([cls] (ancestor-tree cls []))
  ([^Class cls output]
     (let [base (.getSuperclass cls)]
       (if-not base output
               (recur base
                      (conj output [base (-> (.getInterfaces cls) seq set)]))))))
(ancestor-tree Class) => [[java.lang.Object #{java.io.Serializable java.lang.reflect.Type java.lang.reflect.AnnotatedElement java.lang.reflect.GenericDeclaration}]]

best-match ^

finds the best matching interface or class from a list of candidates

v 2.1
(defn best-match
  [candidates ^Class cls]
  (or (get candidates cls)
      (->> (apply concat (ancestor-tree cls))
           (map (fn [v]
                  (if (set? v)
                    (first (set/intersection v candidates))
                    (get candidates v))))
           (filter identity)
(best-match #{Object} Long) => Object (best-match #{String} Long) => nil (best-match #{Object Number} Long) => Number

2    class.multi

Add to project.clj dependencies:

[zcaudate/hara.class.multi "2.8.2"]

hara.class.multi contain functions that operate on multimethods

multimethod ^

creates a multimethod from an existing one

v 2.4
(defn multimethod
  [source name]
  (let [table (.getMethodTable source)
        clone (MultiFn. name 
                        (.dispatchFn source) 
                        (.defaultDispatchVal source)
                        (.hierarchy source))]
    (doseq [[dispatch-val method] table]
      (.addMethod clone dispatch-val method))
(defmulti hello :type) (defmethod hello :a [e] (assoc e :a 1)) (def world (multimethod hello "world")) (defmethod world :b [e] (assoc e :b 2)) (world {:type :b}) => {:type :b :b 2} ;; original method should not be changed (hello {:type :b}) => (throws)