[Git][clojure-team/cheshire-clojure][upstream] New upstream version 6.2.1
Jérôme Charaoui (@lavamind)
gitlab at salsa.debian.org
Thu Nov 5 19:06:40 GMT 2026
Jérôme Charaoui pushed to branch upstream at Debian Clojure Maintainers / cheshire-clojure
Commits:
6ca48b0d by Jérôme Charaoui at 2026-11-04T19:18:12-05:00
New upstream version 6.2.1
- - - - -
23 changed files:
- + .clj-kondo/config.edn
- + .github/workflows/nvd_scan.yml
- + .github/workflows/test.yml
- .gitignore
- − .travis.yml
- ChangeLog.md
- README.md
- + cheshire_puss.png
- + nvd-helper/deps.edn
- + nvd-helper/nvd-clojure.edn
- + nvd-helper/suppressions.xml
- project.clj
- src/cheshire/core.clj
- src/cheshire/custom.clj
- src/cheshire/exact.clj
- src/cheshire/experimental.clj
- src/cheshire/factory.clj
- src/cheshire/generate.clj
- src/cheshire/generate_seq.clj
- src/cheshire/parse.clj
- test/cheshire/test/core.clj
- test/cheshire/test/custom.clj
- test/cheshire/test/generative.clj
Changes:
=====================================
.clj-kondo/config.edn
=====================================
@@ -0,0 +1 @@
+{:exclude-files "test/cheshire/test/generative.clj"}
=====================================
.github/workflows/nvd_scan.yml
=====================================
@@ -0,0 +1,82 @@
+name: Vulnerability Scan
+
+on:
+ schedule:
+ # daily
+ - cron: "5 0 * * *"
+ push:
+ branches:
+ - master
+
+jobs:
+ nvd-scan:
+ environment: nvd
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout at v4
+
+ - name: Setup Java
+ uses: actions/setup-java at v4
+ with:
+ distribution: 'temurin'
+ java-version: 21
+
+ - name: Install Clojure Tools
+ uses: DeLaGuardo/setup-clojure at 13.2
+ with:
+ cli: 'latest'
+ lein: 'latest'
+
+ - name: Generate Cache Key File
+ run: |
+ # We are using RELEASE for deps, grab current versions for CI cache key
+ mkdir -p target
+ VERSION_NVD_CLOJURE=$(curl -s --fail https://clojars.org/api/artifacts/nvd-clojure/nvd-clojure | jq -r '.recent_versions[0].version')
+ VERSION_DEPENDENCY_CHECK=$(curl -s --fail 'https://search.maven.org/solrsearch/select?q=g:org.owasp+AND+a:dependency-check-core&core=gav&rows=1&wt=json' | jq '.response.docs[0].v')
+ echo "nvd-clojure=${VERSION_NVD_CLOJURE}" > target/ci-versions.txt
+ echo "dependency-check=${VERSION_DEPENDENCY_CHECK}" >> target/ci-versions.txt
+ cat target/ci-versions.txt
+ working-directory: nvd-helper
+
+ - name: Restore NVD DB & Clojure Deps Cache
+ # nvd caches its db under ~/.m2/repository/org/owasp so that it can
+ # conveniently be cached with deps
+ uses: actions/cache/restore at v4
+ with:
+ path: |
+ ~/.m2/repository
+ ~/.deps.clj
+ ~/.gitlibs
+ key: |
+ nvd-${{ hashFiles('nvd-helper/target/ci-versions.txt') }}
+ restore-keys: |
+ nvd-
+
+ - name: Tools Versions
+ run: |
+ echo "java -version"
+ java -version
+ echo "lein --version"
+ lein --version
+ echo "clojure --version"
+ clojure --version
+
+ - name: Run NVD Scanner
+ env:
+ NVD_API_TOKEN: ${{ secrets.NVD_API_TOKEN }}
+ run: clojure -J-Dclojure.main.report=stderr -J-Danalyzer.ossindex.enabled=false -M -m nvd.task.check "nvd-clojure.edn" "$(cd ..; lein classpath)"
+ working-directory: nvd-helper
+
+ - name: Save NVD DB & Clojure Deps Cache
+ if: always() # always cache regardless of outcome of nvd scan
+ uses: actions/cache/save at v4
+ with:
+ path: |
+ ~/.m2/repository
+ ~/.deps.clj
+ ~/.gitlibs
+ # we tack on github.run_id to uniquely identify the cache
+ # the next cache restore will find the best (and most current) match
+ key: |
+ nvd-${{ hashFiles('nvd-helper/target/ci-versions.txt') }}-${{ github.run_id }}
=====================================
.github/workflows/test.yml
=====================================
@@ -0,0 +1,105 @@
+name: Test
+
+on:
+ push:
+ branches:
+ - master
+ pull_request:
+ branches:
+ - master
+
+jobs:
+ lint:
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout at v4
+
+ - name: Clojure deps cache
+ uses: actions/cache at v4
+ with:
+ path: |
+ ~/.m2/repository
+ key: ${{ runner.os }}-cljdeps-${{ hashFiles('project.clj') }}
+ restore-keys: ${{ runner.os }}-cljdeps-
+
+ - name: Setup Java
+ uses: actions/setup-java at v4
+ with:
+ distribution: 'temurin'
+ # We also lint with eastwood, using latest jdk release can help find
+ # JDK deprecations
+ java-version: 24
+
+ - name: Install Clojure Tools
+ uses: DeLaGuardo/setup-clojure at 13.2
+ with:
+ lein: 'latest'
+
+ - name: Download deps
+ run: lein all deps
+
+ - name: Tools Versions
+ run: |
+ echo "java -version"
+ java -version
+ echo "lein --version"
+ lein --version
+
+ - name: Lint with eastwood
+ run: lein eastwood
+
+ - name: Lint with clj-kondo
+ run: lein clj-kondo-lint
+
+ test:
+ runs-on: ${{ matrix.os }}-latest
+ strategy:
+ fail-fast: false
+ matrix:
+ os: [ ubuntu, windows ]
+ java-version: [ '8', '11', '17', '21', '24' ]
+
+ defaults:
+ run:
+ # Windows lein.ps1 script is problematic, force lein.bat by using cmd shell
+ shell: ${{ matrix.os == 'windows' && 'cmd' || 'bash' }}
+
+ name: test ${{matrix.os}} jdk${{matrix.java-version}}
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout at v4
+
+ - name: Clojure deps cache
+ uses: actions/cache at v4
+ with:
+ path: |
+ ~/.m2/repository
+ key: ${{ runner.os }}-cljdeps-${{ hashFiles('project.clj') }}
+ restore-keys: ${{ runner.os }}-cljdeps-
+
+ - name: Setup Java
+ uses: actions/setup-java at v4
+ with:
+ distribution: 'temurin'
+ java-version: ${{ matrix.java-version }}
+
+ - name: Install Clojure Tools
+ uses: DeLaGuardo/setup-clojure at 13.2
+ with:
+ lein: 'latest'
+
+ - name: Download deps
+ run: lein all deps
+
+ - name: Tools Versions
+ run: |
+ echo "java -version"
+ java -version
+ echo "lein --version"
+ lein --version
+
+ - name: Run Tests
+ run: lein all test :all
=====================================
.gitignore
=====================================
@@ -4,7 +4,7 @@ coref
classes/*
.lein-failures
.lein-deps-sum
-target/*
+target
pom.xml*
doc*
.lein*
@@ -12,3 +12,7 @@ doc*
.idea
*.iml
.DS_Store
+.lsp
+.eastwood
+.cache
+.cpcache
=====================================
.travis.yml deleted
=====================================
@@ -1,11 +0,0 @@
-language: clojure
-lein: lein
-script: lein all test :all
-branches:
- only:
- - master
-jdk:
- - openjdk8
- - openjdk9
- - openjdk10
- - openjdk11
=====================================
ChangeLog.md
=====================================
@@ -1,105 +1,675 @@
-## Changes between Cheshire 5.8.1 and 5.9.0
+<!--
+The changelog is currently manually updated
+
+Changes should always be included when potentially interesting to users.
+
+Each change should include:
+- if possible/practical/meaningful, link to issue (else link to PR else link to commit)
+- short description of change
+- link to github profile of author of change
+
+Place any breaking changes under a "BREAKING changes" list item
+-->
+
+# v6.2.1 - 2026-11-02
+
+* Update Jackson dependencies to v2.21.8
+ [#255](https://github.com/dakrone/cheshire/pull/255)
+ ([@ray1729](https://github.com/ray1729))
+
+[commit log](https://github.com/dakrone/cheshire/compare/6.2.0...6.2.1)
+
+# v6.2.0 - 2026-03-19
+
+* Add support for JsonReadFeature `ALLOW_TRAILING_COMMA`
+ [#245](https://github.com/dakrone/cheshire/pull/245)
+ ([@esnyder](https://github.com/esnyder))
+* Update Jackson dependencies to v2.21.1
+ [#250](https://github.com/dakrone/cheshire/pull/250)
+ ([@dbasedow0000](https://github.com/dbasedow0000))
+
+[commit log](https://github.com/dakrone/cheshire/compare/6.1.0...6.2.0)
+
+# v6.1.0 - 2025-09-01
+
+* Add encoding for `java.time.Instant`
+ [#241](https://github.com/dakrone/cheshire/pull/241)
+ ([@mthl](https://github.com/mthl))
+* Add encoding for `java.util.concurrent.atomic.AtomicInteger`
+ [#243](https://github.com/dakrone/cheshire/pull/243)
+ ([@mthl](https://github.com/mthl))
+* Add encoding for `java.util.concurrent.atomic.AtomicLong`
+ [#243](https://github.com/dakrone/cheshire/pull/243)
+ ([@mthl](https://github.com/mthl))
+* Update Jackson dependencies to v2.20.0
+ ([@dakrone](https://github.com/dakrone))
+
+[commit log](https://github.com/dakrone/cheshire/compare/6.0.0...6.1.0)
+
+# v6.0.0 - 2025-04-15
+
+* **BREAKING** changes
+ * [#217](https://github.com/dakrone/cheshire/issues/217):
+ Windows only: pretty printing now consistently uses JVM's OS default of `\r\n` for `:line-break`
+ ([@lread](https://github.com/lread))
+* Bump minimum JDK version from v7 to v8
+ ([@lread](https://github.com/lread))
+* Bump Jackson to v2.18.3
+ ([@lread](https://github.com/lread))
+* [#209](https://github.com/dakrone/cheshire/pull/209):
+ Fix type hints on `generate-stream`
+ ([@souenzzo](https://github.com/souenzzo)])
+* [#210](https://github.com/dakrone/cheshire/issues/210):
+ Expose new Jackson processing limits via factory options
+ ([@lread](https://github.com/lread))
+* [#215](https://github.com/dakrone/cheshire/issues/215):
+ Add `:escape-non-ascii` to factory options
+ ([@lread](https://github.com/lread))
+* Internal maintenance:
+ * [#212](https://github.com/dakrone/cheshire/issues/212):
+ Migrate away from usages of deprecated Jackson
+ ([@lread](https://github.com/lread))
+* Quality
+ * [#114](https://github.com/dakrone/cheshire/issues/114):
+ Freshen changelog and add missing history
+ ([@lread](https://github.com/lread))
+ * [#214](https://github.com/dakrone/cheshire/issues/214):
+ Add CI on GitHub Actions and with test coverage on Linux and Windows
+ ([@lread](https://github.com/lread))
+ * [#222](https://github.com/dakrone/cheshire/issues/222):
+ Add linting
+ ([@lread](https://github.com/lread))
+ * [#226](https://github.com/dakrone/cheshire/issues/226):
+ Add vulnerability scanning for cheshire dependencies
+ ([@lread](https://github.com/lread))
+
+[commit log](https://github.com/dakrone/cheshire/compare/5.13.0...6.0.0)
+
+# v5.13.0 - 2024-04-01
+
+* Bump Jackson to v2.17.0
+ ([@antonmos](https://github.com/antonmos))
+
+[commit log](https://github.com/dakrone/cheshire/compare/5.12.0...5.13.0)
+
+# v5.12.0 - 2023-09-19
+
+* Bump Jackson to v2.15.2
+ ([@jakepearson](https://github.com/jakepearson))
+
+[commit log](https://github.com/dakrone/cheshire/compare/5.11.0...5.12.0)
+
+# v5.11.0 - 2022-05-26
+
+* Bump Jackson to v2.13.3
+ ([@dakrone](https://github.com/dakrone))
+
+[commit log](https://github.com/dakrone/cheshire/compare/5.10.2...5.11.0)
+
+# v5.10.2 - 2022-01-24
+
+* [ab52d71](https://github.com/dakrone/cheshire/commit/ab52d71):
+ Add data reader `#cheshire/json` tag to generate JSON strings
+ ([@mrroman](https://github.com/mrroman))
+* [#187](https://github.com/dakrone/cheshire/pull/187):
+ Exclude jackson-data-bind dependency, cheshire doesn't use and it has triggered many CVEs
+ ([@technomancy](https://github.com/technomancy))
+
+[commit log](https://github.com/dakrone/cheshire/compare/5.10.1...5.10.2)
+
+# v5.10.1 - 2021-07-13
+
+* Bump Jackson to v2.12.4
+ ([@dakrone](https://github.com/dakrone))
+* [#170](https://github.com/dakrone/cheshire/pull/170):
+ Add `:strict-duplicate-detection` to factory options
+ ([@sjamaan](https://github.com/sjamaan))
+* [7040a4a](https://github.com/dakrone/cheshire/commit/7040a4a):
+ Optimization: replace internal usage of `doseq` with `reduce`
+ ([@nilern](https://github.com/nilern))
+
+[commit log](https://github.com/dakrone/cheshire/compare/5.10.0...5.10.1)
+
+# v5.10.0 - 2020-02-04
+
+* Bump Jackson to v2.10.2
+ ([@willcohen](https://github.com/willcohen))
+* [#150](https://github.com/dakrone/cheshire/pull/150):
+ Bump tigris to v0.1.2
+ ([@aiba](https://github.com/aiba))
+* [9d69b18](https://github.com/dakrone/cheshire/commit/9d69b18):
+ Fix misplaced docstring (found with clj-kondo)
+ ([@borkdude](https://github.com/borkdude))
+
+[commit log](https://github.com/dakrone/cheshire/compare/5.9.0...5.10.0)
+
+# v5.9.0 - 2019-08-05
+
+* Bump Jackson to v2.9.9
+ ([@kumarshantanu](https://github.com/kumarshantanu))
+* [b980d98](https://github.com/dakrone/cheshire/commit/b980d98):
+ Add `parse-stream-strict` to parse streams strictly rather than lazily
+ ([@nilern](https://github.com/nilern))
+* [#141](https://github.com/dakrone/cheshire/pull/141):
+ Chunk size for lazy seqs is now configurable
+ ([@johnswanson](https://github.com/johnswanson) & ([@cayennes](https://github.com/cayennes)))
+* [fe453ea](https://github.com/dakrone/cheshire/commit/fe453ea):
+ Fix misplaced docstring (found with clj-kondo)
+ ([@borkdude](https://github.com/borkdude))
+
+[commit log](https://github.com/dakrone/cheshire/compare/5.8.1...5.9.0)
+
+# v5.8.1 - 2018-09-21
+
+* Bump Jackson to v2.9.6
+ ([@ikitommi](https://github.com/ikitommi))
+* [4ceaf16](https://github.com/dakrone/cheshire/commit/4ceaf16):
+ Add `:quote-field-names` factory option to control quoting field names in encoding
+ ([@crazymerlyn](https://github.com/crazymerlyn))
+* [#106](https://github.com/dakrone/cheshire/issues/106):
+ Respect `:indent-objects?` `false` in pretty printer
+ ([@crazymerlyn](https://github.com/crazymerlyn))
+* [#128](https://github.com/dakrone/cheshire/issues/128):
+ Add dependency on tools.namespace for clojure 1.9 compatability
+ ([@dakrone](https://github.com/dakrone))
+* [#131](https://github.com/dakrone/cheshire/issues/131):
+ Fix type hint in `parse-string-strict`
+ ([@spieden](https://github.com/spieden))
-* Add `parse-stream-strict` to parse streams strictly rather than lazily
-* Bump Jackson dependencies to 2.9.9
-* Chunk size for lazy seqs is now configurable
+[commit log](https://github.com/dakrone/cheshire/compare/5.8.0...5.8.1)
-## Changes between Cheshire 5.8.0 and 5.8.1
+# v5.8.0 - 2017-08-15
-* Add `:quote-field-names` parameter to control quoting field names in encoding
+* Bump Jackson to v2.9.0
+ ([@brabster](https://github.com/brabster))
+* [#111](https://github.com/dakrone/cheshire/issues/112):
+ Fix type hints for un-imported classes
+ ([@dakrone](https://github.com/dakrone))
+* Add `cheshire.exact` namespace for exactly-once decoding
+ ([@lucacervello](https://github.com/lucacervello))
+* Add only valid json option when parsing json
+ ([@lucacervello](https://github.com/lucacervello))
-## Changes between Cheshire 5.7.2 and 5.8.0
+[commit log](https://github.com/dakrone/cheshire/compare/5.7.1...5.8.0)
-* Fix type hints for un-imported classes
-* Update Jackson dependencies to mitigate vulnerability https://github.com/FasterXML/jackson-databind/issues/1599
-* Correct spelling in documentation
-* Add `cheshire.exact` namespace for exactly-once decoding
-* Bump Jackson dependencies to 2.9.0
+# v5.7.1 - 2017-04-20
-## Changes between Cheshire 5.6.3 and 5.6.2
+* [#112](https://github.com/dakrone/cheshire/issues/112):
+ Remove `condp` usage in `generate` to avoid memory issues for lazy seqs
+ ([@senior](https://github.com/senior))
-* Fix float coercion when encoding
+[commit log](https://github.com/dakrone/cheshire/compare/5.7.0...5.7.1)
-## Changes between Cheshire 5.6.2 and 5.6.1
+# v5.7.0 - 2017-01-13
-* Fix type hints for newer clojure version
-* Bump Jackson dependencies
+* Bump Jackson to v2.8.6
+ ([@dakrone](https://github.com/dakrone))
+* [847077d](https://github.com/dakrone/cheshire/commit/847077d):
+ Allow non const booleans `decode` for `key-fn`
+ ([@bfabry](https://github.com/bfabry))
-## Changes between Cheshire 5.6.1 and 5.6.0
+[commit log](https://github.com/dakrone/cheshire/compare/5.6.3...5.7.0)
-* Fix javac target for 1.6 compatibility
+# v5.6.3 - 2016-06-27
-## Changes between Cheshire 5.6.0 and 5.5.0
+* [#97](https://github.com/dakrone/cheshire/issues/97):
+ Fix float coercion when encoding
+ ([@dakrone](https://github.com/dakrone))
-* Fixes for type hinting
-* Make :pretty option configurable to use custom pretty printer
+[commit log](https://github.com/dakrone/cheshire/compare/5.6.2...5.6.3)
-## Changes between Cheshire 5.5.0 and 5.5.0
+# v5.6.2 - 2016-06-20
-* Bump Jackson dependencies
+* Bump Jackson to v2.7.5
+ ([@dakrone](https://github.com/dakrone))
+* [e949e00](https://github.com/dakrone/cheshire/commit/e949e00)
+ Fix type hints for newer clojure version
+ ([@pjstadig](https://github.com/pjstadig))
-## Changes between Cheshire 5.4.0 and 5.3.2
+[commit log](https://github.com/dakrone/cheshire/compare/5.6.1...5.6.2)
-* Add CBOR encoding/decoding
-* Add docstrings for clojure-json aliases
-* Add default encoder for java.lang.Character
-* Add sequential write support
-* Bump dependencies
+# v5.6.1 - 2016-04-12
-## Changes between Cheshire 5.3.1 and 5.3.0
+* [0d90f44](https://github.com/dakrone/cheshire/commit/0d90f44):
+ Tell javac to generate Java 1.6 compatible class files
+ ([@Deraen](https://github.com/Deraen))
-* Fix string parsing for 1 and 2 arity methods
-* Bump Jackson to 2.3.1
+[commit log](https://github.com/dakrone/cheshire/compare/5.6.0...5.6.1)
-## Changes between Cheshire 5.3.0 and 5.2.0
+# v5.6.0 - 2016-04-10
-* Dependencies have been bumped
-* Parse streams strictly by default to avoid scoping issues
+* Bump Jackson to v2.7.3
+ ([@niwinz](https://github.com/niwinz))
+* [#96](https://github.com/dakrone/cheshire/pull/96)
+ Fixes for type hinting
+ ([@ahjones](https://github.com/ahjones))
+* [77f9813](https://github.com/dakrone/cheshire/commit/77f9813)
+ Support byte-array encoding/decoding
+ ([@blendmaster](https://github.com/blendmaster))
+* [#99](https://github.com/dakrone/cheshire/issues/99):
+ Make `:pretty` option configurable to use custom pretty printer
+ ([@prayerslayer](https://github.com/prayerslayer))
-## Changes between Cheshire 5.2.0 and 5.1.2
+[commit log](https://github.com/dakrone/cheshire/compare/5.5.0...5.6.0)
-* Bump tigris to 0.1.1 to use PushbackReader
-* Lazily decode top-level arrays (thanks ztellman)
+# v5.5.0 - 2015-05-28
-## Changes between Cheshire 5.1.2 and 5.1.1
+* Bump Jackson to v2.5.3
+ ([@laczoka](https://github.com/laczoka))
+* [7124611](https://github.com/dakrone/cheshire/commit/7124611):
+ Add docstrings for clojure-json aliases
+ ([@danielcompton](https://github.com/danielcompton))
+* [#72](https://github.com/dakrone/cheshire/issues/72)
+ Address Jackson deprecations
+ ([@dakrone](https://github.com/dakrone))
-* Add experimental namespace
-* Bump Jackson deps to 2.2.1
+[commit log](https://github.com/dakrone/cheshire/compare/5.4.0...5.5.0)
-## Changes between Cheshire 5.1.1 and 5.1.0
+# v5.4.0 - 2014-12-10
-* Remove all reflection (thanks amalloy)
-* Fixed custom encoder helpers (thanks lynaghk)
+* Bump Jackson to v2.4.4
+ ([@dakrone](https://github.com/dakrone))
+* [ffac717](https://github.com/dakrone/cheshire/commit/ffac717):
+ Add CBOR encoding/decoding
+ ([@dakrone](https://github.com/dakrone))
+* [#53](https://github.com/dakrone/cheshire/issues/53):
+ Add default encoder for `java.lang.Character`
+ ([@dakrone](https://github.com/dakrone))
+* [56662c2](https://github.com/dakrone/cheshire/commit/56662c2):
+ Add sequential write support
+ ([@kostafey](https://github.com/kostafey))
-## Changes between Cheshire 5.1.0 and 5.0.2
+[commit log](https://github.com/dakrone/cheshire/compare/5.3.1...5.4.0)
-* Allow custom keyword function for encoding (thanks goodwink)
+# v5.3.1 - 2014-01-10
-## Changes between Cheshire 5.0.2 and 5.0.1
+* Bump Jackson to v2.3.1
+ ([@dakrone](https://github.com/dakrone))
+* [#46](https://github.com/dakrone/cheshire/issues/46)
+& [#48](https://github.com/dakrone/cheshire/issues/48):
+ Fix string parsing for 1 and 2 arity methods
+ ([@maxnoel](https://github.com/maxnoel))
-* Bump Jackson dependency from 2.1.1 to 2.1.3
+[commit log](https://github.com/dakrone/cheshire/compare/5.3.0...5.3.1)
-* Add more type hinting (thanks to ztellman)
+# v5.3.0 - 2013-12-18
-## Changes between Cheshire 5.0.0 and 5.0.1
+* Bump Jackson to v2.3.0
+ ([@dakrone](https://github.com/dakrone))
+* [#48](https://github.com/dakrone/cheshire/issues/48):
+ Parse streams strictly by default to avoid scoping issues
+ ([@dakrone](https://github.com/dakrone))
-* Protocol custom encoders now take precedence over regular map
- encoders.
+[commit log](https://github.com/dakrone/cheshire/compare/5.2.0...5.3.0)
-* Benchmarking is now a separate lein command, not a test selector.
+# v5.2.0 - 2013-05-22
+
+* Bump tigris to v0.1.1 to use `PushbackReader`
+ ([@dakrone](https://github.com/dakrone))
+* Performance tweaks
+ ([@ztellman](https://github.com/ztellman))
+
+[commit log](https://github.com/dakrone/cheshire/compare/5.1.2...5.2.0)
+
+# v5.1.2 - 2013-05-17
+
+* Bump Jackson to v2.2.1
+ ([@dakrone](https://github.com/dakrone))
+* [ce4ff056](https://github.com/dakrone/cheshire/commit/ce4ff056):
+ Add experimental namespace
+ ([@dakrone](https://github.com/dakrone))
+
+[commit log](https://github.com/dakrone/cheshire/compare/5.1.1...5.1.2)
+
+# v5.1.1 - 2013-04-12
+
+* [e4cc3b3](https://github.com/dakrone/cheshire/commit/e4cc3b3):
+ Remove all reflection
+ ([@amalloy](https://github.com/amalloy))
+* [6d78a56](https://github.com/dakrone/cheshire/commit/6d78a56):
+ Fixed custom encoder helpers
+ ([@lynaghk](https://github.com/lynaghk))
+
+[commit log](https://github.com/dakrone/cheshire/compare/5.1.0...5.1.1)
+
+# v5.1.0 - 2013-04-04
-## Changes between Cheshire 5.0.0 and 4.0.x
+* Bump Jackson to v2.1.4
+ ([@dakrone](https://github.com/dakrone))
+* [c5f0be3](https://github.com/dakrone/cheshire/commit/c5f0be3):
+ Allow custom keyword function for encoding
+ ([@goodwink](https://github.com/goodwink))
-### Custom Encoders Changes
+[commit log](https://github.com/dakrone/cheshire/compare/5.0.2...5.1.0)
-Custom encoder functions were moved to the `cheshire.generate` namespace:
+# v5.0.2 - 2013-02-19
- * `cheshire.custom/add-encoder` is now `cheshire.generate/add-encoder`
- * `cheshire.custom/remove-encoder` is now `cheshire.generate/remove-encoder`
+* Bump Jackson to v2.1.3
+ ([@dakrone](https://github.com/dakrone))
+* [03aff88](https://github.com/dakrone/cheshire/commit/03aff88):
+ Add more type hinting
+ ([@ztellman](https://github.com/ztellman))
-In addition, `cheshire.custom/encode` and `cheshire.custom/decode` are no longer
+[commit log](https://github.com/dakrone/cheshire/compare/5.0.1...5.0.2)
+
+# v5.0.1 - 2012-12-04
+
+* [#32](https://github.com/dakrone/cheshire/issues/32):
+ Protocol custom encoders now take precedence over regular map encoders.
+ ([@dakrone](https://github.com/dakrone))
+* Benchmarking is now a separate lein command, not a test selector.
+ ([@dakrone](https://github.com/dakrone))
+* Performance tweaks
+ ([@dakrone](https://github.com/dakrone))
+
+[commit log](https://github.com/dakrone/cheshire/compare/5.0.0...5.0.1)
+
+# v5.0.0 - 2012-09-20
+
+* [#32](https://github.com/dakrone/cheshire/issues/32):
+ Custom Encoders Changes
+ ([@dakrone](https://github.com/dakrone))
+ * Custom encoder functions were moved to the `cheshire.generate` namespace:
+ * `cheshire.custom/add-encoder` is now `cheshire.generate/add-encoder`
+ * `cheshire.custom/remove-encoder` is now `cheshire.generate/remove-encoder`
+ * In addition, `cheshire.custom/encode` and `cheshire.custom/decode` are no longer
necessary. Use `cheshire.core/encode` and `cheshire.core/decode` instead and
those functions will pick up custom encoders while still preserving the same
level of efficiency.
+ * The `cheshire.custom` namespace is now deprecated
+* Bump Jackson to v2.1.1
+ ([@dakrone](https://github.com/dakrone))
+
+[commit log](https://github.com/dakrone/cheshire/compare/4.0.4...5.0.0)
+
+# v4.0.4 - 2012-11-19
+
+* Bump Jackson to v2.1.0
+ ([@dakrone](https://github.com/dakrone))
+* [811ea45](https://github.com/dakrone/cheshire/commit/811ea45):
+ Add missing writer arg for custom `encode-stream` passthrough to `encode-stream*`
+ ([@dakrone](https://github.com/dakrone))
+
+[commit log](https://github.com/dakrone/cheshire/compare/4.0.3...4.0.4)
+
+# v4.0.3 - 2012-09-22
+
+* Bump Jackson to v2.0.6
+ ([@dakrone](https://github.com/dakrone))
+* [e7c5088](https://github.com/dakrone/cheshire/commit/e7c5088):
+ Make clojure a dev dependency
+ ([@dakrone](https://github.com/dakrone))
+* [10062af](https://github.com/dakrone/cheshire/commit/10062af):
+ Encode empty sets to empty arrays for consistency with empty array encoding
+ ([@dlebrero](https://github.com/dlebrero))
+* [9b32e2e](https://github.com/dakrone/cheshire/commit/9b32e2e):
+ Fix custom encoding of namespaced keywords
+ ([@dakrone](https://github.com/dakrone))
+
+[commit log](https://github.com/dakrone/cheshire/compare/4.0.2...4.0.3)
+
+# v4.0.2 - 2012-08-30
+
+* Bump Jackson to v2.0.5
+ ([@dakrone](https://github.com/dakrone))
+* [bacb3ac](https://github.com/dakrone/cheshire/commit/bacb3ac):
+ Add support for escaping non-ASCII chars when decoding
+ ([@dakrone](https://github.com/dakrone))
+* [52a700b](https://github.com/dakrone/cheshire/commit/52a700b):
+ Add support for custom munging of keys when decoding
+ ([@dakrone](https://github.com/dakrone))
+
+[commit log](https://github.com/dakrone/cheshire/compare/4.0.1...4.0.2)
+
+# v4.0.1 - 2012-06-12
+
+* Bump Jackson to v2.0.4
+ ([@dakrone](https://github.com/dakrone))
+* [6087d7f](https://github.com/dakrone/cheshire/commit/6087d7f):
+ Add support for encoding `Byte` and `Short` to int
+ ([@dakrone](https://github.com/dakrone))
+* [d05acde](https://github.com/dakrone/cheshire/commit/d05acde):
+ Add support for encoding `clojure.lang.Associative` to json map
+ ([@warsus](https://github.com/warsus))
+* Performance tweaks
+ ([@dakrone](https://github.com/dakrone))
+
+[commit log](https://github.com/dakrone/cheshire/compare/4.0.0...4.0.1)
+
+# v4.0.0 - 2012-04-13
+
+* [20ebaa8](https://github.com/dakrone/cheshire/commit/20ebaa8):
+ Add optional default pretty printer to json generator
+ ([@drewr](https://github.com/drewr))
+* Support encoding with custom date format
+ ([@dakrone](https://github.com/dakrone))
+
+[commit log](https://github.com/dakrone/cheshire/compare/3.1.0...4.0.0)
+
+# v3.1.0 - 2012-03-30
+
+* Bump Jackson to v2.0.0
+ ([@dakrone](https://github.com/dakrone))
+* Performance tweaks
+ ([@dakrone](https://github.com/dakrone))
+
+[commit log](https://github.com/dakrone/cheshire/compare/3.0.0...3.1.0)
+
+# v3.0.0 - 2012-03-09
+
+* [65ace30](https://github.com/dakrone/cheshire/commit/65ace30):
+ Add support for encoding `clojure.lang.PersitentQueue`
+ ([@dakrone](https://github.com/dakrone))
+* [89348a7](https://github.com/dakrone/cheshire/commit/89348a7):
+ Throw `JsonGenerationExcption` instead of `Exception` when encoding fails
+ ([@dakrone](https://github.com/dakrone))
+* [714bec2](https://github.com/dakrone/cheshire/commit/714bec2):
+ Custom encoding now falls back to core encoding by default
+ ([@dakrone](https://github.com/dakrone))
+* [263ed65](https://github.com/dakrone/cheshire/commit/263ed65):
+ Encode qualified keywords `{:document/name "My document"} -> {"document/name" : "My document"}`
+ ([@maxweber](https://github.com/maxweber))
+
+[commit log](https://github.com/dakrone/cheshire/compare/2.2.2...3.0.0)
+
+# v2.2.2 - 2012-03-06
+
+* [6e4df40](https://github.com/dakrone/cheshire/commit/6e4df40):
+ Generate symbols as strings, encoding non-resolvable symbol without throwing
+ ([@dakrone](https://github.com/dakrone))
+* [#19](https://github.com/dakrone/cheshire/issues/19):
+ Fix custom encoding for Longs
+ ([@dakrone](https://github.com/dakrone))
+
+[commit log](https://github.com/dakrone/cheshire/compare/2.2.1...2.2.2)
+
+# v2.2.1 - 2012-03-05
+
+* Bump Jackson to v1.9.5
+ ([@dakrone](https://github.com/dakrone))
+* [d2a9ad8a](https://github.com/dakrone/cheshire/commit/d2a9ad8a):
+ Add support for `java.util.{Map,List,Set}`
+ ([@ndimiduk](https://github.com/ndimiduk))
+* Performance tweaks
+ ([@dakrone](https://github.com/dakrone))
+
+[commit log](https://github.com/dakrone/cheshire/compare/2.2.0...2.2.1)
+
+# v2.2.0 - 2012-02-07
+
+* [#16](https://github.com/dakrone/cheshire/issues/16):
+ Allow parsing floats into BigDecimal to retain precision
+ ([@dakrone](https://github.com/dakrone))
+* Various performance tweaks
+ ([@dakrone](https://github.com/dakrone))
+
+[commit log](https://github.com/dakrone/cheshire/compare/2.1.0...2.2.0)
+
+# v2.1.0 - 2012-01-27
+
+* Bump Jackson to v1.9.4
+ ([@dakrone](https://github.com/dakrone))
+* Introduce `*json-factory*`, `*smile-factory*`, `*cbor-factory*` as a way to specify options to Jackson
+ ([@dakrone](https://github.com/dakrone))
+* Address some reflection warnings
+ ([@dakrone](https://github.com/dakrone))
+
+[commit log](https://github.com/dakrone/cheshire/compare/2.0.6...2.1.0)
+
+# v2.0.6 - 2012-01-12
+
+* [b96106e](https://github.com/dakrone/cheshire/commit/b96106e):
+ Encode ns-qualified symbols consistently
+ ([@dakrone](https://github.com/dakrone))
+
+[commit log](https://github.com/dakrone/cheshire/compare/2.0.5...2.0.6)
+
+# v2.0.5 - 2012-01-11
+
+* [eaee529](https://github.com/dakrone/cheshire/commit/eaee529):
+ Encode symbols that are not resolvable as strings
+ ([@dakrone](https://github.com/dakrone))
+
+[commit log](https://github.com/dakrone/cheshire/compare/2.0.4...2.0.5)
+
+# v2.0.4 - 2011-11-29
+
+* [434099d](https://github.com/dakrone/cheshire/commit/434099d):
+ Support custom array coercion when parsing
+ ([@sbtourist](https://github.com/sbtourist))
+
+[commit log](https://github.com/dakrone/cheshire/compare/2.0.3...2.0.4)
+
+# v2.0.3 - 2011-11-26
+
+* Bump Jackson to v1.9.2
+ ([@dakrone](https://github.com/dakrone))
+* Support encoding of `clojure.lang.Ratio`
+ ([@dakrone](https://github.com/dakrone))
+* [de849ce](https://github.com/dakrone/cheshire/commit/de849ce):
+ Support encoding of `BigDecimal`
+ ([@CmdrDats](https://github.com/CmdrDats))
+* Don't attempt to parse `nil` things
+ ([@dakrone](https://github.com/dakrone) and [@zk](https://github.com/zk))
+* [750ae7c](https://github.com/dakrone/cheshire/commit/750ae7c):
+ Improve error message when encoding fails
+ ([@dakrone](https://github.com/dakrone))
+
+[commit log](https://github.com/dakrone/cheshire/compare/2.0.2...2.0.3)
+
+# v2.0.2 - 2011-09-16
+
+* [db755c4](https://github.com/dakrone/cheshire/commit/db755c4):
+ Support encoding of `BigInteger`
+ ([@dakrone](https://github.com/dakrone))
+
+[commit log](https://github.com/dakrone/cheshire/compare/2.0.1...2.0.2)
+
+# v2.0.1 - 2011-08-30
+
+* Bump Jackson to v1.8.5
+ ([@dakrone](https://github.com/dakrone))
+* [#6](https://github.com/dakrone/cheshire/issues/6):
+ Support encoding of `java.sql.Timestamp`
+ ([@dakrone](https://github.com/dakrone))
+* [8c686c2](https://github.com/dakrone/cheshire/commit/8c686c2):
+ Write namespace when encoding qualified keywords
+ ([@dakrone](https://github.com/dakrone))
+* Quality
+ * Automated testing on Travis CI
+ ([@dakrone](https://github.com/dakrone))
+
+[commit log](https://github.com/dakrone/cheshire/compare/2.0.0...2.0.1)
+
+# v2.0.0 - 2011-08-02
+
+* Bump Jackson to v1.8.3
+ ([@dakrone](https://github.com/dakrone))
+* Introduce `cheshire.factory` namespace
+ ([@dakrone](https://github.com/dakrone))
+* Continue work on custom encoders
+ ([@dakrone](https://github.com/dakrone))
+
+[commit log](https://github.com/dakrone/cheshire/compare/1.1.4...2.0.0)
+
+# v1.1.4 - 2011-06-28
+
+* Bump Jackson to v1.8.2
+ ([@dakrone](https://github.com/dakrone))
+* [85f195b](https://github.com/dakrone/cheshire/commit/85f195b):
+ Add experimental custom encoders
+ ([@dakrone](https://github.com/dakrone))
+* [13db92a](https://github.com/dakrone/cheshire/commit/13db92a):
+ Add convenience methods for adding/removing custom encoders
+ ([@zk](https://github.com/zk))
+
+[commit log](https://github.com/dakrone/cheshire/compare/1.1.3...1.1.4)
+
+# v1.1.3 - 2011-05-25
+
+* Bump Jackson to v1.8.1
+ ([@dakrone](https://github.com/dakrone))
+
+[commit log](https://github.com/dakrone/cheshire/compare/da8c206a22afffa55d4023b38ba0f7e6d4d69bdd...1.1.3)
+
+# v1.1.2 - 2011-04-29
+
+* [da8c206](https://github.com/dakrone/cheshire/commit/da8c206):
+ Support clojure v1.3
+ ([@dakrone](https://github.com/dakrone))
+
+[commit log](https://github.com/dakrone/cheshire/compare/1.1.1...da8c206a22afffa55d4023b38ba0f7e6d4d69bdd)
+
+# v1.1.1 - 2011-04-18
+
+* [9cdc44c](https://github.com/dakrone/cheshire/commit/9cdc44c):
+ Add cheshire puss to README :)
+ ([@dakrone](https://github.com/dakrone))
+* [344e984](https://github.com/dakrone/cheshire/commit/344e984):
+ Stop using java for parsing
+ ([@hiredman](https://github.com/hiredman))
+* Quality
+ * Add time tests, address reflection warnings, and turf unused code
+ ([@hiredman](https://github.com/hiredman))
+
+[commit log](https://github.com/dakrone/cheshire/compare/1.1.0...1.1.1)
+
+# v1.1.0 - 2011-03-29
+
+First world-consumption release of cheshire!
+
+* [04b2ce4](https://github.com/dakrone/cheshire/commit/04b2ce4):
+ Add `Date` and `UUID` encoding
+ ([@dakrone](https://github.com/dakrone))
+* [1e21b7d](https://github.com/dakrone/cheshire/commit/1e21b7d):
+ Add stream handling (encode/decode)
+ ([@dakrone](https://github.com/dakrone))
+* [215038d](https://github.com/dakrone/cheshire/commit/215038d):
+ Add helpers for streams
+ ([@dakrone](https://github.com/dakrone))
+* Add docs and cleanup docstrings
+ ([@dakrone](https://github.com/dakrone))
+
+[commit log](https://github.com/dakrone/cheshire/compare/fca4fbb871ba43b3a00db90d96dd3bc95aa00174...1.1.0)
+
+# v1.0.2 - 2011-03-25
+
+* [fca4fbb](https://github.com/dakrone/cheshire/commit/fca4fbb):
+ Support encoding `#{}` and clojure symbols
+ ([@dakrone](https://github.com/dakrone))
+
+[commit log](https://github.com/dakrone/cheshire/compare/76186a84a68442919d4c7d79eafae9ab40e5b9a0...fca4fbb871ba43b3a00db90d96dd3bc95aa00174)
+
+# v1.0.1 - 2011-03-25
+
+* [76186a8](https://github.com/dakrone/cheshire/commit/76186a8):
+ Add helpers for people coming from `clojure-json`
+ ([@dakrone](https://github.com/dakrone))
+
+[commit log](https://github.com/dakrone/cheshire/compare/33a0e24d7b63fd091afae20666d03ac68c829411...76186a84a68442919d4c7d79eafae9ab40e5b9a0)
+
+# v1.0.0 - 2011-03-25
+
+First release of cheshire!
-GH issue: [#32](https://github.com/dakrone/cheshire/issues/32).
+[commit log](https://github.com/dakrone/cheshire/compare/74eb30ec1a2f94c044c6e46ea4454ec3ab0e2934...33a0e24d7b63fd091afae20666d03ac68c829411)
=====================================
README.md
=====================================
@@ -1,8 +1,8 @@
# Cheshire
-<img src="https://dakrone.github.io/cheshire/cheshire_small.jpg"
-title=":)" align="left" padding="5px" />
-<small>
+<img src="cheshire_puss.png" title=":)" align="left" />
+<!-- use italics to distiguish quote from other text -->
+<i>
'Cheshire Puss,' she began, rather timidly, as she did not at all know
whether it would like the name: however, it only grinned a little
wider. 'Come, it's pleased so far,' thought Alice, and she went
@@ -18,17 +18,18 @@ on. 'Would you tell me, please, which way I ought to go from here?'
'Oh, you're sure to do that,' said the Cat, 'if you only walk long
enough.'
-</small>
-<br clear=all /><br />
+</i>
+<br clear=all />
+
Cheshire is fast JSON encoding, based off of clj-json and
clojure-json, with additional features like Date/UUID/Set/Symbol
encoding and SMILE support.
-
-[Clojure code with docs](http://dakrone.github.io/cheshire/)
-
-[](https://clojars.org/cheshire)
-[](http://travis-ci.org/dakrone/cheshire)
+- [](https://cljdoc.org/d/cheshire/cheshire)
+- [](https://clojars.org/cheshire)
+- [](https://github.com/dakrone/cheshire/actions/workflows/test.yml)
+- [](https://github.com/dakrone/cheshire/actions/workflows/nvd_scan.yml)
+- Cheshire is a built-in library in the [Babashka](https://babashka.org/) project
## Why?
@@ -40,9 +41,9 @@ encoders.
## Usage
```clojure
-[cheshire "5.11.0"]
+[cheshire "6.2.1"]
-;; Cheshire v5.11.0 uses Jackson 2.13.3
+;; Cheshire v6.2.1 uses Jackson 2.21.8
;; In your ns statement:
(ns my.ns
@@ -85,9 +86,12 @@ encoders.
;; generate JSON and munge keys with a custom function
(generate-string {:foo "bar"} {:key-fn (fn [k] (.toUpperCase (name k)))})
;; => "{\"FOO\":\"bar\"}"
+
+;; generate JSON without escaping the characters (by writing it to a file)
+(spit "foo.json" (json/generate-string {:foo "bar"} {:pretty true}))
```
-In the event encoding fails, Cheshire will throw a JsonGenerationException.
+In the event encoding fails, Cheshire will throw a `JsonGenerationException`.
#### Custom Pretty Printing Options
@@ -97,8 +101,8 @@ or `encode` methods:
```clojure
(let [my-pretty-printer (create-pretty-printer
- (assoc default-pretty-print-options
- :indent-arrays? true))]
+ (assoc default-pretty-print-options
+ :indent-arrays? true))]
(generate-string {:foo [1 2 3]} {:pretty my-pretty-printer}))
```
@@ -143,10 +147,10 @@ function to specify what kind of types to return, like so:
```clojure
;; In this example a function that checks for a certain key
(decode "{\"myarray\":[2,3,3,2],\"myset\":[1,2,2,1]}" true
- (fn [field-name]
- (if (= field-name "myset")
- #{}
- [])))
+ (fn [field-name]
+ (if (= field-name "myset")
+ #{}
+ [])))
;; => {:myarray [2 3 3 2], :myset #{1 2}}
```
The type must be "transient-able", so use either #{} or []
@@ -165,12 +169,12 @@ namespace change)
;; things to be encoded:
(ns myns
(:require [cheshire.core :refer :all]
- [cheshire.generate :refer [add-encoder encode-str remove-encoder]]))
+ [cheshire.generate :refer [add-encoder encode-str remove-encoder]]))
;; First, add a custom encoder for a class:
(add-encoder java.awt.Color
- (fn [c jsonGenerator]
- (.writeString jsonGenerator (str c))))
+ (fn [c jsonGenerator]
+ (.writeString jsonGenerator (str c))))
;; There are also helpers for common encoding actions:
(add-encoder java.net.URL encode-str)
@@ -206,12 +210,12 @@ on what you would like to use.
There are also a few aliases for commonly used functions:
- encode -> generate-string
- encode-stream -> generate-stream
- encode-smile -> generate-smile
- decode -> parse-string
- decode-stream -> parse-stream
- decode-smile -> parse-smile
+ encode -> generate-string
+ encode-stream -> generate-stream
+ encode-smile -> generate-smile
+ decode -> parse-string
+ decode-stream -> parse-stream
+ decode-smile -> parse-smile
## Features
Cheshire supports encoding standard clojure datastructures, with a few
@@ -258,7 +262,7 @@ to true:
```clojure
(ns foo.bar
(require [cheshire.core :as json]
- [cheshire.parse :as parse]))
+ [cheshire.parse :as parse]))
(json/decode "111111111111111111111111111111111.111111111111111111111111111111111111")
;; => 1.1111111111111112E32 (a Double)
@@ -273,7 +277,7 @@ to true:
## Change Log
-[Change log](https://github.com/dakrone/cheshire/blob/master/ChangeLog.md) is available on GitHub.
+[Change log](/ChangeLog.md) is available on GitHub.
## Speed
@@ -297,10 +301,10 @@ nil
user> (use 'clojure.java.io)
nil
user> (println (slurp (encode-large-field-in-map {:id "10"
- :things [1 2 3]
- :body "I'll be removed"}
- :body
- (input-stream (file "/tmp/foo")))))
+ :things [1 2 3]
+ :body "I'll be removed"}
+ :body
+ (input-stream (file "/tmp/foo")))))
{"things":[1,2,3],"id":"10","body":"Hi. \"THIS\" is a string.\\yep.\n"}
nil
```
@@ -312,26 +316,21 @@ once (it returns a stream). Check out the docstring for full usage.
It's experimental, like the name says. Based on [Tigris](http://github.com/dakrone/tigris).
## Advanced customization for factories
-See
-[this](http://fasterxml.github.com/jackson-core/javadoc/2.10/com/fasterxml/jackson/core/JsonFactory.Feature.html)
-and
-[this](http://fasterxml.github.com/jackson-core/javadoc/2.10/com/fasterxml/jackson/core/JsonParser.Feature.html)
-for a list of features that can be customized if desired. A custom
-factory can be used like so:
+A custom factory can be used like so:
```clojure
(ns myns
(:require [cheshire.core :as core]
- [cheshire.factory :as factory]))
+ [cheshire.factory :as factory]))
(binding [factory/*json-factory* (factory/make-json-factory
- {:allow-non-numeric-numbers true})]
- (json/decode "{\"foo\":NaN}" true))))))
+ {:allow-non-numeric-numbers true})]
+ (json/decode "{\"foo\":NaN}" true))
```
See the `default-factory-options` map in
-[factory.clj](https://github.com/dakrone/cheshire/blob/master/src/cheshire/factory.clj)
-for a full list of configurable options. Smile factories can also be
+[factory.clj](/src/cheshire/factory.clj)
+for a full list of configurable options. Smile and CBOR factories can also be
created, and factories work exactly the same with custom encoding.
## Future Ideas/TODOs
=====================================
cheshire_puss.png
=====================================
Binary files /dev/null and b/cheshire_puss.png differ
=====================================
nvd-helper/deps.edn
=====================================
@@ -0,0 +1,5 @@
+{:deps {org.clojure/clojure {:mvn/version "1.12.0"}
+ ;; it is generally considered bad practice to use RELEASE, but we always want the latest
+ ;; security tooling
+ nvd-clojure/nvd-clojure #_:clj-kondo/ignore {:mvn/version "RELEASE"}
+ org.owasp/dependency-check-core #_:clj-kondo/ignore {:mvn/version "RELEASE"}}}
=====================================
nvd-helper/nvd-clojure.edn
=====================================
@@ -0,0 +1,3 @@
+{:delete-config? false
+ :nvd {:nvd-api {:max-retry-count 30}}
+ :suppression-file "./suppressions.xml"}
=====================================
nvd-helper/suppressions.xml
=====================================
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<suppressions xmlns="https://jeremylong.github.io/DependencyCheck/dependency-suppression.1.3.xsd">
+ <!-- This is an automatically generated config file by nvd-clojure. -->
+ <!-- Feel free to tweak it, version-control it and remove any comment. -->
+ <!-- You can find suppression examples in https://jeremylong.github.io/DependencyCheck/general/suppression.html -->
+ <suppress>
+ <notes><![CDATA[
+ This CVE is described as: An issue in Clojure versions 1.20 to 1.12.0-alpha5 allows an attacker to cause a denial of service (DoS) via the clojure.core$partial$fn__5920 function.
+ False positive; cheshire does not depend on a specific version of Clojure.
+ ]]></notes>
+ <cve>CVE-2024-22871</cve>
+ </suppress>
+</suppressions>
=====================================
project.clj
=====================================
@@ -1,23 +1,24 @@
-(defproject cheshire "5.11.0"
+(defproject cheshire "6.2.1"
:description "JSON and JSON SMILE encoding, fast."
:url "https://github.com/dakrone/cheshire"
:license {:name "The MIT License"
:url "http://opensource.org/licenses/MIT"
:distribution :repo}
:global-vars {*warn-on-reflection* false}
- :dependencies [[com.fasterxml.jackson.core/jackson-core "2.13.3"]
- [com.fasterxml.jackson.dataformat/jackson-dataformat-smile "2.13.3"
+ :dependencies [[com.fasterxml.jackson.core/jackson-core "2.21.8"]
+ [com.fasterxml.jackson.dataformat/jackson-dataformat-smile "2.21.8"
:exclusions [com.fasterxml.jackson.core/jackson-databind]]
- [com.fasterxml.jackson.dataformat/jackson-dataformat-cbor "2.13.3"
+ [com.fasterxml.jackson.dataformat/jackson-dataformat-cbor "2.21.8"
:exclusions [com.fasterxml.jackson.core/jackson-databind]]
[tigris "0.1.2"]]
- :profiles {:dev {:dependencies [[org.clojure/clojure "1.11.1"]
+ :profiles {:dev {:dependencies [[org.clojure/clojure "1.12.2"]
[org.clojure/test.generative "0.1.4"]
[org.clojure/tools.namespace "0.3.1"]]}
:1.7 {:dependencies [[org.clojure/clojure "1.7.0"]]}
:1.8 {:dependencies [[org.clojure/clojure "1.8.0"]]}
:1.9 {:dependencies [[org.clojure/clojure "1.9.0"]]}
:1.10 {:dependencies [[org.clojure/clojure "1.10.3"]]}
+ :1.11 {:dependencies [[org.clojure/clojure "1.11.4"]]}
:benchmark {:test-paths ["benchmarks"]
:jvm-opts ^:replace ["-Xms1g" "-Xmx1g" "-server"]
:dependencies [[criterium "0.4.6"]
@@ -26,19 +27,35 @@
:aliases {"all" ["with-profile" "dev,1.7:dev,1.8:dev,1.9:dev,1.10:dev"]
"benchmark" ["with-profile" "dev,benchmark" "test"]
"pretty-bench" ["with-profile" "dev,benchmark" "test" ":only"
- "cheshire.test.benchmark/t-bench-pretty"]
+ "cheshire.test.benchmark/t-bench-pretty"]
"core-bench" ["with-profile" "dev,benchmark" "test" ":only"
- "cheshire.test.benchmark/t-bench-core"]}
+ "cheshire.test.benchmark/t-bench-core"]
+ "clj-kondo-deps" ["with-profile" "+test" "clj-kondo" "--skip-lint" "--copy-configs" "--dependencies" "--parallel" "--lint" "$classpath"]
+ "clj-kondo-lint" ["do" ["clj-kondo-deps"] ["with-profile" "+test" "clj-kondo" "--parallel" "--lint" "src" "test" "project.clj"]]}
:test-selectors {:default #(and (not (:benchmark %))
(not (:generative %)))
:generative :generative
:all (constantly true)}
- :plugins [[codox "0.6.3"]
- [lein-ancient "0.6.15"]]
+ :plugins [[com.github.liquidz/antq "2.11.1276"]
+ [jonase/eastwood "1.4.3"]
+ [com.github.clj-kondo/lein-clj-kondo "2025.04.07"]]
:java-source-paths ["src/java"]
- :jvm-opts ["-Xmx512M"
+ :jvm-opts ["-Xmx1024M"
;; "-XX:+PrintCompilation"
;; "-XX:+UnlockDiagnosticVMOptions"
;; "-XX:+PrintInlining"
]
- :javac-options ["-target" "1.7" "-source" "1.7" "-Xlint:-options"])
+ :eastwood {:namespaces [:source-paths]
+ :linters [:deprecations]}
+ :javac-options
+ ~(let [version (System/getProperty "java.version")
+ ;; Parse major version from strings like "1.8.0_292" or "11.0.11"
+ major (-> (re-find #"^(1\.)?(\d+)" version)
+ (last)
+ (Integer/parseInt))
+ target-opts (case major
+ 8 ["-source" "1.8" "-target" "1.8"]
+ (if (>= major 9)
+ ["--release" "8"]
+ (throw (ex-info "javac needs a min of JDK 8" {}))))]
+ (into target-opts ["-Xlint:-options" "-Xlint:deprecation" "-Werror"])))
=====================================
src/cheshire/core.clj
=====================================
@@ -5,17 +5,17 @@
[cheshire.generate-seq :as gen-seq]
[cheshire.parse :as parse])
(:import (com.fasterxml.jackson.core JsonParser JsonFactory
- JsonGenerator PrettyPrinter
- JsonGenerator$Feature)
+ JsonGenerator PrettyPrinter)
+ (com.fasterxml.jackson.core.json JsonWriteFeature)
(com.fasterxml.jackson.dataformat.cbor CBORFactory)
(com.fasterxml.jackson.dataformat.smile SmileFactory)
(cheshire.prettyprint CustomPrettyPrinter)
- (java.io StringWriter StringReader BufferedReader BufferedWriter
+ (java.io StringWriter StringReader BufferedReader
ByteArrayOutputStream OutputStream Reader Writer)))
(defonce default-pretty-print-options
{:indentation " "
- :line-break "\n"
+ :line-break (System/lineSeparator)
:indent-arrays? false
:indent-objects? true
:before-array-values nil
@@ -69,8 +69,10 @@
PrettyPrinter
(.setPrettyPrinter generator print-pretty)
nil))
- (when (:escape-non-ascii opt-map)
- (.enable generator JsonGenerator$Feature/ESCAPE_NON_ASCII))
+ ;; legacy fn opt, consider using fatory opt instead
+ (when (some? (:escape-non-ascii opt-map))
+ (.configure generator (.mappedFeature JsonWriteFeature/ESCAPE_NON_ASCII)
+ (boolean (:escape-non-ascii opt-map))))
(gen/generate generator obj
(or (:date-format opt-map) factory/default-date-format)
(:ex opt-map)
@@ -84,13 +86,13 @@
objects will be encoded with.
The default date format (in UTC) is: yyyy-MM-dd'T'HH:mm:ss'Z'"
- (^BufferedWriter [obj ^BufferedWriter writer]
+ (^Writer [obj ^Writer writer]
(generate-stream obj writer nil))
- (^BufferedWriter [obj ^BufferedWriter writer opt-map]
+ (^Writer [obj ^Writer writer opt-map]
(let [generator (.createGenerator
^JsonFactory (or factory/*json-factory*
factory/json-factory)
- ^Writer writer)
+ writer)
print-pretty (:pretty opt-map)]
(when print-pretty
(condp instance? print-pretty
@@ -101,8 +103,10 @@
PrettyPrinter
(.setPrettyPrinter generator print-pretty)
nil))
- (when (:escape-non-ascii opt-map)
- (.enable generator JsonGenerator$Feature/ESCAPE_NON_ASCII))
+ ;; legacy fn opt, consider using fatory opt instead
+ (when (some? (:escape-non-ascii opt-map))
+ (.configure generator (.mappedFeature JsonWriteFeature/ESCAPE_NON_ASCII)
+ (boolean (:escape-non-ascii opt-map))))
(gen/generate generator obj (or (:date-format opt-map)
factory/default-date-format)
(:ex opt-map)
@@ -118,8 +122,8 @@
factory/json-factory)
^Writer writer))
-(def ^:dynamic ^JsonGenerator *generator*)
-(def ^:dynamic *opt-map*)
+(def ^:dynamic ^JsonGenerator *generator* nil)
+(def ^:dynamic *opt-map* nil)
(defmacro with-writer
"Start writing for series objects using the same json generator.
=====================================
src/cheshire/custom.clj
=====================================
@@ -1,19 +1,17 @@
-(ns cheshire.custom
+(ns ^{:deprecated "5.0.0"} 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.factory :as fact]
[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)))
+ (com.fasterxml.jackson.core JsonFactory JsonGenerator)
+ (com.fasterxml.jackson.core.json JsonWriteFeature)))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;; DEPRECATED, DO NOT USE ;;;;;;
@@ -21,11 +19,7 @@
;; 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"))
+(def ^{:dynamic true :private true} *date-format* nil)
(defprotocol JSONable
(to-json [t jg]))
@@ -34,14 +28,15 @@
(^String [obj]
(encode* obj nil))
(^String [obj opt-map]
- (binding [*date-format* (or (:date-format opt-map) default-date-format)]
+ (binding [*date-format* (or (:date-format opt-map) fact/default-date-format)]
(let [sw (StringWriter.)
- generator (.createJsonGenerator
- ^JsonFactory (or *json-factory* json-factory) sw)]
+ generator (.createGenerator
+ ^JsonFactory (or fact/*json-factory* fact/json-factory) sw)]
(when (:pretty opt-map)
(.useDefaultPrettyPrinter generator))
- (when (:escape-non-ascii opt-map)
- (.enable generator JsonGenerator$Feature/ESCAPE_NON_ASCII))
+ (when (some? (:escape-non-ascii opt-map))
+ (.configure generator (.mappedFeature JsonWriteFeature/ESCAPE_NON_ASCII)
+ (boolean (:escape-non-ascii opt-map))))
(if obj
(to-json obj generator)
(.writeNull generator))
@@ -55,17 +50,20 @@
(^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)]
+ (binding [*date-format* (or (:date-format opt-map) fact/default-date-format)]
+ (let [generator (.createGenerator
+ ^JsonFactory (or fact/*json-factory* fact/json-factory) w)]
(when (:pretty opt-map)
(.useDefaultPrettyPrinter generator))
- (when (:escape-non-ascii opt-map)
- (.enable generator JsonGenerator$Feature/ESCAPE_NON_ASCII))
+ (when (some? (:escape-non-ascii opt-map))
+ (.configure generator (.mappedFeature JsonWriteFeature/ESCAPE_NON_ASCII)
+ (boolean (:escape-non-ascii opt-map))))
(to-json obj generator)
(.flush generator)
w))))
+
+
(def encode-stream encode-stream*)
(core/copy-arglists encode-stream encode-stream*)
@@ -73,10 +71,10 @@
(^bytes [obj]
(encode-smile* obj nil))
(^bytes [obj opt-map]
- (binding [*date-format* (or (:date-format opt-map) default-date-format)]
+ (binding [*date-format* (or (:date-format opt-map) fact/default-date-format)]
(let [baos (ByteArrayOutputStream.)
- generator (.createJsonGenerator ^SmileFactory
- (or *smile-factory* smile-factory)
+ generator (.createGenerator ^SmileFactory
+ (or fact/*smile-factory* fact/smile-factory)
baos)]
(to-json obj generator)
(.flush generator)
=====================================
src/cheshire/exact.clj
=====================================
@@ -2,7 +2,7 @@
(:require [cheshire.factory :as factory]
[cheshire.parse :as parse]
[cheshire.core :as core])
- (:import (java.io StringReader Reader BufferedReader
+ (:import (java.io StringReader Reader
Writer)
(com.fasterxml.jackson.core JsonFactory)))
=====================================
src/cheshire/experimental.clj
=====================================
@@ -1,7 +1,6 @@
(ns cheshire.experimental
"Experimental JSON encoding/decoding tools."
- (:require [cheshire.core :refer :all]
- [clojure.java.io :refer :all]
+ (:require [cheshire.core :as json]
[tigris.core :refer [str-escaping-input-stream]])
(:import (java.io ByteArrayInputStream SequenceInputStream)))
@@ -19,8 +18,8 @@
([obj field stream]
(encode-large-field-in-map obj field stream nil))
([obj field stream & [opt-map]]
- (let [otherstr (encode (dissoc obj field) opt-map)
- truncstr (str (subs otherstr 0 (dec (count otherstr))))
+ (let [otherstr (json/encode (dissoc obj field) opt-map)
+ truncstr (subs otherstr 0 (dec (count otherstr)))
stream (str-escaping-input-stream stream)
pre-stream (ByteArrayInputStream.
(.getBytes (str truncstr ",\"" (name field) "\":\"")))
=====================================
src/cheshire/factory.clj
=====================================
@@ -3,9 +3,11 @@
custom generators."
(:import (com.fasterxml.jackson.dataformat.smile SmileFactory)
(com.fasterxml.jackson.dataformat.cbor CBORFactory)
- (com.fasterxml.jackson.core JsonFactory JsonFactory$Feature
- JsonParser$Feature
- JsonGenerator$Feature)))
+ (com.fasterxml.jackson.core TSFBuilder JsonFactory JsonFactory$Feature
+ StreamReadFeature
+ StreamReadConstraints StreamWriteConstraints)
+ (com.fasterxml.jackson.core.json JsonReadFeature
+ JsonWriteFeature)))
;; default date format used to JSON-encode Date objects
(def default-date-format "yyyy-MM-dd'T'HH:mm:ss'Z'")
@@ -19,94 +21,89 @@
:allow-backslash-escaping false
:allow-numeric-leading-zeros false
:allow-non-numeric-numbers false
+ :allow-trailing-comma false
:intern-field-names false
:canonicalize-field-names false
+ :escape-non-ascii false
:quote-field-names true
- :strict-duplicate-detection false})
+ :strict-duplicate-detection false
+ ;; default values from Jackson 2.18.3
+ ;; as of this version seem to be enforced for json only and not cbor, smile
+ :max-input-document-length nil ;; no limit by default
+ :max-input-token-count nil ;; no limit by default
+ :max-input-name-length 50000
+ :max-input-nesting-depth 1000
+ :max-input-number-length 1000
+ :max-input-string-length 20000000
+ :max-output-nesting-depth 1000})
-;; Factory objects that are needed to do the encoding and decoding
-(defn make-json-factory
- ^JsonFactory [opts]
- (let [opts (merge default-factory-options opts)]
- (doto (JsonFactory.)
- (.configure JsonParser$Feature/AUTO_CLOSE_SOURCE
+(defn- apply-base-opts ^TSFBuilder [^TSFBuilder builder opts]
+ (-> builder
+ (.configure StreamReadFeature/AUTO_CLOSE_SOURCE
(boolean (:auto-close-source opts)))
- (.configure JsonParser$Feature/ALLOW_COMMENTS
- (boolean (:allow-comments opts)))
- (.configure JsonParser$Feature/ALLOW_UNQUOTED_FIELD_NAMES
- (boolean (:allow-unquoted-field-names opts)))
- (.configure JsonParser$Feature/ALLOW_SINGLE_QUOTES
- (boolean (:allow-single-quotes opts)))
- (.configure JsonParser$Feature/ALLOW_UNQUOTED_CONTROL_CHARS
- (boolean (:allow-unquoted-control-chars opts)))
- (.configure JsonParser$Feature/ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER
- (boolean (:allow-backslash-escaping opts)))
- (.configure JsonParser$Feature/ALLOW_NUMERIC_LEADING_ZEROS
- (boolean (:allow-numeric-leading-zeros opts)))
- (.configure JsonParser$Feature/ALLOW_NON_NUMERIC_NUMBERS
- (boolean (:allow-non-numeric-numbers opts)))
- (.configure JsonParser$Feature/STRICT_DUPLICATE_DETECTION
+ (.configure StreamReadFeature/STRICT_DUPLICATE_DETECTION
(boolean (:strict-duplicate-detection opts)))
(.configure JsonFactory$Feature/INTERN_FIELD_NAMES
(boolean (:intern-field-names opts)))
(.configure JsonFactory$Feature/CANONICALIZE_FIELD_NAMES
(boolean (:canonicalize-field-names opts)))
- (.configure JsonGenerator$Feature/QUOTE_FIELD_NAMES
- (boolean (:quote-field-names opts))))))
+ (.streamReadConstraints (-> (StreamReadConstraints/builder)
+ (.maxDocumentLength (or (:max-input-document-length opts) -1))
+ (.maxTokenCount (or (:max-input-token-count opts) -1))
+ (.maxNameLength (:max-input-name-length opts))
+ (.maxNestingDepth (:max-input-nesting-depth opts))
+ (.maxNumberLength (:max-input-number-length opts))
+ (.maxStringLength (:max-input-string-length opts))
+ (.build)))
+ (.streamWriteConstraints (-> (StreamWriteConstraints/builder)
+ (.maxNestingDepth (:max-output-nesting-depth opts))
+ (.build)))))
-(defn make-smile-factory
- ^SmileFactory [opts]
- (let [opts (merge default-factory-options opts)]
- (doto (SmileFactory.)
- (.configure JsonParser$Feature/AUTO_CLOSE_SOURCE
- (boolean (:auto-close-source opts)))
- (.configure JsonParser$Feature/ALLOW_COMMENTS
+(defn- apply-json-opts ^TSFBuilder [^TSFBuilder builder opts]
+ (-> builder
+ (.configure JsonReadFeature/ALLOW_JAVA_COMMENTS
(boolean (:allow-comments opts)))
- (.configure JsonParser$Feature/ALLOW_UNQUOTED_FIELD_NAMES
+ (.configure JsonReadFeature/ALLOW_UNQUOTED_FIELD_NAMES
(boolean (:allow-unquoted-field-names opts)))
- (.configure JsonParser$Feature/ALLOW_SINGLE_QUOTES
+ (.configure JsonReadFeature/ALLOW_SINGLE_QUOTES
(boolean (:allow-single-quotes opts)))
- (.configure JsonParser$Feature/ALLOW_UNQUOTED_CONTROL_CHARS
+ (.configure JsonReadFeature/ALLOW_UNESCAPED_CONTROL_CHARS
(boolean (:allow-unquoted-control-chars opts)))
- (.configure JsonParser$Feature/ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER
+ (.configure JsonReadFeature/ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER
(boolean (:allow-backslash-escaping opts)))
- (.configure JsonParser$Feature/ALLOW_NUMERIC_LEADING_ZEROS
+ (.configure JsonReadFeature/ALLOW_LEADING_ZEROS_FOR_NUMBERS
(boolean (:allow-numeric-leading-zeros opts)))
- (.configure JsonParser$Feature/ALLOW_NON_NUMERIC_NUMBERS
+ (.configure JsonReadFeature/ALLOW_NON_NUMERIC_NUMBERS
(boolean (:allow-non-numeric-numbers opts)))
- (.configure JsonFactory$Feature/INTERN_FIELD_NAMES
- (boolean (:intern-field-names opts)))
- (.configure JsonFactory$Feature/CANONICALIZE_FIELD_NAMES
- (boolean (:canonicalize-field-names opts)))
- (.configure JsonGenerator$Feature/QUOTE_FIELD_NAMES
- (boolean (:quote-field-names opts))))))
+ (.configure JsonReadFeature/ALLOW_TRAILING_COMMA
+ (boolean (:allow-trailing-comma opts)))
+ (.configure JsonWriteFeature/QUOTE_FIELD_NAMES
+ (boolean (:quote-field-names opts)))
+ (.configure JsonWriteFeature/ESCAPE_NON_ASCII
+ (boolean (:escape-non-ascii opts)))))
+
+;; Factory objects that are needed to do the encoding and decoding
+(defn make-json-factory
+ ^JsonFactory [opts]
+ (let [opts (merge default-factory-options opts)]
+ (-> (JsonFactory/builder)
+ (apply-base-opts opts)
+ (apply-json-opts opts)
+ (.build))))
+
+(defn make-smile-factory
+ ^SmileFactory [opts]
+ (let [opts (merge default-factory-options opts)]
+ (-> (SmileFactory/builder)
+ (apply-base-opts opts)
+ (.build))))
(defn make-cbor-factory
^CBORFactory [opts]
(let [opts (merge default-factory-options opts)]
- (doto (CBORFactory.)
- (.configure JsonParser$Feature/AUTO_CLOSE_SOURCE
- (boolean (:auto-close-source opts)))
- (.configure JsonParser$Feature/ALLOW_COMMENTS
- (boolean (:allow-comments opts)))
- (.configure JsonParser$Feature/ALLOW_UNQUOTED_FIELD_NAMES
- (boolean (:allow-unquoted-field-names opts)))
- (.configure JsonParser$Feature/ALLOW_SINGLE_QUOTES
- (boolean (:allow-single-quotes opts)))
- (.configure JsonParser$Feature/ALLOW_UNQUOTED_CONTROL_CHARS
- (boolean (:allow-unquoted-control-chars opts)))
- (.configure JsonParser$Feature/ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER
- (boolean (:allow-backslash-escaping opts)))
- (.configure JsonParser$Feature/ALLOW_NUMERIC_LEADING_ZEROS
- (boolean (:allow-numeric-leading-zeros opts)))
- (.configure JsonParser$Feature/ALLOW_NON_NUMERIC_NUMBERS
- (boolean (:allow-non-numeric-numbers opts)))
- (.configure JsonFactory$Feature/INTERN_FIELD_NAMES
- (boolean (:intern-field-names opts)))
- (.configure JsonFactory$Feature/CANONICALIZE_FIELD_NAMES
- (boolean (:canonicalize-field-names opts)))
- (.configure JsonGenerator$Feature/QUOTE_FIELD_NAMES
- (boolean (:quote-field-names opts))))))
+ (-> (CBORFactory/builder)
+ (apply-base-opts opts)
+ (.build))))
(defonce ^JsonFactory json-factory (make-json-factory default-factory-options))
(defonce ^SmileFactory smile-factory
=====================================
src/cheshire/generate.clj
=====================================
@@ -4,11 +4,13 @@
(java.util Date Map List Set SimpleTimeZone UUID)
(java.sql Timestamp)
(java.text SimpleDateFormat)
+ (java.time Instant)
(java.math BigInteger)
- (clojure.lang IPersistentCollection Keyword Ratio Symbol)))
+ (java.util.concurrent.atomic AtomicInteger AtomicLong)
+ (clojure.lang Keyword Ratio Symbol)))
;; date format rebound for custom encoding
-(def ^{:dynamic true :private true} *date-format*)
+(def ^{:dynamic true :private true} *date-format* nil)
(defmacro tag
([obj]
@@ -26,7 +28,8 @@
(catch IllegalArgumentException _#
(throw (or ~e (JsonGenerationException.
(str "Cannot JSON encode object of class: "
- (class ~obj) ": " ~obj)))))))
+ (class ~obj) ": " ~obj)
+ ~jg))))))
(defmacro number-dispatch [jg obj e]
(let [g (tag (gensym 'jg))
@@ -41,7 +44,9 @@
~g ~(with-meta o {:tag `BigDecimal}))
Ratio (.writeNumber ~g (double ~o))
Short (.writeNumber ~g (int ~o))
- Byte (.writeNumber ~g (int ~o))]]
+ Byte (.writeNumber ~g (int ~o))
+ AtomicLong (.writeNumber ~g (long ~o))
+ AtomicInteger (.writeNumber ~g (int ~o))]]
`(let [~g ~jg
~o ~obj]
(condp instance? ~o
@@ -75,7 +80,6 @@
(definline generate-key-fn-map
[^JsonGenerator jg obj ^String date-format ^Exception e key-fn]
(let [k (gensym 'k)
- name (gensym 'name)
jg (tag jg)]
`(do
(.writeStartObject ~jg)
@@ -148,10 +152,13 @@
(i? Date obj) (let [sdf (doto (SimpleDateFormat. date-format)
(.setTimeZone (SimpleTimeZone. 0 "UTC")))]
(write-string ^JsonGenerator jg (.format sdf obj)))
- (i? Timestamp obj) (let [date (Date. (.getTime ^Timestamp obj))
- sdf (doto (SimpleDateFormat. date-format)
+ (i? Timestamp obj) (let [sdf (doto (SimpleDateFormat. date-format)
(.setTimeZone (SimpleTimeZone. 0 "UTC")))]
(write-string ^JsonGenerator jg (.format sdf obj)))
+ (i? Instant obj) (let [sdf (doto (SimpleDateFormat. date-format)
+ (.setTimeZone (SimpleTimeZone. 0 "UTC")))
+ d (Date/from obj)]
+ (write-string ^JsonGenerator jg (.format sdf d)))
:else (fail obj jg ex)))
;; Generic encoders, these can be used by someone writing a custom
=====================================
src/cheshire/generate_seq.clj
=====================================
@@ -1,15 +1,13 @@
(ns cheshire.generate-seq
"Namespace used to generate JSON from Clojure data structures in a
sequential way."
- (:use [cheshire.generate :only [tag JSONable to-json i?
- number-dispatch write-string
- fail]])
- (:import (com.fasterxml.jackson.core JsonGenerator JsonGenerationException)
+ (:require [cheshire.generate :as g])
+ (:import (com.fasterxml.jackson.core JsonGenerator)
(java.util Date Map List Set SimpleTimeZone UUID)
(java.sql Timestamp)
(java.text SimpleDateFormat)
- (java.math BigInteger)
- (clojure.lang IPersistentCollection Keyword Ratio Symbol)))
+ (java.time Instant)
+ (clojure.lang IPersistentCollection Keyword Symbol)))
(definline write-start-object [^JsonGenerator jg wholeness]
`(if (contains? #{:all :start :start-inner} ~wholeness)
@@ -32,7 +30,7 @@
(definline generate-basic-map
[^JsonGenerator jg obj ^String date-format ^Exception e
wholeness]
- (let [jg (tag jg)]
+ (let [jg (g/tag jg)]
`(do
(write-start-object ~jg ~wholeness)
(reduce (fn [^JsonGenerator jg# kv#]
@@ -53,8 +51,7 @@
[^JsonGenerator jg obj ^String date-format ^Exception e
key-fn wholeness]
(let [k (gensym 'k)
- name (gensym 'name)
- jg (tag jg)]
+ jg (g/tag jg)]
`(do
(write-start-object ~jg ~wholeness)
(reduce (fn [^JsonGenerator jg# kv#]
@@ -81,7 +78,7 @@
(definline generate-array [^JsonGenerator jg obj ^String date-format
^Exception e key-fn wholeness]
- (let [jg (tag jg)]
+ (let [jg (g/tag jg)]
`(do
(write-start-array ~jg ~wholeness)
(reduce (fn [jg# item#]
@@ -98,9 +95,9 @@
(let [wholeness (or wholeness :all)]
(cond
(nil? obj) (.writeNull ^JsonGenerator jg)
- (get (:impls JSONable) (class obj)) (#'to-json obj jg)
+ (get (:impls g/JSONable) (class obj)) (#'g/to-json obj jg)
- (i? IPersistentCollection obj)
+ (g/i? IPersistentCollection obj)
(condp instance? obj
clojure.lang.IPersistentMap
(generate-map jg obj date-format ex key-fn wholeness)
@@ -115,21 +112,24 @@
clojure.lang.Associative
(generate-map jg obj date-format ex key-fn wholeness))
- (i? Number obj) (number-dispatch ^JsonGenerator jg obj ex)
- (i? Boolean obj) (.writeBoolean ^JsonGenerator jg ^Boolean obj)
- (i? String obj) (write-string ^JsonGenerator jg ^String obj)
- (i? Character obj) (write-string ^JsonGenerator jg ^String (str obj))
- (i? Keyword obj) (write-string ^JsonGenerator jg (.substring (str obj) 1))
- (i? Map obj) (generate-map jg obj date-format ex key-fn wholeness)
- (i? List obj) (generate-array jg obj date-format ex key-fn wholeness)
- (i? Set obj) (generate-array jg obj date-format ex key-fn wholeness)
- (i? UUID obj) (write-string ^JsonGenerator jg (.toString ^UUID obj))
- (i? Symbol obj) (write-string ^JsonGenerator jg (.toString ^Symbol obj))
- (i? Date obj) (let [sdf (doto (SimpleDateFormat. date-format)
+ (g/i? Number obj) (g/number-dispatch ^JsonGenerator jg obj ex)
+ (g/i? Boolean obj) (.writeBoolean ^JsonGenerator jg ^Boolean obj)
+ (g/i? String obj) (g/write-string ^JsonGenerator jg ^String obj)
+ (g/i? Character obj) (g/write-string ^JsonGenerator jg ^String (str obj))
+ (g/i? Keyword obj) (g/write-string ^JsonGenerator jg (.substring (str obj) 1))
+ (g/i? Map obj) (generate-map jg obj date-format ex key-fn wholeness)
+ (g/i? List obj) (generate-array jg obj date-format ex key-fn wholeness)
+ (g/i? Set obj) (generate-array jg obj date-format ex key-fn wholeness)
+ (g/i? UUID obj) (g/write-string ^JsonGenerator jg (.toString ^UUID obj))
+ (g/i? Symbol obj) (g/write-string ^JsonGenerator jg (.toString ^Symbol obj))
+ (g/i? Date obj) (let [sdf (doto (SimpleDateFormat. date-format)
(.setTimeZone (SimpleTimeZone. 0 "UTC")))]
- (write-string ^JsonGenerator jg (.format sdf obj)))
- (i? Timestamp obj) (let [date (Date. (.getTime ^Timestamp obj))
- sdf (doto (SimpleDateFormat. date-format)
- (.setTimeZone (SimpleTimeZone. 0 "UTC")))]
- (write-string ^JsonGenerator jg (.format sdf obj)))
- :else (fail obj jg ex))))
+ (g/write-string ^JsonGenerator jg (.format sdf obj)))
+ (g/i? Timestamp obj) (let [sdf (doto (SimpleDateFormat. date-format)
+ (.setTimeZone (SimpleTimeZone. 0 "UTC")))]
+ (g/write-string ^JsonGenerator jg (.format sdf obj)))
+ (g/i? Instant obj) (let [sdf (doto (SimpleDateFormat. date-format)
+ (.setTimeZone (SimpleTimeZone. 0 "UTC")))
+ d (Date/from obj)]
+ (g/write-string ^JsonGenerator jg (.format sdf d)))
+ :else (g/fail obj jg ex))))
=====================================
src/cheshire/parse.clj
=====================================
@@ -32,7 +32,7 @@
(definline parse-array [^JsonParser jp key-fn bd? array-coerce-fn]
(let [jp (tag jp)]
- `(let [array-field-name# (.getCurrentName ~jp)]
+ `(let [array-field-name# (.currentName ~jp)]
(.nextToken ~jp)
(loop [coll# (transient (if ~array-coerce-fn
(~array-coerce-fn array-field-name#)
=====================================
test/cheshire/test/core.clj
=====================================
@@ -1,17 +1,39 @@
(ns cheshire.test.core
- (:use [clojure.test]
- [clojure.java.io :only [file reader]])
- (:require [cheshire.core :as json]
+ (:require [clojure.test :refer [deftest testing is are]]
+ [clojure.java.io :as io]
+ [clojure.string :as str]
+ [cheshire.core :as json]
[cheshire.exact :as json-exact]
[cheshire.generate :as gen]
[cheshire.factory :as fact]
[cheshire.parse :as parse])
(:import (com.fasterxml.jackson.core JsonGenerationException
JsonParseException)
+ (com.fasterxml.jackson.core.exc StreamConstraintsException)
(java.io FileInputStream StringReader StringWriter
- BufferedReader BufferedWriter)
+ BufferedReader BufferedWriter
+ IOException)
(java.sql Timestamp)
- (java.util Date UUID)))
+ (java.time Instant)
+ (java.util Date UUID)
+ (java.util.concurrent.atomic AtomicInteger AtomicLong)))
+
+(defn- str-of-len
+ ([len]
+ (str-of-len len "x"))
+ ([len val]
+ (apply str (repeat len val))))
+
+(defn- nested-map [depth]
+ (reduce (fn [acc n] {(str n) acc})
+ {"0" "foo"}
+ (range 1 depth)))
+
+(defn- encode-stream->str [obj opts]
+ (let [sw (StringWriter.)
+ bw (BufferedWriter. sw)]
+ (json/generate-stream obj bw opts)
+ (.toString sw)))
(def test-obj {"int" 3 "long" (long -2147483647) "boolean" true
"LongObj" (Long/parseLong "2147483647") "double" 1.23
@@ -39,6 +61,24 @@
(binding [parse/*use-bigdecimals?* true]
(is (= n (:num (json/decode (json/encode {:num n}) true)))))))
+(deftest test-atomic-long
+ (is (= {"x" 42}
+ (json/decode (json/encode {:x (AtomicLong. 42)}))))
+ (is (= {"x" 42}
+ (json/decode
+ (str
+ (json/with-writer [(StringWriter.) nil]
+ (json/write {:x (AtomicLong. 42)})))))))
+
+(deftest test-atomic-integer
+ (is (= {"y" 14}
+ (json/decode (json/encode {:y (AtomicInteger. 14)}))))
+ (is (= {"y" 14}
+ (json/decode
+ (str
+ (json/with-writer [(StringWriter.) nil]
+ (json/write {:y (AtomicInteger. 14)})))))))
+
(deftest test-string-round-trip
(is (= test-obj (json/decode (json/encode test-obj)))))
@@ -111,13 +151,52 @@
(def bin-obj {"byte-array" (byte-array (map byte [1 2 3]))})
(deftest test-round-trip-binary
- (for [[p g] {json/parse-string json/generate-string
- json/parse-smile json/generate-smile
- json/parse-cbor json/generate-cbor}]
+ (doseq [[p g] {json/parse-string json/generate-string
+ json/parse-smile json/generate-smile
+ json/parse-cbor json/generate-cbor}]
(is (let [roundtripped (p (g bin-obj))]
;; test value equality
- (= (->> bin-obj (get "byte-array") seq)
- (->> roundtripped (get "byte-array") seq))))))
+ (is (= (->> bin-obj (get "byte-array") seq)
+ (->> roundtripped (get "byte-array") seq)))))))
+
+(deftest test-smile-factory
+ (binding [fact/*smile-factory* (fact/make-smile-factory {})]
+ (is (= {"a" 1} (-> {:a 1}
+ json/generate-smile
+ json/parse-smile)))))
+
+(deftest test-smile-duplicate-detection
+ (let [smile-data (byte-array [0x3a 0x29 0x0a 0x01 ;; smile header
+ 0xFa ;; object start
+ 0x80 0x61 ;; key a
+ 0xC2 ;; value 1
+ 0x80 0x61 ;; key a (again)
+ 0xC4 ;; value 2
+ 0xFB ;; object end
+ ])]
+ (binding [fact/*smile-factory* (fact/make-smile-factory {:strict-duplicate-detection false})]
+ (is (= {"a" 2} (json/parse-smile smile-data))))
+ (binding [fact/*smile-factory* (fact/make-smile-factory {:strict-duplicate-detection true})]
+ (is (thrown? JsonParseException (json/parse-smile smile-data))))))
+
+(deftest test-cbor-factory
+ (binding [fact/*cbor-factory* (fact/make-cbor-factory {})]
+ (is (= {"a" 1} (-> {:a 1}
+ json/generate-cbor
+ json/parse-cbor)))))
+
+(deftest test-cbor-duplicate-detection
+ (let [cbor-data (byte-array [0xbf ;; object begin
+ 0x61 0x61 ;; key a
+ 0x01 ;; value 1
+ 0x61 0x61 ;; key a (again)
+ 0x02 ;; value 2
+ 0xff ;; object end
+ ])]
+ (binding [fact/*cbor-factory* (fact/make-cbor-factory {:strict-duplicate-detection false})]
+ (is (= {"a" 2} (json/parse-cbor cbor-data))))
+ (binding [fact/*cbor-factory* (fact/make-cbor-factory {:strict-duplicate-detection true})]
+ (is (thrown? JsonParseException (json/parse-cbor cbor-data))))))
(deftest test-aliases
(is (= {"foo" "bar" "1" "bat" "2" "bang" "3" "biz"}
@@ -141,6 +220,30 @@
{:date-format "yyyy-MM-dd"})))
"encode with given date format"))
+(deftest test-instant
+ (is (= {"foo" "1970-01-01T00:00:00Z"}
+ (json/decode (json/encode {:foo (Instant/ofEpochSecond (long 0))}))))
+ (is (= {"foo" "1970-01-01"}
+ (json/decode (json/encode {:foo (Instant/ofEpochSecond (long 0))}
+ {:date-format "yyyy-MM-dd"})))
+ "encode with given date format")
+ (is (= {"foo" "1970-01-01-0004"}
+ (json/decode (json/encode {:foo (Instant/ofEpochSecond (long 0))}
+ {:date-format "yyyy-MM-dd-uuuu"})))
+ "use [[java.text.SimpleDateFormat]] format rules")
+
+ (is (= {"foo" "1970-01-01T00:00:00Z"}
+ (json/decode
+ (str (json/with-writer [(StringWriter.) nil]
+ (json/write {:foo (Instant/ofEpochSecond (long 0))}))))))
+
+ (is (= {"foo" "1970-01-01"}
+ (json/decode
+ (str
+ (json/with-writer [(StringWriter.) {:date-format "yyyy-MM-dd"}]
+ (json/write {:foo (Instant/ofEpochSecond (long 0))})))))
+ "write with given date format"))
+
(deftest test-uuid
(let [id (UUID/randomUUID)
id-str (str id)]
@@ -212,11 +315,11 @@
(deftest test-multiple-objs-in-file
(is (= {"one" 1, "foo" "bar"}
- (first (json/parsed-seq (reader "test/multi.json")))))
+ (first (json/parsed-seq (io/reader "test/multi.json")))))
(is (= {"two" 2, "foo" "bar"}
- (second (json/parsed-seq (reader "test/multi.json")))))
- (with-open [s (FileInputStream. (file "test/multi.json"))]
- (let [r (reader s)]
+ (second (json/parsed-seq (io/reader "test/multi.json")))))
+ (with-open [s (FileInputStream. (io/file "test/multi.json"))]
+ (let [r (io/reader s)]
(is (= [{"one" 1, "foo" "bar"} {"two" 2, "foo" "bar"}]
(json/parsed-seq r))))))
@@ -245,16 +348,142 @@
(is (= "{\"bar\":\"clojure.core/pam\",\"foo\":\"foo.bar/baz\"}"
(json/encode (sorted-map :foo 'foo.bar/baz :bar 'clojure.core/pam)))))
-(deftest t-bindable-factories
+(deftest t-bindable-factories-auto-close-source
(binding [fact/*json-factory* (fact/make-json-factory
- {:allow-non-numeric-numbers true})]
- (is (= (type Double/NaN)
- (type (:foo (json/decode "{\"foo\":NaN}" true)))))))
+ {:auto-close-source false})]
+ (let [br (BufferedReader. (StringReader. "123"))]
+ (is (= 123 (json/parse-stream br)))
+ (is (= -1 (.read br)))))
+ (binding [fact/*json-factory* (fact/make-json-factory
+ {:auto-close-source true})]
+ (let [br (BufferedReader. (StringReader. "123"))]
+ (is (= 123 (json/parse-stream br)))
+ (is (thrown? IOException (.read br))))))
+
+(deftest t-bindable-factories-allow-comments
+ (let [s "{\"a\": /* comment */ 1, // comment\n \"b\": 2}"]
+ (binding [fact/*json-factory* (fact/make-json-factory
+ {:allow-comments true})]
+ (is (= {"a" 1 "b" 2} (json/decode s))))
+ (binding [fact/*json-factory* (fact/make-json-factory
+ {:allow-comments false})]
+ (is (thrown? JsonParseException (json/decode s))))))
+
+(deftest t-bindable-factories-allow-unquoted-field-names
+ (let [s "{a: 1, b: 2}"]
+ (binding [fact/*json-factory* (fact/make-json-factory
+ {:allow-unquoted-field-names true})]
+ (is (= {"a" 1 "b" 2} (json/decode s))))
+ (binding [fact/*json-factory* (fact/make-json-factory
+ {:allow-unquoted-field-names false})]
+ (is (thrown? JsonParseException (json/decode s))))))
+
+(deftest t-bindable-factories-allow-single-quotes
+ (doseq [s ["{'a': \"one\", 'b': \"two\"}"
+ "{\"a\": 'one', \"b\": 'two'}"
+ "{'a': 'one', 'b': 'two'}"]]
+ (testing s
+ (binding [fact/*json-factory* (fact/make-json-factory
+ {:allow-single-quotes true})]
+ (is (= {"a" "one" "b" "two"} (json/decode s))))
+ (binding [fact/*json-factory* (fact/make-json-factory
+ {:allow-single-quotes false})]
+ (is (thrown? JsonParseException (json/decode s)))))))
+
+(deftest t-bindable-factories-allow-unquoted-control-chars
+ (let [s "{\"a\": \"one\ntwo\"}"]
+ (binding [fact/*json-factory* (fact/make-json-factory
+ {:allow-unquoted-control-chars true})]
+ (is (= {"a" "one\ntwo"} (json/decode s))))
+ (binding [fact/*json-factory* (fact/make-json-factory
+ {:allow-unquoted-control-chars false})]
+ (is (thrown? JsonParseException (json/decode s))))))
+
+(deftest t-bindable-factories-allow-numeric-leading-zeros
+ (let [s "{\"a\": 00000000001}"]
+ (binding [fact/*json-factory* (fact/make-json-factory
+ {:allow-numeric-leading-zeros true})]
+ (is (= {"a" 1} (json/decode s))))
+ (binding [fact/*json-factory* (fact/make-json-factory
+ {:allow-numeric-leading-zeros false})]
+ (is (thrown? JsonParseException (json/decode s))))))
+
+(deftest t-bindable-factories-allow-backslash-escaping-any-char
+ (let [s "{\"a\": \"\\o\\n\\e\"}"]
+ (binding [fact/*json-factory* (fact/make-json-factory
+ {:allow-backslash-escaping true})]
+ (is (= {"a" "o\ne"} (json/decode s))))
+ (binding [fact/*json-factory* (fact/make-json-factory
+ {:allow-backslash-escaping false})]
+ (is (thrown? JsonParseException (json/decode s))))))
+
+(deftest t-bindable-factories-non-numeric-numbers
+ (let [s "{\"foo\":NaN}"]
+ (binding [fact/*json-factory* (fact/make-json-factory
+ {:allow-non-numeric-numbers true})]
+ (is (= (type Double/NaN)
+ (type (:foo (json/decode s true))))))
+ (binding [fact/*json-factory* (fact/make-json-factory
+ {:allow-non-numeric-numbers false})]
+ (is (thrown? JsonParseException (json/decode s true))))))
+
+(deftest t-bindable-factories-allow-trailing-comma
+ (let [s "{\"foo\":\"bar\",}"]
+ (binding [fact/*json-factory* (fact/make-json-factory
+ {:allow-trailing-comma true})]
+ (is (= "bar"
+ (:foo (json/decode s true)))))
+ (binding [fact/*json-factory* (fact/make-json-factory
+ {:allow-trailing-comma false})]
+ (is (thrown? JsonParseException (json/decode s true))))))
+
+(deftest t-bindable-factories-optimization-opts
+ (let [s "{\"a\": \"foo\"}"]
+ (doseq [opts [{:intern-field-names true}
+ {:intern-field-names false}
+ {:canonicalize-field-names true}
+ {:canonicalize-field-names false}]]
+ (binding [fact/*json-factory* (fact/make-json-factory opts)]
+ (is (= {"a" "foo"} (json/decode s)))))))
+
+(deftest t-bindable-factories-escape-non-ascii
+ ;; includes testing legacy fn opt of same name can override factory
+ (let [edn {:foo "It costs £100"}
+ expected-esc "{\"foo\":\"It costs \\u00A3100\"}"
+ expected-no-esc "{\"foo\":\"It costs £100\"}"
+ opt-esc {:escape-non-ascii true}
+ opt-no-esc {:escape-non-ascii false}]
+ (testing "default factory"
+ (doseq [[fn-opts expected]
+ [[{} expected-no-esc]
+ [opt-esc expected-esc]
+ [opt-no-esc expected-no-esc]]]
+ (testing fn-opts
+ (is (= expected (json/encode edn fn-opts) (encode-stream->str edn fn-opts))))))
+ (testing (str "factory: " opt-esc)
+ (binding [fact/*json-factory* (fact/make-json-factory opt-esc)]
+ (doseq [[fn-opts expected]
+ [[{} expected-esc]
+ [opt-esc expected-esc]
+ [opt-no-esc expected-no-esc]]]
+ (testing (str "fn: " fn-opts)
+ (is (= expected (json/encode edn fn-opts) (encode-stream->str edn fn-opts)))))))
+ (testing (str "factory: " opt-no-esc)
+ (binding [fact/*json-factory* (fact/make-json-factory opt-no-esc)]
+ (doseq [[fn-opts expected]
+ [[{} expected-no-esc]
+ [opt-esc expected-esc]
+ [opt-no-esc expected-no-esc]]]
+ (testing (str "fn: " fn-opts)
+ (is (= expected (json/encode edn fn-opts) (encode-stream->str edn fn-opts)))))))))
(deftest t-bindable-factories-quoteless
+ (binding [fact/*json-factory* (fact/make-json-factory
+ {:quote-field-names true})]
+ (is (= "{\"a\":\"foo\"}" (json/encode {:a "foo"}))))
(binding [fact/*json-factory* (fact/make-json-factory
{:quote-field-names false})]
- (is (= "{a:1}" (json/encode {:a 1})))))
+ (is (= "{a:\"foo\"}" (json/encode {:a "foo"})))))
(deftest t-bindable-factories-strict-duplicate-detection
(binding [fact/*json-factory* (fact/make-json-factory
@@ -267,16 +496,150 @@
(is (= {"a" 3 "b" 2}
(json/decode "{\"a\": 1, \"b\": 2, \"a\": 3}")))))
+(deftest t-bindable-factories-max-input-document-length
+ (let [edn {"a" (apply str (repeat 10000 "x"))}
+ sample-data (json/encode edn)]
+ (binding [fact/*json-factory* (fact/make-json-factory
+ {:max-input-document-length (count sample-data)})]
+ (is (= edn (json/decode sample-data))))
+ (binding [fact/*json-factory* (fact/make-json-factory
+ ;; as per Jackson docs, limit is inexact, so dividing input length by 2 should do the trick
+ {:max-input-document-length (/ (count sample-data) 2)})]
+ (is (thrown-with-msg?
+ StreamConstraintsException #"(?i)document length .* exceeds"
+ (json/decode sample-data))))))
+
+(deftest t-bindable-factories-max-input-token-count
+ ;; A token is a single unit of input, such as a number, a string, an object start or end, or an array start or end.
+ (let [edn {"1" 2 "3" 4}
+ sample-data (json/encode edn)]
+ (binding [fact/*json-factory* (fact/make-json-factory
+ {:max-input-token-count 6})]
+ (is (= edn (json/decode sample-data))))
+ (binding [fact/*json-factory* (fact/make-json-factory
+ {:max-input-token-count 5})]
+ (is (thrown-with-msg?
+ StreamConstraintsException #"(?i)token count .* exceeds"
+ (json/decode sample-data))))))
+
+(deftest t-bindable-factories-max-input-name-length
+ (let [k "somekey"
+ edn {k 1}
+ sample-data (json/encode edn)]
+ (binding [fact/*json-factory* (fact/make-json-factory
+ {:max-input-name-length (count k)})]
+ (is (= edn (json/decode sample-data))))
+ (binding [fact/*json-factory* (fact/make-json-factory
+ {:max-input-name-length (dec (count k))})]
+ (is (thrown-with-msg?
+ StreamConstraintsException #"(?i)name .* exceeds"
+ (json/decode sample-data)))))
+ (let [default-limit (:max-input-name-length fact/default-factory-options)]
+ (let [k (str-of-len default-limit)
+ edn {k 1}
+ sample-data (json/encode edn)]
+ (is (= edn (json/decode sample-data))))
+ (let [k (str-of-len (inc default-limit))
+ sample-data (json/encode {k 1})]
+ (is (thrown-with-msg?
+ StreamConstraintsException #"(?i)name .* exceeds"
+ (json/decode sample-data))))))
+
+(deftest t-bindable-factories-input-nesting-depth
+ (let [edn (nested-map 100)
+ sample-data (json/encode edn)]
+ (binding [fact/*json-factory* (fact/make-json-factory
+ {:max-input-nesting-depth 100})]
+ (is (= edn (json/decode sample-data))))
+ (binding [fact/*json-factory* (fact/make-json-factory
+ {:max-input-nesting-depth 99})]
+ (is (thrown-with-msg?
+ StreamConstraintsException #"(?i)nesting depth .* exceeds"
+ (json/decode sample-data))))))
+
+(deftest t-bindable-factories-max-input-number-length
+ (let [num 123456789
+ edn {"foo" num}
+ sample-data (json/encode edn)]
+ (binding [fact/*json-factory* (fact/make-json-factory
+ {:max-input-number-length (-> num str count)})]
+ (is (= edn (json/decode sample-data))))
+ (binding [fact/*json-factory* (fact/make-json-factory
+ {:max-input-number-length (-> num str count dec)})]
+ (is (thrown-with-msg?
+ StreamConstraintsException #"(?i)number value length .* exceeds"
+ (json/decode sample-data)))))
+ (let [default-limit (:max-input-number-length fact/default-factory-options)]
+ (let [num (bigint (str-of-len default-limit 2))
+ edn {"foo" num}
+ sample-data (json/encode edn)]
+ (is (= edn (json/decode sample-data))))
+ (let [num (bigint (str-of-len (inc default-limit) 2))
+ sample-data (json/encode {"foo" num})]
+ (is (thrown-with-msg?
+ StreamConstraintsException #"(?i)number value length .* exceeds"
+ (json/decode sample-data))))))
+
+(deftest t-bindable-factories-max-input-string-length
+ (let [big-string (str-of-len 40000000)
+ edn {"big-string" big-string}
+ sample-data (json/encode edn)]
+ (binding [fact/*json-factory* (fact/make-json-factory
+ {:max-input-string-length (count big-string)})]
+ (is (= edn (json/decode sample-data))))
+ (binding [fact/*json-factory* (fact/make-json-factory
+ {:max-input-string-length (dec (count big-string))})]
+ (is (thrown-with-msg?
+ StreamConstraintsException #"(?i)string value length .* exceeds"
+ (json/decode sample-data)))))
+ (let [default-limit (:max-input-string-length fact/default-factory-options)]
+ (let [big-string (str-of-len default-limit)
+ edn {"big-string" big-string}
+ sample-data (json/encode edn)]
+ (is (= edn (json/decode sample-data))))
+ (let [big-string (str-of-len (inc default-limit))
+ sample-data (json/encode {"big-string" big-string})]
+ (is (thrown-with-msg?
+ StreamConstraintsException #"(?i)string value length .* exceeds"
+ (json/decode sample-data))))))
+
+(deftest t-bindable-factories-max-output-nesting-depth
+ (let [edn (nested-map 100)]
+ (binding [fact/*json-factory* (fact/make-json-factory
+ {:max-output-nesting-depth 100})]
+ (is (.contains (json/encode edn) "\"99\"")))
+ (binding [fact/*json-factory* (fact/make-json-factory
+ {:max-output-nesting-depth 99})]
+ (is (thrown-with-msg?
+ StreamConstraintsException #"(?i)nesting depth .* exceeds"
+ (json/encode edn))))))
+
(deftest t-persistent-queue
- (let [q (conj (clojure.lang.PersistentQueue/EMPTY) 1 2 3)]
+ (let [q (conj clojure.lang.PersistentQueue/EMPTY 1 2 3)]
(is (= q (json/decode (json/encode q))))))
(deftest t-pretty-print
- (is (= (str "{\n \"bar\" : [ {\n \"baz\" : 2\n }, "
- "\"quux\", [ 1, 2, 3 ] ],\n \"foo\" : 1\n}")
+ (is (= (str/join (System/lineSeparator)
+ ["{"
+ " \"bar\" : [ {"
+ " \"baz\" : 2"
+ " }, \"quux\", [ 1, 2, 3 ] ],"
+ " \"foo\" : 1"
+ "}"])
(json/encode (sorted-map :foo 1 :bar [{:baz 2} :quux [1 2 3]])
{:pretty true}))))
+(deftest t-pretty-print-custom-linebreak
+ (is (= (str/join "foo"
+ ["{"
+ " \"bar\" : [ {"
+ " \"baz\" : 2"
+ " }, \"quux\", [ 1, 2, 3 ] ],"
+ " \"foo\" : 1"
+ "}"])
+ (json/encode (sorted-map :foo 1 :bar [{:baz 2} :quux [1 2 3]])
+ {:pretty {:line-break "foo"}}))))
+
(deftest t-pretty-print-illegal-argument
; just expecting this not to throw
(json/encode {:foo "bar"}
@@ -303,17 +666,18 @@
:before-array-values ""
:after-array-values ""
:object-field-value-separator ": "}}
- expected (str "{\n"
- " \"bar\": {\n"
- " \"baz\": [{\n"
- " \"ulu\": \"mulu\"\n"
- " }, {\n"
- " \"moot\": \"foo\"\n"
- " }, 3]\n"
- " },\n"
- " \"foo\": 1,\n"
- " \"quux\": \"blub\"\n"
- "}")
+ expected (str/join (System/lineSeparator)
+ ["{"
+ " \"bar\": {"
+ " \"baz\": [{"
+ " \"ulu\": \"mulu\""
+ " }, {"
+ " \"moot\": \"foo\""
+ " }, 3]"
+ " },"
+ " \"foo\": 1,"
+ " \"quux\": \"blub\""
+ "}"])
pretty-str (json/encode test-obj test-opts)]
; just to be easy on the eyes in case of error
@@ -338,10 +702,6 @@
(println expected))
(is (= expected pretty-str))))
-(deftest t-unicode-escaping
- (is (= "{\"foo\":\"It costs \\u00A3100\"}"
- (json/encode {:foo "It costs £100"} {:escape-non-ascii true}))))
-
(deftest t-custom-keyword-fn
(is (= {:FOO "bar"} (json/decode "{\"foo\": \"bar\"}"
(fn [k] (keyword (.toUpperCase k))))))
@@ -392,41 +752,41 @@
(deftest t-custom-helpers
(let [thing (CTestR. :state)
remove #(gen/remove-encoder CTestR)]
- (gen/add-encoder CTestR (fn [obj jg] (gen/encode-nil nil jg)))
+ (gen/add-encoder CTestR (fn [_obj jg] (gen/encode-nil nil jg)))
(is (= nil (json/decode (json/encode thing) true)))
(remove)
- (gen/add-encoder CTestR (fn [obj jg] (gen/encode-str "foo" jg)))
+ (gen/add-encoder CTestR (fn [_obj jg] (gen/encode-str "foo" jg)))
(is (= "foo" (json/decode (json/encode thing) true)))
(remove)
- (gen/add-encoder CTestR (fn [obj jg] (gen/encode-number 5 jg)))
+ (gen/add-encoder CTestR (fn [_obj jg] (gen/encode-number 5 jg)))
(is (= 5 (json/decode (json/encode thing) true)))
(remove)
- (gen/add-encoder CTestR (fn [obj jg] (gen/encode-long 4 jg)))
+ (gen/add-encoder CTestR (fn [_obj jg] (gen/encode-long 4 jg)))
(is (= 4 (json/decode (json/encode thing) true)))
(remove)
- (gen/add-encoder CTestR (fn [obj jg] (gen/encode-int 3 jg)))
+ (gen/add-encoder CTestR (fn [_obj jg] (gen/encode-int 3 jg)))
(is (= 3 (json/decode (json/encode thing) true)))
(remove)
- (gen/add-encoder CTestR (fn [obj jg] (gen/encode-ratio 1/2 jg)))
+ (gen/add-encoder CTestR (fn [_obj jg] (gen/encode-ratio 1/2 jg)))
(is (= 0.5 (json/decode (json/encode thing) true)))
(remove)
- (gen/add-encoder CTestR (fn [obj jg] (gen/encode-seq [:foo :bar] jg)))
+ (gen/add-encoder CTestR (fn [_obj jg] (gen/encode-seq [:foo :bar] jg)))
(is (= ["foo" "bar"] (json/decode (json/encode thing) true)))
(remove)
- (gen/add-encoder CTestR (fn [obj jg] (gen/encode-date (Date. (long 0)) jg)))
+ (gen/add-encoder CTestR (fn [_obj jg] (gen/encode-date (Date. (long 0)) jg)))
(binding [gen/*date-format* "yyyy-MM-dd'T'HH:mm:ss'Z'"]
(is (= "1970-01-01T00:00:00Z" (json/decode (json/encode thing) true))))
(remove)
- (gen/add-encoder CTestR (fn [obj jg] (gen/encode-bool true jg)))
+ (gen/add-encoder CTestR (fn [_obj jg] (gen/encode-bool true jg)))
(is (= true (json/decode (json/encode thing) true)))
(remove)
- (gen/add-encoder CTestR (fn [obj jg] (gen/encode-named :foo jg)))
+ (gen/add-encoder CTestR (fn [_obj jg] (gen/encode-named :foo jg)))
(is (= "foo" (json/decode (json/encode thing) true)))
(remove)
- (gen/add-encoder CTestR (fn [obj jg] (gen/encode-map {:foo "bar"} jg)))
+ (gen/add-encoder CTestR (fn [_obj jg] (gen/encode-map {:foo "bar"} jg)))
(is (= {:foo "bar"} (json/decode (json/encode thing) true)))
(remove)
- (gen/add-encoder CTestR (fn [obj jg] (gen/encode-symbol 'foo jg)))
+ (gen/add-encoder CTestR (fn [_obj jg] (gen/encode-symbol 'foo jg)))
(is (= "foo" (json/decode (json/encode thing) true)))
(remove)))
=====================================
test/cheshire/test/custom.clj
=====================================
@@ -1,8 +1,10 @@
(ns cheshire.test.custom
"DEPRECATED, kept here to ensure backward compatibility."
- (:use [clojure.test]
- [clojure.java.io :only [reader]])
- (:require [cheshire.custom :as json] :reload
+ (:require [clojure.test :refer [deftest is]]
+ [clojure.java.io :as io]
+ [clojure.string :as str]
+ #_{:clj-kondo/ignore [:deprecated-namespace]}
+ [cheshire.custom :as json] :reload
[cheshire.factory :as fact]
[cheshire.parse :as parse])
(:import (java.io StringReader StringWriter
@@ -157,9 +159,9 @@
(deftest test-multiple-objs-in-file
(is (= {"one" 1, "foo" "bar"}
- (first (json/parsed-seq (reader "test/multi.json")))))
+ (first (json/parsed-seq (io/reader "test/multi.json")))))
(is (= {"two" 2, "foo" "bar"}
- (second (json/parsed-seq (reader "test/multi.json"))))))
+ (second (json/parsed-seq (io/reader "test/multi.json"))))))
(deftest test-jsondotorg-pass1
(let [string (slurp "test/pass1.json")
@@ -195,12 +197,17 @@
(type (:foo (json/decode "{\"foo\":NaN}" true)))))))
(deftest t-persistent-queue
- (let [q (conj (clojure.lang.PersistentQueue/EMPTY) 1 2 3)]
+ (let [q (conj clojure.lang.PersistentQueue/EMPTY 1 2 3)]
(is (= q (json/decode (json/encode* q))))))
(deftest t-pretty-print
- (is (= (str "{\n \"bar\" : [ {\n \"baz\" : 2\n }, "
- "\"quux\", [ 1, 2, 3 ] ],\n \"foo\" : 1\n}")
+ (is (= (str/join (System/lineSeparator)
+ ["{"
+ " \"bar\" : [ {"
+ " \"baz\" : 2"
+ " }, \"quux\", [ 1, 2, 3 ] ],"
+ " \"foo\" : 1"
+ "}"])
(json/encode* (sorted-map :foo 1 :bar [{:baz 2} :quux [1 2 3]])
{:pretty true}))))
@@ -233,7 +240,7 @@
(deftest test-shadowing-default-encoder
(json/remove-encoder java.util.Date)
(json/add-encoder java.util.Date
- (fn [d jg] (json/encode-str "foo" jg)))
+ (fn [_d jg] (json/encode-str "foo" jg)))
(is (= "\"foo\"" (json/encode* (java.util.Date.))))
(is (= "\"foo\"" (json/encode* :foo)))
(json/remove-encoder java.util.Date)
=====================================
test/cheshire/test/generative.clj
=====================================
@@ -1,19 +1,19 @@
(ns cheshire.test.generative
- (:use [cheshire.core]
- [clojure.test.generative]
- [clojure.test :only [deftest is]]))
+ (:require [cheshire.core :as json]
+ [clojure.test.generative :refer [defspec] :as g]
+ [clojure.test :refer [deftest is]]))
;; determines whether generative stuff is printed to stdout
(def verbose true)
(defn encode-equality [x]
- [x (decode (encode x))])
+ [x (json/decode (json/encode x))])
(defn encode-equality-keys [x]
- [x (decode (encode x) true)])
+ [x (json/decode (json/encode x) true)])
(defspec number-json-encoding
- (fn [a b c] [[a b c] (decode (encode [a b c]))])
+ (fn [a b c] [[a b c] (json/decode (json/encode [a b c]))])
[^int a ^long b ^double c]
(is (= (first %) (last %))))
@@ -47,9 +47,9 @@
;; you have more than 16 CPU cores
(let [seeds (take 16 (repeatedly #(rand-int 1024)))]
(when-not verbose
- (reset! report-fn identity))
+ (reset! g/report-fn identity))
(println "Seeds:" seeds)
- (binding [*msec* 25000
- *seeds* seeds
- *verbose* false]
- (doall (map deref (test-namespaces 'cheshire.test.generative))))))
+ (binding [g/*msec* 25000
+ g/*seeds* seeds
+ g/*verbose* false]
+ (doall (map deref (g/test-namespaces 'cheshire.test.generative))))))
View it on GitLab: https://salsa.debian.org/clojure-team/cheshire-clojure/-/commit/6ca48b0d46d11d8aa20d8011cf7671a8c566da52
--
View it on GitLab: https://salsa.debian.org/clojure-team/cheshire-clojure/-/commit/6ca48b0d46d11d8aa20d8011cf7671a8c566da52
You're receiving this email because of your account on salsa.debian.org. Manage all notifications: https://salsa.debian.org/-/profile/notifications | Help: https://salsa.debian.org/help
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-java-commits/attachments/20261105/47fa8697/attachment.htm>
More information about the pkg-java-commits
mailing list