On Nov 16, 11:53 am, Ben Smith-Mannschott <[email protected]>
wrote:
> On Wed, Nov 16, 2011 at 17:28, Ben Mabey <[email protected]> wrote:
> > Hi,
> > I would like to be able to add metadata to arbitrary java objects that have
> > already been instantiated. I know that you can use proxy to add metadata to
> > objects that you create but in my case the object already exists (i.e. it is
> > returned from another method call outside of my control).
>
> > It seems like the best solution would be to create a delegate class/object
> > that wraps the original one. Being able to write something like this would
> > be ideal:
>
> > (defn wrap-with-meta
> > ([obj]
> > (wrap-with-meta obj nil))
> > ([obj meta]
> > (delegate obj
> > clojure.lang.IObj
> > (withMeta [this new-meta] (wrap-with-meta obj
>
> > new-meta))
> > (meta [this] meta))))
>
> > The delegate function would operate very similar to proxy, but instead of
> > taking a class it takes an object. A class would be created that extends
> > the object's class, just like a class is generated for proxy. However,
> > instead of stubs being generated that call super the stubs would delegate to
> > the given object. (Also note, I am also using reify-like syntax since I
> > prefer that to the syntax in proxy.)
>
> > I'm curious to hear people's thoughts on this approach. I'd also be really
> > interested to see how other people have addressed this in the past (I doubt
> > I'm the first one to run into this).
>
> > I know that clojure mentality is to avoid wrappers, but I don't see this as
> > being much different than what proxy already does. Of course, I may be
> > missing something... if so, please enlighten me. :)
>
> > Thanks,
> > Ben
>
> Here's an approach that may be of use: don't store the metadata in a
> Map instead of decorating the Object with it. This map should use
> object identity, not equality and should hold its keys weakly so that
> it prevent collection of objects that otherwise would be garbage.
> Safe to use concurrently would also be a plus. Conveniently, Google's
> Guava library provides such a thing. Here's a sketch:
>
> == project.clj ========================================
>
> (defproject pojometa "0.0.1-SNAPSHOT"
> :dependencies [[org.clojure/clojure "1.3.0"]
> [com.google.guava/guava "10.0.1"]])
>
> == src/pojometa/core.clj ==============================
>
> (ns pojometa.core
> (:import [com.google.common.collect MapMaker]))
>
> (def meta-map
> (-> (MapMaker.) .weakKeys .makeMap))
>
> (defn meta* [o]
> (if (instance? clojure.lang.IMeta o)
> (clojure.core/meta o)
> (.get meta-map o)))
>
> (defn with-meta* [o m]
> (if (instance? clojure.lang.IMeta o)
> (clojure.core/with-meta o m)
> (do (.put meta-map o m)
> o)))
>
> == usage ==============================================
>
> pojometa.core=> (def o (Object.)) ;; arbitrary java object
> pojometa.core=> (meta* (with-meta* o {:foo true}))
> {:foo true}
>
> ;; also "does the right thing" for Clojure types that
> ;; already know how to have metadata.
>
> pojometa.core=> (meta* (with-meta* {} {:bar 1}))
> {:bar 1}
(def o (Object.))
(def om (with-meta* o {:foo true}))
(def whatever (with-meta* o {:foo false}))
(meta* om) ;=> {:foo false}
Doesn't really support Clojure's concept of metadata if it's shared
global mutable state.
--
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