The bean function is a very useful Java interop feature that provides a read-only view of a Java Bean as a Clojure map. As it stands, the function performs introspection on the bean's class whenever the function is called:
(defn bean "Takes a Java object and returns a read-only implementation of the map abstraction based upon its JavaBean properties." {:added "1.0"} [^Object x] (let [c (. x (getClass)) pmap (reduce1 (fn [m ^java.beans.PropertyDescriptor pd] (let [name (. pd (getName)) method (. pd (getReadMethod))] (if (and method (zero? (alength (. method (getParameterTypes))))) (assoc m (keyword name) (fn [] (clojure.lang.Reflector/prepRet (.getPropertyType pd) (. method (invoke x nil))))) m))) {} (seq (.. java.beans.Introspector (getBeanInfo c) (getPropertyDescriptors)))) v (fn [k] ((pmap k))) snapshot (fn [] (reduce1 (fn [m e] (assoc m (key e) ((val e)))) {} (seq pmap)))] (proxy [clojure.lang.APersistentMap] [] (containsKey [k] (contains? pmap k)) (entryAt [k] (when (contains? pmap k) (new clojure.lang.MapEntry k (v k)))) (valAt ([k] (when (contains? pmap k) (v k))) ([k default] (if (contains? pmap k) (v k) default))) (cons [m] (conj (snapshot) m)) (count [] (count pmap)) (assoc [k v] (assoc (snapshot) k v)) (without [k] (dissoc (snapshot) k)) (seq [] ((fn thisfn [plseq] (lazy-seq (when-let [pseq (seq plseq)] (cons (new clojure.lang.MapEntry (first pseq) (v (first pseq))) (thisfn (rest pseq)))))) (keys pmap)))))) I propose to cache the pmap value for each class using JDK 7's ClassValue<http://docs.oracle.com/javase/7/docs/api/>. Here's a proposed implementation: (def ^:private ^java.lang.ClassValue bean-class-value (proxy [java.lang.ClassValue] [] (computeValue [c] (reduce (fn [m ^java.beans.PropertyDescriptor pd] (let [name (. pd (getName)) method (. pd (getReadMethod)) type (.getPropertyType pd)] (if (and method (zero? (alength (. method (getParameterTypes))))) (assoc m (keyword name) (fn [x] (clojure.lang.Reflector/prepRet type (. method (invoke x nil))))) m))) {} (seq (.. java.beans.Introspector (getBeanInfo c) (getPropertyDescriptors))))))) (defn bean "Takes a Java object and returns a read-only implementation of the map abstraction based upon its JavaBean properties." {:added "1.0"} [^Object x] (let [c (. x (getClass)) pmap (.get bean-class-value c) v (fn [k] ((pmap k) x)) snapshot (fn [] (reduce (fn [m e] (assoc m (key e) ((val e) x))) {} (seq pmap)))] (proxy [clojure.lang.APersistentMap] [] (containsKey [k] (contains? pmap k)) (entryAt [k] (when (contains? pmap k) (new clojure.lang.MapEntry k (v k)))) (valAt ([k] (when (contains? pmap k) (v k))) ([k default] (if (contains? pmap k) (v k) default))) (cons [m] (conj (snapshot) m)) (count [] (count pmap)) (assoc [k v] (assoc (snapshot) k v)) (without [k] (dissoc (snapshot) k)) (seq [] ((fn thisfn [plseq] (lazy-seq (when-let [pseq (seq plseq)] (cons (new clojure.lang.MapEntry (first pseq) (v (first pseq))) (thisfn (rest pseq)))))) (keys pmap)))))) -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/groups/opt_out.