Sorry, I've misread your post. If you want this feature to be added to Clojure, please submit a ticket at http://dev.clojure.org/jira/browse/CLJ
JW On Thu, Jan 30, 2014 at 3:16 PM, pron <[email protected]> wrote: > 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 <[email protected]> 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 [email protected] >>> >>> Note that posts from new members are moderated - please be patient with >>> your first post. >>> To unsubscribe from this group, send email to >>> [email protected] >>> >>> 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 [email protected]. >>> >>> 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 [email protected] > Note that posts from new members are moderated - please be patient with > your first post. > To unsubscribe from this group, send email to > [email protected] > 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 [email protected]. > 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 [email protected] Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to [email protected] 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 [email protected]. For more options, visit https://groups.google.com/groups/opt_out.
