I'm not caching the values, only the mapping from keywords to methods (the caching is per class, not per bean). It's just saving the introspection/reflection on each call. The values themselves are always obtained directly from the bean.
On Thursday, January 30, 2014 4:12:31 PM UTC+2, Jozef Wagner wrote: > > Hi, > > Not every bean is immutable, so you cannot cache its values by default. If > reading from the bean is expensive for you, either create a normal hash-map > with into {} and select-keys, or use memoize. > > user=> (def b (bean (java.util.Date.))) > #'user/b > user=> (def hm (into {} (select-keys b [:year :month :date]))) > #'user/hm > user=> hm > {:date 30, :month 0, :year 114} > user=> (def mb (memoize b)) > #'user/mb > user=> (mb :day) > 4 > > JW > > > > On Thu, Jan 30, 2014 at 2:35 PM, pron <ron.pr...@gmail.com > <javascript:>>wrote: > >> 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 clo...@googlegroups.com<javascript:> >> Note that posts from new members are moderated - please be patient with >> your first post. >> To unsubscribe from this group, send email to >> clojure+u...@googlegroups.com <javascript:> >> 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+u...@googlegroups.com <javascript:>. >> For more options, visit https://groups.google.com/groups/opt_out. >> > > -- 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.