Search code examples
clojureedn

How can I use *data-readers* with edn?


I tried to follow the documentation for clojure.instant/read-instant-timestamp, which reads:

clojure.instant/read-instant-timestamp
  To read an instant as a java.sql.Timestamp, bind *data-readers* to a
map with this var as the value for the 'inst key. Timestamp preserves
fractional seconds with nanosecond precision. The timezone offset will
be used to convert into UTC.`

The following result was unexpected:


(do
  (require '[clojure.edn :as edn])
  (require '[clojure.instant :refer [read-instant-timestamp]])
  (let [instant "#inst \"1970-01-01T00:00:09.999-00:00\""
        reader-map {'inst #'read-instant-timestamp}]
    ;; This binding is not appearing to do anything.
    (binding [*data-readers* reader-map]
      ;; prints java.util.Date -- unexpected
      (->> instant edn/read-string class println)
      ;; prints java.sql.Timestamp -- as desired
      (->> instant (edn/read-string {:readers reader-map}) class println))))

How can I use the *data-readers* binding? Clojure version 1.5.1.


Solution

  • The *data-readers* dynamic var seems to apply to the read-string and read functions from clojure.core only.

    (require '[clojure.instant :refer [read-instant-timestamp]])
    (let [instant "#inst \"1970-01-01T00:00:09.999-00:00\""
          reader-map {'inst #'read-instant-timestamp}]
      ;; This will read a java.util.Date
      (->> instant read-string class println)
      ;; This will read a java.sql.Timestamp
      (binding [*data-readers* reader-map]
        (->> instant read-string class println)))
    

    Browsing through the source code for clojure.edn reader here, I couldn't find anything that would indicate that the same *data-readers* var is used at all there.

    clojure.core's functions read and read-string use LispReader (which uses the value from *data-readers*), while the functions from clojure.edn use the EdnReader.

    This edn library is relatively new in Clojure so that might be the reason why the documentation string is not specific enough regarding edn vs. core reader, which can cause this kind of confusion.

    Hope it helps.