{"id":13442382,"url":"https://github.com/dakrone/cheshire","last_synced_at":"2025-05-11T03:51:06.640Z","repository":{"id":708622,"uuid":"1516467","full_name":"dakrone/cheshire","owner":"dakrone","description":"Clojure JSON and JSON SMILE (binary json format) encoding/decoding","archived":false,"fork":false,"pushed_at":"2025-04-15T19:17:21.000Z","size":1252,"stargazers_count":1508,"open_issues_count":52,"forks_count":155,"subscribers_count":29,"default_branch":"master","last_synced_at":"2025-05-08T17:17:24.345Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://github.com/dakrone/cheshire","language":"Clojure","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dakrone.png","metadata":{"files":{"readme":"README.md","changelog":"ChangeLog.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2011-03-23T14:11:48.000Z","updated_at":"2025-05-04T13:44:08.000Z","dependencies_parsed_at":"2023-07-06T11:31:43.194Z","dependency_job_id":"9207e607-a23f-4394-8909-11884fb49689","html_url":"https://github.com/dakrone/cheshire","commit_stats":{"total_commits":460,"total_committers":59,"mean_commits":7.796610169491525,"dds":0.2543478260869565,"last_synced_commit":"65c3750cc105c28413ecfbd111a40a541ca0169b"},"previous_names":[],"tags_count":49,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dakrone%2Fcheshire","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dakrone%2Fcheshire/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dakrone%2Fcheshire/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dakrone%2Fcheshire/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dakrone","download_url":"https://codeload.github.com/dakrone/cheshire/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253514567,"owners_count":21920334,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-31T03:01:45.058Z","updated_at":"2025-05-11T03:51:06.608Z","avatar_url":"https://github.com/dakrone.png","language":"Clojure","funding_links":[],"categories":["Clojure","Capabilities","JSON","Infrastructure"],"sub_categories":["Serialization"],"readme":"# Cheshire\n\n\u003cimg src=\"cheshire_puss.png\" title=\":)\" align=\"left\" /\u003e\n\u003c!-- use italics to distiguish quote from other text --\u003e\n\u003ci\u003e\n'Cheshire Puss,' she began, rather timidly, as she did not at all know\nwhether it would like the name: however, it only grinned a little\nwider.  'Come, it's pleased so far,' thought Alice, and she went\non. 'Would you tell me, please, which way I ought to go from here?'\n\n'That depends a good deal on where you want to get to,' said the Cat.\n\n'I don't much care where--' said Alice.\n\n'Then it doesn't matter which way you go,' said the Cat.\n\n'--so long as I get SOMEWHERE,' Alice added as an explanation.\n\n'Oh, you're sure to do that,' said the Cat, 'if you only walk long\nenough.'\n\u003c/i\u003e\n\u003cbr clear=all /\u003e\n\nCheshire is fast JSON encoding, based off of clj-json and\nclojure-json, with additional features like Date/UUID/Set/Symbol\nencoding and SMILE support.\n\n- [![Docs](https://cljdoc.org/badge/cheshire/cheshire)](https://cljdoc.org/d/cheshire/cheshire)\n- [![Clojars Project](https://img.shields.io/clojars/v/cheshire.svg)](https://clojars.org/cheshire)\n- [![Continuous Integration Tests](https://github.com/dakrone/cheshire/actions/workflows/test.yml/badge.svg)](https://github.com/dakrone/cheshire/actions/workflows/test.yml)\n- [![Vulnerability Scan](https://github.com/dakrone/cheshire/actions/workflows/nvd_scan.yml/badge.svg)](https://github.com/dakrone/cheshire/actions/workflows/nvd_scan.yml)\n- Cheshire is a built-in library in the [Babashka](https://babashka.org/) project\n\n## Why?\n\nclojure-json had really nice features (custom encoders), but was slow;\nclj-json had no features, but was fast. Cheshire encodes JSON fast,\nwith added support for more types and the ability to use custom\nencoders.\n\n## Usage\n\n```clojure\n[cheshire \"6.0.0\"]\n\n;; Cheshire v6.0.0 uses Jackson 2.18.3\n\n;; In your ns statement:\n(ns my.ns\n  (:require [cheshire.core :refer :all]))\n```\n\n### Encoding\n\n```clojure\n;; generate some json\n(generate-string {:foo \"bar\" :baz 5})\n\n;; write some json to a stream\n(generate-stream {:foo \"bar\" :baz 5} (clojure.java.io/writer \"/tmp/foo\"))\n\n;; generate some SMILE\n(generate-smile {:foo \"bar\" :baz 5})\n\n;; generate some JSON with Dates\n;; the Date will be encoded as a string using\n;; the default date format: yyyy-MM-dd'T'HH:mm:ss'Z'\n(generate-string {:foo \"bar\" :baz (java.util.Date. 0)})\n\n;; generate some JSON with Dates with custom Date encoding\n(generate-string {:baz (java.util.Date. 0)} {:date-format \"yyyy-MM-dd\"})\n\n;; generate some JSON with pretty formatting\n(generate-string {:foo \"bar\" :baz {:eggplant [1 2 3]}} {:pretty true})\n;; {\n;;   \"foo\" : \"bar\",\n;;   \"baz\" : {\n;;     \"eggplant\" : [ 1, 2, 3 ]\n;;   }\n;; }\n\n;; generate JSON escaping UTF-8\n(generate-string {:foo \"It costs £100\"} {:escape-non-ascii true})\n;; =\u003e \"{\\\"foo\\\":\\\"It costs \\\\u00A3100\\\"}\"\n\n;; generate JSON and munge keys with a custom function\n(generate-string {:foo \"bar\"} {:key-fn (fn [k] (.toUpperCase (name k)))})\n;; =\u003e \"{\\\"FOO\\\":\\\"bar\\\"}\"\n\n;; generate JSON without escaping the characters (by writing it to a file)\n(spit \"foo.json\" (json/generate-string {:foo \"bar\"} {:pretty true}))\n```\n\nIn the event encoding fails, Cheshire will throw a `JsonGenerationException`.\n\n#### Custom Pretty Printing Options\n\nIf Jackson's default pretty printing library is not what you desire, you can\nmanually create your own pretty printing class and pass to the `generate-string`\nor `encode` methods:\n\n```clojure\n(let [my-pretty-printer (create-pretty-printer\n                          (assoc default-pretty-print-options\n                                 :indent-arrays? true))]\n  (generate-string {:foo [1 2 3]} {:pretty my-pretty-printer}))\n```\n\nSee the `default-pretty-print-options` for a list of options that can be\nchanged.\n\n### Decoding\n\n```clojure\n;; parse some json\n(parse-string \"{\\\"foo\\\":\\\"bar\\\"}\")\n;; =\u003e {\"foo\" \"bar\"}\n\n;; parse some json and get keywords back\n(parse-string \"{\\\"foo\\\":\\\"bar\\\"}\" true)\n;; =\u003e {:foo \"bar\"}\n\n;; parse some json and munge keywords with a custom function\n(parse-string \"{\\\"foo\\\":\\\"bar\\\"}\" (fn [k] (keyword (.toUpperCase k))))\n;; =\u003e {:FOO \"bar\"}\n\n;; top-level strings are valid JSON too\n(parse-string \"\\\"foo\\\"\")\n;; =\u003e \"foo\"\n\n;; parse some SMILE (keywords option also supported)\n(parse-smile \u003cyour-byte-array\u003e)\n\n;; parse a stream (keywords option also supported)\n(parse-stream (clojure.java.io/reader \"/tmp/foo\"))\n\n;; parse a stream lazily (keywords option also supported)\n(parsed-seq (clojure.java.io/reader \"/tmp/foo\"))\n\n;; parse a SMILE stream lazily (keywords option also supported)\n(parsed-smile-seq (clojure.java.io/reader \"/tmp/foo\"))\n```\n\nIn 2.0.4 and up, Cheshire allows passing in a\nfunction to specify what kind of types to return, like so:\n\n```clojure\n;; In this example a function that checks for a certain key\n(decode \"{\\\"myarray\\\":[2,3,3,2],\\\"myset\\\":[1,2,2,1]}\" true\n        (fn [field-name]\n          (if (= field-name \"myset\")\n            #{}\n            [])))\n;; =\u003e {:myarray [2 3 3 2], :myset #{1 2}}\n```\nThe type must be \"transient-able\", so use either #{} or []\n\n\n### Custom Encoders\n\nCustom encoding is supported from 2.0.0 and up, if you encounter a\nbug, please open a github issue. From 5.0.0 onwards, custom encoding\nhas been moved to be part of the core namespace (not requiring a\nnamespace change)\n\n```clojure\n;; Custom encoders allow you to swap out the api for the fast\n;; encoder with one that is slightly slower, but allows custom\n;; things to be encoded:\n(ns myns\n  (:require [cheshire.core :refer :all]\n            [cheshire.generate :refer [add-encoder encode-str remove-encoder]]))\n\n;; First, add a custom encoder for a class:\n(add-encoder java.awt.Color\n             (fn [c jsonGenerator]\n               (.writeString jsonGenerator (str c))))\n\n;; There are also helpers for common encoding actions:\n(add-encoder java.net.URL encode-str)\n\n;; List of common encoders that can be used: (see generate.clj)\n;; encode-nil\n;; encode-number\n;; encode-seq\n;; encode-date\n;; encode-bool\n;; encode-named\n;; encode-map\n;; encode-symbol\n;; encode-ratio\n\n;; Then you can use encode from the custom namespace as normal\n(encode (java.awt.Color. 1 2 3))\n;; =\u003e \"java.awt.Color[r=1,g=2,b=3]\"\n\n;; Custom encoders can also be removed:\n(remove-encoder java.awt.Color)\n\n;; Decoding remains the same, you are responsible for doing custom decoding.\n```\n\n\u003ch3\u003eNOTE: `cheshire.custom` has been deprecated in version 5.0.0\u003c/h3\u003e\n\nCustom and Core encoding have been combined in Cheshire 5.0.0, so\nthere is no longer any need to require a different namespace depending\non what you would like to use.\n\n### Aliases\n\nThere are also a few aliases for commonly used functions:\n\n    encode -\u003e generate-string\n    encode-stream -\u003e generate-stream\n    encode-smile -\u003e generate-smile\n    decode -\u003e parse-string\n    decode-stream -\u003e parse-stream\n    decode-smile -\u003e parse-smile\n\n## Features\nCheshire supports encoding standard clojure datastructures, with a few\nadditions.\n\nCheshire encoding supports:\n\n### Clojure data structures\n- strings\n- lists\n- vectors\n- sets\n- maps\n- symbols\n- booleans\n- keywords (qualified and unqualified)\n- numbers (Integer, Long, BigInteger, BigInt, Double, Float, Ratio,\n  Short, Byte, primitives)\n- clojure.lang.PersistentQueue\n\n### Java classes\n- Date\n- UUID\n- java.sql.Timestamp\n- any java.util.Set\n- any java.util.Map\n- any java.util.List\n\n### Custom class encoding while still being fast\n\n### Also supports\n- Stream encoding/decoding\n- Lazy decoding\n- Pretty-printing JSON generation\n- Unicode escaping\n- Custom keyword coercion\n- Arbitrary precision for decoded values:\n\nCheshire will automatically use a BigInteger if needed for\nnon-floating-point numbers, however, for floating-point numbers,\nDoubles will be used unless the `*use-bigdecimals?*` symbol is bound\nto true:\n\n```clojure\n(ns foo.bar\n  (require [cheshire.core :as json]\n           [cheshire.parse :as parse]))\n\n(json/decode \"111111111111111111111111111111111.111111111111111111111111111111111111\")\n;; =\u003e 1.1111111111111112E32 (a Double)\n\n(binding [parse/*use-bigdecimals?* true]\n  (json/decode \"111111111111111111111111111111111.111111111111111111111111111111111111\"))\n;; =\u003e 111111111111111111111111111111111.111111111111111111111111111111111111M (a BigDecimal)\n```\n\n- Replacing default encoders for builtin types\n- [SMILE encoding/decoding](http://wiki.fasterxml.com/SmileFormatSpec)\n\n## Change Log\n\n[Change log](/ChangeLog.md) is available on GitHub.\n\n## Speed\n\nCheshire is about twice as fast as data.json.\n\nCheck out the benchmarks in `cheshire.test.benchmark`; or run `lein\nbenchmark`. If you have scenarios where Cheshire is not performing as\nwell as expected (compared to a different library), please let me\nknow.\n\n## Experimental things\n\nIn the `cheshire.experimental` namespace:\n\n```\n$ echo \"Hi. \\\"THIS\\\" is a string.\\\\yep.\" \u003e /tmp/foo\n\n$ lein repl\nuser\u003e (use 'cheshire.experimental)\nnil\nuser\u003e (use 'clojure.java.io)\nnil\nuser\u003e (println (slurp (encode-large-field-in-map {:id \"10\"\n                                                  :things [1 2 3]\n                                                  :body \"I'll be removed\"}\n                                                 :body\n                                                 (input-stream (file \"/tmp/foo\")))))\n{\"things\":[1,2,3],\"id\":\"10\",\"body\":\"Hi. \\\"THIS\\\" is a string.\\\\yep.\\n\"}\nnil\n```\n\n`encode-large-field-in-map` is used for streamy JSON encoding where\nyou want to JSON encode a map, but don't want the map in memory all at\nonce (it returns a stream). Check out the docstring for full usage.\n\nIt's experimental, like the name says. Based on [Tigris](http://github.com/dakrone/tigris).\n\n## Advanced customization for factories\nA custom factory can be used like so:\n\n```clojure\n(ns myns\n  (:require [cheshire.core :as core]\n            [cheshire.factory :as factory]))\n\n(binding [factory/*json-factory* (factory/make-json-factory\n                                  {:allow-non-numeric-numbers true})]\n  (json/decode \"{\\\"foo\\\":NaN}\" true))\n```\n\nSee the `default-factory-options` map in\n[factory.clj](/src/cheshire/factory.clj)\nfor a full list of configurable options. Smile and CBOR factories can also be\ncreated, and factories work exactly the same with custom encoding.\n\n## Future Ideas/TODOs\n- \u003cdel\u003emove away from using Java entirely, use Protocols for the\n  custom encoder\u003c/del\u003e (see custom.clj)\n- \u003cdel\u003eallow custom encoders\u003c/del\u003e (see custom.clj)\n- \u003cdel\u003efigure out a way to encode namespace-qualified keywords\u003c/del\u003e\n- \u003cdel\u003elook into overriding the default encoding handlers with custom handlers\u003c/del\u003e\n- \u003cdel\u003ebetter handling when java numbers overflow ECMAScript's numbers\n  (-2^31 to (2^31 - 1))\u003c/del\u003e\n- \u003cdel\u003ehandle encoding java.sql.Timestamp the same as\n  java.util.Date\u003c/del\u003e\n- \u003cdel\u003eadd benchmarking\u003c/del\u003e\n- get criterium benchmarking ignored for 1.2.1 profile\n- \u003cdel\u003e look into faster exception handling by pre-allocating an exception\n  object instead of creating one on-the-fly (maybe ask Steve?)\u003c/del\u003e\n- make it as fast as possible (ongoing)\n\n## License\nRelease under the MIT license. See LICENSE for the full license.\n\n## Thanks\nThanks go to Mark McGranaghan for clj-json and Jim Duey for the name\nsuggestion. :)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdakrone%2Fcheshire","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdakrone%2Fcheshire","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdakrone%2Fcheshire/lists"}