I have a standard clojure map of things. The keys are keywords, and the values are arbitrary values. They can be nil
, numbers, strings, or any other kind of JVM object/class.
I need to know how to encode this map into JSON, so that "normal" values map to the usual JSON values (e.g. keywords -> strings, integers -> JSON numbers, etc.), while values of any other class map to the string representations of those values, like this:
{
:a 1
:b :myword
:c "hey"
:d <this is an "unprintable" java File object>
}
gets encoded thus:
{ "a": 1, "b": "myword", "c": "hey", "d": "#object[java.io.File 0x6944e53e foo]" }
I want to do this because my program is a CLI parsing library and I'm working with the caller of the library to build this map up, so I don't exactly know what types of data will be in it. However, I would like to print it to the screen all the same to aid the caller in debugging. I have tried to naively give this map to cheshire, but when I do, cheshire keeps choking with this error:
Exception in thread "main" com.fasterxml.jackson.core.JsonGenerationException: Cannot JSON encode object of class: class java.io.File: foo
Bonus: I am trying to keep my dependency counts down and I have already vetted cheshire as my JSON library, but full marks if you can find a way to do the above without it.
With cheshire you can add an encoder for java.lang.Object
user> (require ['cheshire.core :as 'cheshire])
nil
user> (require ['cheshire.generate :as 'generate])
nil
user> (generate/add-encoder Object (fn [obj jsonGenerator] (.writeString jsonGenerator (str obj))))
nil
user> (def json (cheshire/generate-string {:a 1 :b nil :c "hello" :d (java.io.File. "/tmp")}))
#'user/json
user> (println json)
{"a":1,"b":null,"c":"hello","d":"/tmp"}