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 <ron.press...@gmail.com> 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 <ron.pr...@gmail.com> 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
>>>
>>> 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
>>>
>>> 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.
>>>
>>> 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.
>

-- 
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.

Reply via email to