clojure.edn
functions by default only use data readers stored in clojure.core/default-data-readers
which, as of Clojure 1.5.1, provides readers for instant and UUID literals. If you want to use custom readers, you can do that by passing in a :readers
option; in particular, you can pass in *data-readers*
. This is documented in the docstring for clojure.edn/read
(the docstring for clojure.edn/read-string
refers to that for read
).
Here are some examples:
(require '[clojure.edn :as edn])
;; instant literals work out of the box:
(edn/read-string "#inst \"2013-06-08T01:00:00Z\"")
;= #inst "2013-06-08T01:00:00.000-00:00"
;; custom literals can be passed in in the opts map:
(edn/read-string {:readers {'foo identity}} "#foo :asdf")
;= :asdf
;; use current binding of *data-readers*
(edn/read-string {:readers *data-readers*} "...")
(The following section added in response to comments made by Richard Möhn in this GitHub issue's comment thread. The immediate question there is whether it is appropriate for a reader function to call eval
on the data passed in. I am not affiliated with the project in question; please see the ticket for details, as well as Richard's comments on the present answer.)
It is worth adding that *data-readers*
is implicitly populated from any data_readers.{clj,cljc}
files that Clojure finds at the root of the classpath at startup time. This can be convenient (it allows one to use custom tagged literals in Clojure source code and at the REPL), but it does mean that new data readers may appear in there with a change to a single dependency. Using an explicitly constructed reader map with clojure.edn
is a simple way to avoid surprises (which could be particularly nasty when dealing with untrusted input).
(Note that the implicit loading process does not result in any code being loaded immediately, or even when a tag mentioned in *data-readers*
is first encountered; the process which populates *data-readers*
creates empty namespaces with unbound Vars as placeholders, and to actually use those readers one still has to require
the relevant namespaces in user code.)