2016-01-23 04:45:24 +00:00
< a href = "https://www.taoensso.com" title = "More stuff by @ptaoussanis at www.taoensso.com" >
< img src = "https://www.taoensso.com/taoensso-open-source.png" alt = "Taoensso open-source" width = "400" / > < / a >
**[CHANGELOG]** | [API] | current [Break Version]:
2012-07-01 17:13:32 +00:00
2012-07-06 12:53:02 +00:00
```clojure
2022-06-23 11:18:10 +00:00
[com.taoensso/nippy "3.1.3"] ; Stable
[com.taoensso/nippy "3.2.0-RC2"] ; Dev, see CHANGELOG for details
2012-07-06 12:53:02 +00:00
```
2020-09-20 10:05:37 +00:00
<!--  -->
2020-09-11 13:25:16 +00:00
> See [here](https://taoensso.com/clojure/backers) if you're interested in helping support my open-source work, thanks! - Peter Taoussanis
2020-07-24 16:27:34 +00:00
2020-09-11 09:35:19 +00:00
## _SECURITY ADVISORY_
2020-07-24 16:27:34 +00:00
2020-09-20 10:08:16 +00:00
Users of Nippy < = `v2.15.0-RC1` should **please upgrade ASAP** due to a **Remote Code Execution (RCE) vulnerability** when deserializing data from an **untrusted source** .
2020-07-24 16:27:34 +00:00
2020-09-20 10:08:16 +00:00
See [here ](https://github.com/ptaoussanis/nippy/issues/130 ) for details, including upgrade instructions.
2016-03-10 07:11:34 +00:00
2020-10-04 08:16:17 +00:00
# Nippy: the fastest serialization library for Clojure
2012-07-06 12:53:02 +00:00
2016-01-23 04:45:24 +00:00
Clojure's [rich data types] are *awesome* . And its [reader] allows you to take your data just about anywhere. But the reader can be painfully slow when you've got a lot of data to crunch (like when you're serializing to a database).
2012-07-06 12:53:02 +00:00
2016-01-23 04:45:24 +00:00
Nippy is an attempt to provide a reliable, high-performance **drop-in alternative to the reader** . Used by the [Carmine Redis client], the [Faraday DynamoDB client], [PigPen], [Onyx] and others.
2012-07-06 12:53:02 +00:00
2016-01-23 04:45:24 +00:00
## Features
* Small, uncomplicated **all-Clojure** library
* **Terrific performance** (the fastest for Clojure that I'm aware of)
* Comprehesive **support for all standard data types**
* **Easily extendable to custom data types** (v2.1+)
* Java's **Serializable** fallback when available (v2.5+)
* **Reader-fallback** for all other types (including Clojure 1.4+ tagged literals)
* **Full test coverage** for every supported type
* Fully pluggable **compression** , including built-in high-performance [LZ4] compressor
* Fully pluggable **encryption** , including built-in high-strength AES128 enabled with a single `:password [:salted "my-password"]` option (v2+)
* Utils for **easy integration into 3rd-party tools/libraries** (v2+)
2013-10-17 10:55:44 +00:00
2013-06-01 12:14:21 +00:00
## Getting started
2012-07-06 12:53:02 +00:00
2016-01-23 04:45:24 +00:00
Add the necessary dependency to your project:
2012-07-06 12:53:02 +00:00
2016-01-23 04:45:24 +00:00
```clojure
2022-06-23 11:18:10 +00:00
Leiningen: [com.taoensso/nippy "3.1.3"] ; or
deps.edn: com.taoensso/nippy {:mvn/version "3.1.3"}
2016-01-23 04:45:24 +00:00
```
And setup your namespace imports:
2012-07-06 12:53:02 +00:00
```clojure
2016-01-23 04:45:24 +00:00
(ns my-ns (:require [taoensso.nippy :as nippy]))
2012-07-06 12:53:02 +00:00
```
2013-06-01 12:14:21 +00:00
### De/serializing
2012-07-06 12:53:02 +00:00
2016-01-23 04:45:24 +00:00
As an example of what it can do, let's take a look at Nippy's own reference stress data:
2012-07-06 19:12:59 +00:00
```clojure
nippy/stress-data
=>
2022-06-25 10:40:52 +00:00
{:nil nil
:true true
:false false
:boxed-false (Boolean. false)
2016-04-07 05:49:26 +00:00
:char \ಬ
:str-short "ಬಾ ಇಲ್ಲಿ ಸಂಭವಿಸ"
:str-long (apply str (range 1000))
:kw :keyword
:kw-ns ::keyword
2020-11-18 09:46:37 +00:00
:kw-long (keyword
(apply str "kw" (range 1000))
(apply str "kw" (range 1000)))
2016-04-07 05:49:26 +00:00
:sym 'foo
:sym-ns 'foo/bar
2020-11-18 09:46:37 +00:00
:sym-long (symbol
(apply str "sym" (range 1000))
(apply str "sym" (range 1000)))
2022-06-25 10:40:52 +00:00
:regex #"^(https?:)?//(www\?|\?)?"
2012-07-06 19:12:59 +00:00
2013-04-14 07:44:06 +00:00
:queue (-> (PersistentQueue/EMPTY) (conj :a :b :c :d :e :f :g))
:queue-empty (PersistentQueue/EMPTY)
2016-04-07 05:49:26 +00:00
:queue-empty (enc/queue)
2013-04-14 07:44:06 +00:00
:sorted-set (sorted-set 1 2 3 4 5)
:sorted-map (sorted-map :b 2 :a 1 :d 4 :c 3)
2012-07-06 19:12:59 +00:00
:list (list 1 2 3 4 5 (list 6 7 8 (list 9 10)))
:list-quoted '(1 2 3 4 5 (6 7 8 (9 10)))
:list-empty (list)
:vector [1 2 3 4 5 [6 7 8 [9 10]]]
:vector-empty []
:map {:a 1 :b 2 :c 3 :d {:e 4 :f {:g 5 :h 6 :i 7}}}
:map-empty {}
:set #{1 2 3 4 5 #{6 7 8 #{9 10}}}
:set-empty #{}
:meta (with-meta {:a :A} {:metakey :metaval})
2016-04-07 05:49:26 +00:00
:nested [#{{1 [:a :b] 2 [:c :d] 3 [:e :f]} [] #{:a :b}}
#{{1 [:a :b] 2 [:c :d] 3 [:e :f]} [] #{:a :b}}
[1 [1 2 [1 2 3 [1 2 3 4 [1 2 3 4 5]]]]]]
:lazy-seq (repeatedly 1000 rand)
:lazy-seq-empty (map identity '())
2012-07-06 19:12:59 +00:00
:byte (byte 16)
:short (short 42)
:integer (int 3)
:long (long 3)
:bigint (bigint 31415926535897932384626433832795)
:float (float 3.14)
:double (double 3.14)
:bigdec (bigdec 3.1415926535897932384626433832795)
2012-07-08 05:49:22 +00:00
:ratio 22/7
2013-10-23 18:53:41 +00:00
:uuid (java.util.UUID/randomUUID)
2013-10-24 06:33:54 +00:00
:date (java.util.Date.)
2020-11-06 13:06:15 +00:00
2020-11-06 14:59:56 +00:00
;;; JVM 8+
:time-instant (java.time.Instant/now)
:time-duration (java.time.Duration/ofSeconds 100 100)
:time-period (java.time.Period/of 1 1 1)
2020-11-06 13:06:15 +00:00
2022-06-25 10:40:52 +00:00
:bytes (byte-array [(byte 1) (byte 2) (byte 3)])
2020-10-24 10:27:53 +00:00
:objects (object-array [1 "two" {:data "data"}])
2013-10-24 06:33:54 +00:00
2016-06-10 04:18:55 +00:00
:stress-record (StressRecord. "data")
2020-10-24 10:27:53 +00:00
:stress-type (StressType. "data")
2013-10-24 06:50:55 +00:00
;; Serializable
:throwable (Throwable. "Yolo")
:exception (try (/ 1 0) (catch Exception e e))
2020-11-06 13:06:15 +00:00
:ex-info (ex-info "ExInfo" {:data "data"})}
2012-07-06 19:12:59 +00:00
```
Serialize it:
```clojure
2013-06-13 04:54:08 +00:00
(def frozen-stress-data (nippy/freeze nippy/stress-data))
2012-07-06 19:12:59 +00:00
=> #< byte [ ] [ B @ 3253bcf3 >
```
Deserialize it:
```clojure
2013-06-13 04:54:08 +00:00
(nippy/thaw frozen-stress-data)
2012-07-07 12:08:42 +00:00
=> {:bytes (byte-array [(byte 1) (byte 2) (byte 3)])
2012-07-06 19:12:59 +00:00
:nil nil
:boolean true
< ... > }
```
Couldn't be simpler!
2012-07-06 12:53:02 +00:00
2014-01-22 07:14:26 +00:00
See also the lower-level `freeze-to-out!` and `thaw-from-in!` fns for operating on `DataOutput` and `DataInput` types directly.
2014-04-05 11:30:28 +00:00
### Encryption (v2+)
2013-06-12 08:19:09 +00:00
2014-04-05 11:30:28 +00:00
Nippy also gives you **dead simple data encryption** . Add a single option to your usual freeze/thaw calls like so:
2013-06-12 08:19:09 +00:00
```clojure
2013-06-13 04:54:08 +00:00
(nippy/freeze nippy/stress-data {:password [:salted "my-password"]}) ; Encrypt
(nippy/thaw < encrypted-data > {:password [:salted "my-password"]}) ; Decrypt
2013-06-12 08:19:09 +00:00
```
2016-01-23 04:45:24 +00:00
There's two default forms of encryption on offer: `:salted` and `:cached` . Each of these makes carefully-chosen trade-offs and is suited to one of two common use cases. See the `aes128-encryptor` [API] docs for a detailed explanation of why/when you'd want one or the other.
2013-06-12 08:19:09 +00:00
2014-04-05 11:30:28 +00:00
### Custom types (v2.1+)
2013-07-29 08:59:24 +00:00
```clojure
(defrecord MyType [data])
2014-07-04 13:05:18 +00:00
(nippy/extend-freeze MyType :my-type/foo ; A unique (namespaced) type identifier
2014-01-22 07:14:26 +00:00
[x data-output]
(.writeUTF data-output (:data x)))
2013-07-29 08:59:24 +00:00
2014-07-04 13:05:18 +00:00
(nippy/extend-thaw :my-type/foo ; Same type id
2014-01-22 07:14:26 +00:00
[data-input]
2016-06-10 04:18:55 +00:00
(MyType. (.readUTF data-input)))
2013-07-29 08:59:24 +00:00
2016-06-10 04:18:55 +00:00
(nippy/thaw (nippy/freeze (MyType. "Joe"))) => #taoensso .nippy.MyType{:data "Joe"}
2013-07-29 08:59:24 +00:00
```
2012-07-06 12:53:02 +00:00
## Performance
2016-06-10 03:37:29 +00:00
Nippy is currently the **fastest serialization library for Clojure** that I'm aware of, and offers roundtrip times between ** ~10x and ~15x** faster than Clojure's `tools.reader.edn` , with a ** ~40% smaller output size**.
2016-01-23 04:45:24 +00:00
![benchmarks-png]
2012-07-06 12:53:02 +00:00
2016-01-23 04:45:24 +00:00
[Detailed benchmark info] is available on Google Docs.
2012-07-06 12:53:02 +00:00
2016-01-23 04:45:24 +00:00
## Contacting me / contributions
2012-11-05 17:49:37 +00:00
2016-01-23 04:45:24 +00:00
Please use the project's [GitHub issues page] for all questions, ideas, etc. **Pull requests welcome** . See the project's [GitHub contributors page] for a list of contributors.
2014-02-25 07:37:27 +00:00
2016-01-23 04:45:24 +00:00
Otherwise, you can reach me at [Taoensso.com]. Happy hacking!
2012-07-06 12:53:02 +00:00
2016-01-23 04:45:24 +00:00
\- [Peter Taoussanis]
2012-07-06 12:53:02 +00:00
## License
2016-01-23 04:45:24 +00:00
Distributed under the [EPL v1.0] \(same as Clojure).
2022-06-23 09:12:35 +00:00
Copyright © 2012-2022 [Peter Taoussanis].
2014-02-22 18:30:11 +00:00
2016-01-23 04:45:24 +00:00
<!-- - Standard links -->
[Taoensso.com]: https://www.taoensso.com
[Peter Taoussanis]: https://www.taoensso.com
[@ptaoussanis]: https://www.taoensso.com
[More by @ptaoussanis ]: https://www.taoensso.com
[Break Version]: https://github.com/ptaoussanis/encore/blob/master/BREAK-VERSIONING.md
2014-02-22 18:30:11 +00:00
2016-01-23 04:45:24 +00:00
<!-- - Standard links (repo specific) -->
2015-03-20 08:14:14 +00:00
[CHANGELOG]: https://github.com/ptaoussanis/nippy/releases
2016-01-23 04:45:24 +00:00
[API]: http://ptaoussanis.github.io/nippy/
[GitHub issues page]: https://github.com/ptaoussanis/nippy/issues
[GitHub contributors page]: https://github.com/ptaoussanis/nippy/graphs/contributors
[EPL v1.0]: https://raw.githubusercontent.com/ptaoussanis/nippy/master/LICENSE
[Hero]: https://raw.githubusercontent.com/ptaoussanis/nippy/master/hero.png "Title"
<!-- - Unique links -->
[rich data types]: http://clojure.org/reference/datatypes
[reader]: http://clojure.org/reference/reader
[Carmine Redis client]: https://github.com/ptaoussanis/carmine
[Faraday DynamoDB client]: https://github.com/ptaoussanis/faraday
[PigPen]: https://github.com/Netflix/PigPen
[Onyx]: https://github.com/onyx-platform/onyx
[LZ4]: https://code.google.com/p/lz4/
[benchmarks-png]: https://github.com/ptaoussanis/nippy/raw/master/benchmarks.png
2016-06-10 03:37:29 +00:00
[Detailed benchmark info]: https://docs.google.com/spreadsheet/ccc?key=0AuSXb68FH4uhdE5kTTlocGZKSXppWG9sRzA5Y2pMVkE