Skip to content

Instantly share code, notes, and snippets.

@viesti
Created July 29, 2022 16:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save viesti/403e3a67e2bc1add10cf3365ede510bc to your computer and use it in GitHub Desktop.
Save viesti/403e3a67e2bc1add10cf3365ede510bc to your computer and use it in GitHub Desktop.
Keep the order of keys from a JSON object
0% cat bb.edn
{:deps {org.flatland/ordered {:mvn/version "1.15.10"}
org.clojure/data.json {:mvn/version "2.4.0"}}}
0% cat ordered.clj
(ns ordered
(:require [flatland.ordered.map :as ordered-map]
[clojure.data.json :as data-json])
(:import (java.io PushbackReader)))
;; Taken from https://github.com/clojure/data.json/blob/master/src/main/clojure/clojure/data/json.clj#L295-L317
;; and modified to use ordered-map, instead of (transient {})
(defn read-object-ordered [^PushbackReader stream options]
;; Expects to be called with the head of the stream AFTER the
;; opening bracket.
(let [key-fn (get options :key-fn)
value-fn (get options :value-fn)]
(loop [result (ordered-map/ordered-map)]
(if-let [key (#'data-json/read-key stream)]
(let [key (cond-> key key-fn key-fn)
value (#'data-json/-read stream true nil options)
r (if value-fn
(let [out-value (value-fn key value)]
(if-not (= value-fn out-value)
(assoc result key out-value)
result))
(assoc result key value))]
(data-json/codepoint-case (int (#'data-json/next-token stream))
\, (recur r)
\} r
(throw (Exception. "JSON error (missing entry in object)"))))
(let [r result]
(if (empty? r)
r
(throw (Exception. "JSON error empty entry in object is not allowed"))))))))
(println (-> (slurp "test.json") (data-json/read-str) keys))
;; Replace clojure.data.json/read-object with a version that maintains JSON object key order via flatland.ordered.map/ordered-map
(alter-var-root #'data-json/read-object (constantly read-object-ordered))
(println (-> (slurp "test.json") (data-json/read-str) keys))
0% cat test.json
{"1": 1, "2": 2, "3": 3, "4":4, "5": 5, "6": 6, "7": 7, "8": 8, "9": 9}
0% bb ordered.clj
(9 3 4 8 7 5 6 1 2)
(1 2 3 4 5 6 7 8 9)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment