dakrone / cheshire

Clojure JSON and JSON SMILE (binary json format) encoding/decoding

Home Page:https://github.com/dakrone/cheshire

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Extended encoding support for proxy / Superclasses

ivarref opened this issue · comments

Hi

And thanks for a fine library!

I'm missing one little piece of functionality. Sometimes I'd like to proxy an object and add some info, but then the correct encoding method is not called. More concretely I'd like to format some instances of java.util.Date differently than others.

Example setup and usage:

(defn wrap-date
  ([^Date d] (wrap-date d {}))
  ([^Date d _meta]
   (proxy [Date IObj] [(.getTime d)]
     (meta [] _meta)
     (withMeta [m] (wrap-date d m)))))

(wrap-date (Date.) {:format-string "yyyy-MM-dd"})
=> #inst"2019-04-05T18:38:13.985-00:00" ; looks like a regular Date, but has metadata

Problem:

; (class (wrap-date (Date.) {:format-string "yyyy-MM-dd"}))
; => cheshire.generate.proxy$java.util.Date$IObj$82d48561

(defn generate [^JsonGenerator jg obj ^String date-format ^Exception ex key-fn]

   (get (:impls JSONable) (class obj)) (#'to-json obj jg)
   ; This will not match

   (i? Date obj) (let [sdf (doto (SimpleDateFormat. date-format)
                             (.setTimeZone (SimpleTimeZone. 0 "UTC")))]
                   (write-string ^JsonGenerator jg (.format sdf obj)))
   ; This will match however

Possible solution:

; Given that (.getSuperclass (class (wrap-date (Date.))))
; => java.util.Date

(defn generate [^JsonGenerator jg obj ^String date-format ^Exception ex key-fn]

   (get (:impls JSONable) (class obj)) (#'to-json obj jg)
   (get (:impls JSONable) (.getSuperclass (class obj))) (#'to-json obj jg)

Not sure if this is a good solution, but it should work, and does not break existing tests.
What do you think?

Thanks and kind regards.

I ended up creating a small project for extending java.util.Date and implementing clojure.lang.IObj for this task: https://github.com/ivarref/datewrapper

That solves my problem (but not the general case) ...

Thinking about this, something that concerns me about:

(get (:impls JSONable) (.getSuperclass (class obj))) (#'to-json obj jg)

Is what happens when the superclass of an object implements to-json differently than the subclass? I think I need a concrete test to know for sure (more playing around with it on my end)