cheshire icon indicating copy to clipboard operation
cheshire copied to clipboard

:key-fn function does not run on all keys

Open shlomiv opened this issue 8 years ago • 2 comments

Hi, I am trying to jsonize some structure that has seqs as keys in a hashmap. I know json only likes strings for keys, so I'd like to control how the seq is being turned to a string.

Here is a simple example:

(json/generate-string
 {[1 2] 1, :a 5}
 {:key-fn (fn [k]
            (println "key" k)
            (str k))})

In here, only "key :a" is printed to screen and [1,2] implicitly turns into a string without running through the function.

shlomiv avatar Sep 18 '17 22:09 shlomiv

Hmm.. perhaps this should be renamed to something like "keyword-fn" or else it should run on all of them. I'll look.

dakrone avatar Sep 26 '17 16:09 dakrone

This has been open for a long time, but I ran into the same problem today. The documentation is a little vague in that :key-fn could be interpreted as a function to call on keys of maps, but it's actually a function called only on keys that are keywords in maps.

In my case, I am trying to hook the encoding of regexes in a map containing either string or regex keys, and was trying to use the key-fn for that.

(cheshire.core/generate-string foo {:key-fn (fn [v] (if (instance? java.util.regex.Pattern v) (str "/" v "/") v)})

and then:

(cheshire.core/parse-string foo {:key-fn (fn [v] (if (re-matches #"/.+/" v) (re-pattern (subs v 1 (dec (count v))) v)})

Doesn't work, because the key-fn is only called on keywords. Neither does adding a custom encoding, because custom encodings are only used for values, and are not applied to keys of maps.

The above is a simplification. I'm trying to avoid copying a huge map, and am actually using some low-level linkages with parse and generate with a generator/parser from the smile factory and direct i/o to/from streams.

ejschoen avatar May 31 '22 23:05 ejschoen