All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cheshire.custom.clj Maven / Gradle / Ivy

The newest version!
(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))




© 2015 - 2025 Weber Informatics LLC | Privacy Policy