Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
319 lines (265 sloc) 9.16 KB
(ns cheshire.custom
"DEPRECATED
Methods used for extending JSON generation to different Java classes.
Has the same public API as core.clj so they can be swapped in and out."
(:use [cheshire.factory])
(:require [cheshire.core :as core]
[cheshire.generate :as generate])
(:import (java.io BufferedWriter ByteArrayOutputStream StringWriter)
(java.util Date SimpleTimeZone)
(java.text SimpleDateFormat)
(java.sql Timestamp)
(com.fasterxml.jackson.dataformat.smile SmileFactory)
(com.fasterxml.jackson.core JsonFactory JsonGenerator
JsonGenerator$Feature
JsonGenerationException JsonParser)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;; DEPRECATED, DO NOT USE ;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; date format rebound for custom encoding
(def ^{:dynamic true :private true} *date-format*)
;; pre-allocated exception for fast-failing core attempt for custom encoding
(def ^{:private true} core-failure (JsonGenerationException.
"Cannot custom JSON encode object"))
(defprotocol JSONable
(to-json [t jg]))
(defn encode*
(^String [obj]
(encode* obj nil))
(^String [obj opt-map]
(binding [*date-format* (or (:date-format opt-map) default-date-format)]
(let [sw (StringWriter.)
generator (.createJsonGenerator
^JsonFactory (or *json-factory* json-factory) sw)]
(when (:pretty opt-map)
(.useDefaultPrettyPrinter generator))
(when (:escape-non-ascii opt-map)
(.enable generator JsonGenerator$Feature/ESCAPE_NON_ASCII))
(if obj
(to-json obj generator)
(.writeNull generator))
(.flush generator)
(.toString sw)))))
(def encode encode*)
(core/copy-arglists encode encode*)
(defn encode-stream*
(^String [obj ^BufferedWriter w]
(encode-stream* obj w nil))
(^String [obj ^BufferedWriter w opt-map]
(binding [*date-format* (or (:date-format opt-map) default-date-format)]
(let [generator (.createJsonGenerator
^JsonFactory (or *json-factory* json-factory) w)]
(when (:pretty opt-map)
(.useDefaultPrettyPrinter generator))
(when (:escape-non-ascii opt-map)
(.enable generator JsonGenerator$Feature/ESCAPE_NON_ASCII))
(to-json obj generator)
(.flush generator)
w))))
(def encode-stream encode-stream*)
(core/copy-arglists encode-stream encode-stream*)
(defn encode-smile*
(^bytes [obj]
(encode-smile* obj nil))
(^bytes [obj opt-map]
(binding [*date-format* (or (:date-format opt-map) default-date-format)]
(let [baos (ByteArrayOutputStream.)
generator (.createJsonGenerator ^SmileFactory
(or *smile-factory* smile-factory)
baos)]
(to-json obj generator)
(.flush generator)
(.toByteArray baos)))))
(def encode-smile encode-smile*)
(core/copy-arglists encode-smile encode-smile*)
;; there are no differences in parsing, but these are here to make
;; this a self-contained namespace if desired
(def parse core/decode)
(core/copy-arglists parse core/decode)
(def parse-string core/decode)
(core/copy-arglists parse-string core/decode)
(def parse-stream core/decode-stream)
(core/copy-arglists parse-stream core/decode-stream)
(def parse-smile core/decode-smile)
(core/copy-arglists parse-smile core/decode-smile)
(def parsed-seq core/parsed-seq)
(core/copy-arglists parsed-seq core/parsed-seq)
(def decode core/parse-string)
(core/copy-arglists decode core/parse-string)
(def decode-stream parse-stream)
(core/copy-arglists decode-stream core/parse-stream)
(def decode-smile parse-smile)
(core/copy-arglists decode-smile core/parse-smile)
;; aliases for encoding
(def generate-string encode*)
(core/copy-arglists generate-string encode*)
(def generate-string* encode*)
(core/copy-arglists generate-string* encode*)
(def generate-stream encode-stream*)
(core/copy-arglists generate-stream encode-stream*)
(def generate-stream* encode-stream*)
(core/copy-arglists generate-stream* encode-stream*)
(def generate-smile encode-smile*)
(core/copy-arglists generate-smile encode-smile*)
(def generate-smile* encode-smile*)
(core/copy-arglists generate-smile* encode-smile*)
;; Generic encoders, these can be used by someone writing a custom
;; encoder if so desired, after transforming an arbitrary data
;; structure into a clojure one, these can just be called.
(defn encode-nil
"Encode null to the json generator."
[_ ^JsonGenerator jg]
(.writeNull jg))
(defn encode-str
"Encode a string to the json generator."
[^String s ^JsonGenerator jg]
(.writeString jg (str s)))
(defn encode-number
"Encode anything implementing java.lang.Number to the json generator."
[^java.lang.Number n ^JsonGenerator jg]
(generate/encode-number n jg))
(defn encode-long
"Encode anything implementing java.lang.Number to the json generator."
[^Long n ^JsonGenerator jg]
(.writeNumber jg (long n)))
(defn encode-int
"Encode anything implementing java.lang.Number to the json generator."
[n ^JsonGenerator jg]
(.writeNumber jg (long n)))
(defn encode-ratio
"Encode a clojure.lang.Ratio to the json generator."
[^clojure.lang.Ratio n ^JsonGenerator jg]
(.writeNumber jg (double n)))
(defn encode-seq
"Encode a seq to the json generator."
[s ^JsonGenerator jg]
(.writeStartArray jg)
(doseq [i s]
(to-json i jg))
(.writeEndArray jg))
(defn encode-date
"Encode a date object to the json generator."
[^Date d ^JsonGenerator jg]
(let [sdf (SimpleDateFormat. *date-format*)]
(.setTimeZone sdf (SimpleTimeZone. 0 "UTC"))
(.writeString jg (.format sdf d))))
(defn encode-bool
"Encode a Boolean object to the json generator."
[^Boolean b ^JsonGenerator jg]
(.writeBoolean jg b))
(defn encode-named
"Encode a keyword to the json generator."
[^clojure.lang.Keyword k ^JsonGenerator jg]
(.writeString jg (if-let [ns (namespace k)]
(str ns "/" (name k))
(name k))))
(defn encode-map
"Encode a clojure map to the json generator."
[^clojure.lang.IPersistentMap m ^JsonGenerator jg]
(.writeStartObject jg)
(doseq [[k v] m]
(.writeFieldName jg (if (instance? clojure.lang.Keyword k)
(if-let [ns (namespace k)]
(str ns "/" (name k))
(name k))
(str k)))
(to-json v jg))
(.writeEndObject jg))
(defn encode-symbol
"Encode a clojure symbol to the json generator."
[^clojure.lang.Symbol s ^JsonGenerator jg]
(.writeString jg (str s)))
;; extended implementations for clojure datastructures
(extend nil
JSONable
{:to-json encode-nil})
(extend java.lang.String
JSONable
{:to-json encode-str})
;; This is lame, thanks for changing all the BigIntegers to BigInts
;; in 1.3 clojure/core :-/
(defmacro handle-bigint []
(when (not= {:major 1 :minor 2} (select-keys *clojure-version*
[:major :minor]))
`(extend clojure.lang.BigInt
JSONable
{:to-json ~'(fn encode-bigint
[^clojure.lang.BigInt n ^JsonGenerator jg]
(.writeNumber jg (.toBigInteger n)))})))
(handle-bigint)
(extend clojure.lang.Ratio
JSONable
{:to-json encode-ratio})
(extend Long
JSONable
{:to-json encode-long})
(extend Short
JSONable
{:to-json encode-int})
(extend Byte
JSONable
{:to-json encode-int})
(extend java.lang.Number
JSONable
{:to-json encode-number})
(extend clojure.lang.ISeq
JSONable
{:to-json encode-seq})
(extend clojure.lang.IPersistentVector
JSONable
{:to-json encode-seq})
(extend clojure.lang.IPersistentSet
JSONable
{:to-json encode-seq})
(extend clojure.lang.IPersistentList
JSONable
{:to-json encode-seq})
(extend java.util.Date
JSONable
{:to-json encode-date})
(extend java.sql.Timestamp
JSONable
{:to-json #(encode-date (Date. (.getTime ^java.sql.Timestamp %1)) %2)})
(extend java.util.UUID
JSONable
{:to-json encode-str})
(extend java.lang.Boolean
JSONable
{:to-json encode-bool})
(extend clojure.lang.Keyword
JSONable
{:to-json encode-named})
(extend clojure.lang.IPersistentMap
JSONable
{:to-json encode-map})
(extend clojure.lang.Symbol
JSONable
{:to-json encode-symbol})
(extend clojure.lang.Associative
JSONable
{:to-json encode-map})
(extend java.util.Map
JSONable
{:to-json encode-map})
(extend java.util.Set
JSONable
{:to-json encode-seq})
(extend java.util.List
JSONable
{:to-json encode-seq})
;; Utility methods to add and remove encoders
(defn add-encoder
"Provide an encoder for a type not handled by Cheshire.
ex. (add-encoder java.net.URL encode-string)
See encode-str, encode-map, etc, in the cheshire.custom
namespace for encoder examples."
[cls encoder]
(extend cls
JSONable
{:to-json encoder}))
(defn remove-encoder
"Remove encoder for a given type.
ex. (remove-encoder java.net.URL)"
[cls]
(alter-var-root #'JSONable #(assoc % :impls (dissoc (:impls %) cls)))
(clojure.core/-reset-methods JSONable))
You can’t perform that action at this time.