Transforming the data after it comes out of the parser can be
cumbersome with complex data structures though, it would be nice to
have a way for the parser to return the data in the desired format.
I updated clojure.contrib.json with the ability to add custom
deserializers:
(def *deserializers* (atom {}))
(defn add-deserializer [k deserializer]
(swap! *deserializers* #(assoc % k deserializer)))
(defn remove-deserializer [k]
(swap! *deserializers* #(dissoc % k)))
(defn- read-json-object [#^PushbackReader stream keywordize?]
;; Expects to be called with the head of the stream AFTER the
;; opening bracket.
(loop [i (.read stream), key nil, result (transient {})]
(let [c (char i)]
(cond
(= i -1) (throw (EOFException. "JSON error (end-of-file inside
object)"))
(Character/isWhitespace c) (recur (.read stream) key result)
(= c \,) (recur (.read stream) nil result)
(= c \:) (recur (.read stream) key result)
(= c \}) (if (nil? key)
(persistent! result)
(throw (Exception. "JSON error (key missing value in
object)")))
:else (do (.unread stream i)
(let [element (read-json-reader stream keywordize?
true nil)]
(if (nil? key)
(if (string? element)
(recur (.read stream) element result)
(throw (Exception. "JSON error (non-string key
in object)")))
(let [elm-key (if keywordize? (keyword key) key)
deserializer (get @*deserializers* elm-
key)]
(recur (.read stream) nil
(assoc! result elm-key
(if deserializer
(deserializer element) element)))))))))))
all I had to change was the part where the key and value are put in
the map to first check if there is a deserializer registered and use
it instead of storing the data directly, then I can use it as follows
(defn write-date [date #^PrintWriter out]
(.print out
(str "\"" (.format (new java.text.SimpleDateFormat "MMM dd, yyyy
hh:mm:ss a") date) "\"")))
(extend Date Write-JSON
{:write-json write-date})
(add-deserializer :age #(.parse (new java.text.SimpleDateFormat "MMM
dd, yyyy hh:mm:ss a") %))
(let [data {:name "John" :age (new java.util.Date) :address [:street
"1 Bay" :city "Toronto"]}
encoded (json-str data)]
(println encoded)
(println "decoded" (read-json encoded)))
Would there be an issue with adding something like that to the
contrib?
On Aug 21, 1:52 pm, Stuart Sierra <[email protected]> wrote:
> I suppose one could override the (private) read-json-object function
> to transform maps after they are read, based on the presence of
> certain keys. But that would seriously complicate the reader. It's
> probably easier to transform the data after it comes back from the
> JSON parser.
>
> -S
>
> On Aug 20, 5:06 pm, Dmitri <[email protected]> wrote:
>
>
>
>
>
>
>
> > My concern is more to do with the reader, I think extending writer
> > works quite well, it would be nice if it was possible to do the same
> > thing with the reader, so you could specify how to deserialize
> > specific types of data. Right now it seems to be baked into read-json-
> > reader and there's no easy way to extend it.
>
> > Maybe it could be possible to specify how to deserialize data based on
> > the key names, then if the reader hits a key with the given name it
> > would try to deserialize it with the given function or something?
>
> > On Aug 20, 3:32 pm, Stuart Sierra <[email protected]> wrote:
>
> > > Since there is no standard for how to represent dates in JSON, it is
> > > unlikely to be built in. But you can extend the writer with
> > > application-specific date formats.
> > > -S
>
> > > On Aug 20, 2:15 pm, Dmitri <[email protected]> wrote:
>
> > > > I'm currently using Dan Larkin's clojure-json, and it provides a way
> > > > to serialize and deserialize dates, it also provides the option to
> > > > specify custom serializers, eg:
>
> > > > (defn date-encoder
> > > > [date writer pad current-indent start-token-indent indent-
> > > > size]
> > > > (.append writer (str start-token-indent \" date \")))
>
> > > > I was looking at switching to using the json implementation in clojure-
> > > > contrib, but noticed that it doesn't handle dates nor does it provide
> > > > a way to register custom serializers, is there a plan to implement
> > > > that in the future, or is the proper approach to simply extend Write-
> > > > JSON whenever a custom serializer/deserializer is needed.
--
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