Liking cljdoc? Tell your friends :D

jsonista Continuous Integration status cljdoc badge

jsonissa / jsonista / jsoniin, jsonilla / jsonilta / jsonille

Clojure library for fast JSON encoding and decoding.

Faster than data.json or Cheshire while still having the necessary features for web development. Designed for use with Muuntaja.

Blogged:

Latest version

Clojars Project

Requires Java1.8+

Quickstart

(require '[jsonista.core :as j])

(j/write-value-as-string {"hello" 1})
;; => "{\"hello\":1}"

(j/read-value *1)
;; => {"hello" 1}

Examples

Using explicit ObjectMapper:

(-> {:dog {:name "Teppo"}}
    (j/write-value-as-bytes j/default-object-mapper)
    (j/read-value j/default-object-mapper))
;; => {"dog" {"name" "Teppo"}}

Using keyword keys:

(-> {:dog {:name "Teppo"}}
    (j/write-value-as-bytes j/keyword-keys-object-mapper)
    (j/read-value j/keyword-keys-object-mapper))
;; => {:dog {:name "Teppo"}}

Changing how map keys are encoded & decoded:

(defn reverse-string [s] (apply str (reverse s)))

(def mapper
  (j/object-mapper
    {:encode-key-fn (comp reverse-string name)
     :decode-key-fn (comp keyword reverse-string)}))

(-> {:kikka "kukka"}
    (doto prn)
    (j/write-value-as-string mapper)
    (doto prn)
    (j/read-value mapper)
    (prn))
; {:kikka "kukka"}
; "{\"akkik\":\"kukka\"}"
; {:kikka "kukka"}

Reading & writing directly into a file:

(def file (java.io.File. "hello.json"))

(j/write-value file {"hello" "world"})

(slurp file)
;; => "{\"hello\":\"world\"}"

(j/read-value file)
;; => {"hello" "world"}

Adding support for joda-time Classes, used by clj-time.

;; [com.fasterxml.jackson.datatype/jackson-datatype-joda "2.9.5"]
(import '[com.fasterxml.jackson.datatype.joda JodaModule])
(import '[org.joda.time LocalDate])

(def mapper
  (j/object-mapper
    {:modules [(JodaModule.)]}))

(j/write-value-as-string (LocalDate. 0) mapper)
; "\"1970-01-01\""

Tagged JSON

Adding support for lossless encoding data using tagged values. This includes both reading and writing support.

(def mapper
  (j/object-mapper
    {:encode-key-fn true
     :decode-key-fn true
     :modules [(jt/module
                 {:handlers {Keyword {:tag "!kw"
                                      :encode jt/encode-keyword
                                      :decode keyword}
                             PersistentHashSet {:tag "!set"
                                                :encode jt/encode-collection
                                                :decode set}}})]}))

(-> {:system/status #{:status/good}}
    (j/write-value-as-string mapper)
    (doto prn)
    (j/read-value mapper))
; prints "{\"system/status\":[\"!set\",[[\"!kw\",\"status/good\"]]]}"
; => {:system/status #{:status/good}}

In simple perf tests, tagged JSON is much faster than EDN or Transit.

Performance

  • All standard encoders and decoders are written in Java
  • Protocol dispatch with read-value & write-value
  • Jackson ObjectMapper is used directly
  • Small functions to support JVM Inlining

Measured using lein-jmh, see perf-tests for details.

Throughput, relative

encode

decode

Throughput, absolute

encode

decode

Throughput, data

➜  jsonista git:(master) ✗ lein jmh '{:file "benchmarks.edn", :type :quick, :format :table}'
{:% 100.0 :eta "00:00:00"}

:benchmark                     :name    :mode        :samples  :score              :score-error  :params
-----------------------------  -------  -----------  --------  ------------------  ------------  --------------
jsonista.jmh/encode-data-json  :encode  :throughput  5         2011809.137  ops/s  12600.809     {:size "10b"}
jsonista.jmh/encode-data-json  :encode  :throughput  5         382677.707   ops/s  2861.142      {:size "100b"}
jsonista.jmh/encode-data-json  :encode  :throughput  5         66403.631    ops/s  597.436       {:size "1k"}
jsonista.jmh/encode-data-json  :encode  :throughput  5         5480.185     ops/s  58.379        {:size "10k"}
jsonista.jmh/encode-data-json  :encode  :throughput  5         576.691      ops/s  15.682        {:size "100k"}
jsonista.jmh/encode-cheshire   :encode  :throughput  5         996875.314   ops/s  5688.227      {:size "10b"}
jsonista.jmh/encode-cheshire   :encode  :throughput  5         482130.613   ops/s  2685.181      {:size "100b"}
jsonista.jmh/encode-cheshire   :encode  :throughput  5         128936.005   ops/s  879.709       {:size "1k"}
jsonista.jmh/encode-cheshire   :encode  :throughput  5         12209.066    ops/s  94.285        {:size "10k"}
jsonista.jmh/encode-cheshire   :encode  :throughput  5         1258.157     ops/s  12.340        {:size "100k"}
jsonista.jmh/encode-jsonista   :encode  :throughput  5         6356105.348  ops/s  85360.100     {:size "10b"}
jsonista.jmh/encode-jsonista   :encode  :throughput  5         2010379.039  ops/s  67648.165     {:size "100b"}
jsonista.jmh/encode-jsonista   :encode  :throughput  5         409264.663   ops/s  3704.992      {:size "1k"}
jsonista.jmh/encode-jsonista   :encode  :throughput  5         34527.245    ops/s  251.065       {:size "10k"}
jsonista.jmh/encode-jsonista   :encode  :throughput  5         2934.595     ops/s  15.858        {:size "100k"}
jsonista.jmh/encode-jackson    :encode  :throughput  5         6275467.563  ops/s  123578.482    {:size "10b"}
jsonista.jmh/encode-jackson    :encode  :throughput  5         2092035.098  ops/s  11417.613     {:size "100b"}
jsonista.jmh/encode-jackson    :encode  :throughput  5         408380.251   ops/s  10912.350     {:size "1k"}
jsonista.jmh/encode-jackson    :encode  :throughput  5         31992.554    ops/s  230.781       {:size "10k"}
jsonista.jmh/encode-jackson    :encode  :throughput  5         2887.485     ops/s  12.491        {:size "100k"}
jsonista.jmh/decode-data-json  :decode  :throughput  5         2257552.949  ops/s  23890.443     {:size "10b"}
jsonista.jmh/decode-data-json  :decode  :throughput  5         498261.935   ops/s  2348.572      {:size "100b"}
jsonista.jmh/decode-data-json  :decode  :throughput  5         85191.855    ops/s  321.961       {:size "1k"}
jsonista.jmh/decode-data-json  :decode  :throughput  5         7763.264     ops/s  250.502       {:size "10k"}
jsonista.jmh/decode-data-json  :decode  :throughput  5         771.691      ops/s  6.559         {:size "100k"}
jsonista.jmh/decode-cheshire   :decode  :throughput  5         1099821.870  ops/s  14796.659     {:size "10b"}
jsonista.jmh/decode-cheshire   :decode  :throughput  5         544013.773   ops/s  4122.539      {:size "100b"}
jsonista.jmh/decode-cheshire   :decode  :throughput  5         109517.975   ops/s  911.623       {:size "1k"}
jsonista.jmh/decode-cheshire   :decode  :throughput  5         10017.553    ops/s  50.871        {:size "10k"}
jsonista.jmh/decode-cheshire   :decode  :throughput  5         1014.003     ops/s  18.609        {:size "100k"}
jsonista.jmh/decode-jsonista   :decode  :throughput  5         3476196.425  ops/s  21535.641     {:size "10b"}
jsonista.jmh/decode-jsonista   :decode  :throughput  5         792773.466   ops/s  8209.591      {:size "100b"}
jsonista.jmh/decode-jsonista   :decode  :throughput  5         160180.797   ops/s  554.940       {:size "1k"}
jsonista.jmh/decode-jsonista   :decode  :throughput  5         14151.302    ops/s  107.906       {:size "10k"}
jsonista.jmh/decode-jsonista   :decode  :throughput  5         1508.829     ops/s  5.855         {:size "100k"}
jsonista.jmh/decode-jackson    :decode  :throughput  5         5145394.434  ops/s  84237.662     {:size "10b"}
jsonista.jmh/decode-jackson    :decode  :throughput  5         1339393.911  ops/s  6660.176      {:size "100b"}
jsonista.jmh/decode-jackson    :decode  :throughput  5         274465.912   ops/s  1589.614      {:size "1k"}
jsonista.jmh/decode-jackson    :decode  :throughput  5         29607.044    ops/s  183.068       {:size "10k"}
jsonista.jmh/decode-jackson    :decode  :throughput  5         2539.491     ops/s  17.753        {:size "100k"}

Making a release

  • Update CHANGELOG.md and increment the version number in project.clj
  • Commit and push to Github
  • Create a Github release here
    • Use the version number of the release for the tag name
  • The Github Actions release workflow should fire and deploy a release to clojars

License

Copyright © 2016-2021 Metosin Oy.

Distributed under the Eclipse Public License 2.0.

Can you improve this documentation? These fine people already did:
Tommi Reiman, Miikka Koskinen, Joel Kaasinen, Juho Teperi, jeaye & kalekale
Edit on GitHub

cljdoc is a website building & hosting documentation for Clojure/Script libraries

× close