Small and furry, well ... definitely furry. [source]

Tuesday, March 2, 2010

Wrap

This is a quick way to wrap a Java object in a Clojure hashmap.

EDIT: Stuart kindly referred me to bean. Seems like I should do more homework :)


(defn- no-arguments? [method]
  (zero? (count (.getParameterTypes method))))

(defn- getter? [method]
  (let [name (.getName method)]
    (and (no-arguments? method)
         (not (= name "getClass"))
         (.startsWith name "get"))))

(defn- obj-getters [obj]
  (let [cls (if (class? obj) obj (class obj))]
    (filter getter? (.getMethods cls))))

(defn- name->keyword 
  "\".getTimezoneoffset\" -> :timezone-offset"
  [n]
  (keyword (-> n (.replaceAll "([A-Z])" "-$1") (.substring 4) (.toLowerCase))))

; FIXME: This is currently doing one level conversion, it'll be nice if it'll
; recursivly convert collections, hash maps ...
(defn wrap 
  "Convert Java object to a hash map, using zero arguments getters

  user=> (wrap (new Date))
  {:timezone-offset 480, :day 2, :year 110, :time 1267559056404, :seconds 16, :month 2, :minutes 44, :hours 11, :date 2}
  "
  [obj]
  (let [getters (obj-getters obj)
        keywords (map name->keyword (map #(.getName %) getters))
        values (map #(.invoke % obj nil) getters)]
    (zipmap keywords values)))

No comments:

Post a Comment