All Projects â†’ 11ways â†’ Json Dry

11ways / Json Dry

Licence: mit
🌞 JSON-dry allows you to serialize & revive objects containing circular references, dates, regexes, class instances,...

Programming Languages

javascript
184084 projects - #8 most used programming language

Projects that are alternatives of or similar to Json Dry

Easyjson
Fast JSON serializer for golang.
Stars: ✭ 3,512 (+1541.12%)
Mutual labels:  json, json-parser, json-serialization
Spotify Json
Fast and nice to use C++ JSON library.
Stars: ✭ 145 (-32.24%)
Mutual labels:  json, json-parser, json-serialization
Thorsserializer
C++ Serialization library for JSON
Stars: ✭ 241 (+12.62%)
Mutual labels:  json, json-parser, json-serialization
Jsondoc
JSON object for Delphi based on IUnknown and Variant
Stars: ✭ 20 (-90.65%)
Mutual labels:  json, json-parser, json-serialization
Json
JSON for Modern C++
Stars: ✭ 27,824 (+12901.87%)
Mutual labels:  json, json-parser, json-serialization
Jsoncons
A C++, header-only library for constructing JSON and JSON-like data formats, with JSON Pointer, JSON Patch, JSON Schema, JSONPath, JMESPath, CSV, MessagePack, CBOR, BSON, UBJSON
Stars: ✭ 400 (+86.92%)
Mutual labels:  json, json-parser, json-serialization
Waargonaut
JSON decoding/encoding/manipulation library.
Stars: ✭ 82 (-61.68%)
Mutual labels:  json, json-parser, json-serialization
Fastjson
A fast JSON parser/generator for Java.
Stars: ✭ 23,997 (+11113.55%)
Mutual labels:  json, json-parser, json-serialization
Spray Json
A lightweight, clean and simple JSON implementation in Scala
Stars: ✭ 917 (+328.5%)
Mutual labels:  json, json-parser, json-serialization
Mir Ion
WIP, use libmir/asdf package for now
Stars: ✭ 78 (-63.55%)
Mutual labels:  json, json-parser, json-serialization
Simplejson
simplejson is a simple, fast, extensible JSON encoder/decoder for Python
Stars: ✭ 1,372 (+541.12%)
Mutual labels:  json, json-parser
Java
jsoniter (json-iterator) is fast and flexible JSON parser available in Java and Go
Stars: ✭ 1,308 (+511.21%)
Mutual labels:  json, json-parser
Go
A high-performance 100% compatible drop-in replacement of "encoding/json"
Stars: ✭ 10,248 (+4688.79%)
Mutual labels:  json, json-parser
Simdjson php
simdjson_php bindings for the simdjson project. https://github.com/lemire/simdjson
Stars: ✭ 90 (-57.94%)
Mutual labels:  json, json-parser
Dynamodb Json
DynamoDB json util to load and dump strings of Dynamodb json format to python object and vise-versa
Stars: ✭ 114 (-46.73%)
Mutual labels:  json, json-parser
Gitlogg
💾 🧮 🤯 Parse the 'git log' of multiple repos to 'JSON'
Stars: ✭ 102 (-52.34%)
Mutual labels:  json, json-parser
Json Voorhees
A killer modern C++ library for interacting with JSON.
Stars: ✭ 120 (-43.93%)
Mutual labels:  json, json-serialization
Daw json link
Static JSON parsing in C++
Stars: ✭ 146 (-31.78%)
Mutual labels:  json, json-parser
Json 2 Kotlin
Convert JSON to Kotlin Data Classes
Stars: ✭ 148 (-30.84%)
Mutual labels:  json, json-serialization
Poison
An incredibly fast, pure Elixir JSON library
Stars: ✭ 1,898 (+786.92%)
Mutual labels:  json, json-parser

JSON-dry

NPM version Build Status Coverage Status

JSON-dry allows you to stringify objects containing circular references, dates, regexes, ...

It can also be used to serialize and revive instances of your own classes.

Table of contents

Installation

$ npm install json-dry

Usage

Basic example

This is a basic example of stringifying an object (containing multiple references to the same object) and parsing it again.

var Dry = require('json-dry');

// The object we'll serialize later
var obj = {};

// The object we'll make multiple references to
var ref = {
    date  : new Date(),
    regex : /test/i
};

// Now we'll make multiple references:
// `reference_one` and `reference_two` both point to the same object
// `date` refers to a `Date` object
obj.reference_one = ref;
obj.reference_two = ref;
obj.date = ref.date;

// Stringify the object
var dried = Dry.stringify(obj);
// {
//     "reference_one": {
//         "date": {
//             "dry": "date",
//             "value": "2018-01-14T17:45:57.989Z"
//         },
//         "regex": {
//             "dry": "regexp",
//             "value": "/test/i"
//         }
//     },
//     "reference_two": "~reference_one",
//     "date": "~reference_one~date"
// }

// Now we'll revive it again
var undried = Dry.parse(dried);
// { reference_one: { date: 2018-01-14T17:56:43.149Z, regex: /test/i },
//   reference_two: { date: 2018-01-14T17:56:43.149Z, regex: /test/i },
//   date: 2018-01-14T17:58:50.427Z }

// See if they're the same objects (as it should)
undried.reference_one == undried.reference_two;
// true

// The date outside of the reference object is also the same reference
undried.reference_one.date == undried.date;
// true

Implementing methods for serializing & reviving instances

Let's create an example class you might want to serialize and revive:

// The class constructor
function Person(options) {
    this.firstname = options.firstname;
    this.lastname = options.lastname;
}

// A simple method that prints out the full name
Person.prototype.fullname = function fullname() {
    return this.firstname + ' ' + this.lastname;
};

// Create an object
var jelle = new Person({firstname: 'Jelle', lastname: 'De Loecker'});

// Test out the fullname method
jelle.fullname();
// returns "Jelle De Loecker"

So now we've created a very basic class, let's register the class and add the 2 required methods for serializing & reviving.

// We need to register the class
Dry.registerClass(Person);

// Add the `toDry` method that will be called upon when serializing/stringifying
Person.prototype.toDry = function toDry() {
    return {
        value: {
            firstname : this.firstname,
            lastname  : this.lastname
        }
    };
};

// Now add the `unDry` method as a **static** method, on the constructor
Person.unDry = function unDry(value) {
    // How you do this is up to you.
    // You can call the constructor for this simple class,
    // or you can use Object.create, ...
    var result = new Person(value);
    return result;
};

Now let's try stringifying it:

var dried = Dry.stringify(jelle);
// {"value":{"firstname":"Jelle","lastname":"De Loecker"},"dry_class":"Person","dry":"toDry","drypath":[]}

// And parse it again
var undried = Dry.parse(dried);
// Person { firstname: 'Jelle', lastname: 'De Loecker' }

// And it works
undried.fullname();
// returns "Jelle De Loecker"

Serializing & reviving instances with circular references

Some classes contain references to each other, for example:

let alpha = new Alpha(),
    beta = new Beta();

alpha.beta = beta;
beta.alpha = alpha;

The problem is that when you serialize & then try to revive this, one of the unDry methods will receive an un-revived placeholder. This can obviously cause issues, especially when setting the property has side-effects. So a new argument whenDone has been added to the unDry method, like so:

Alpha.prototype.unDry = function unDry(obj, custom_method, whenDone) {

  let alpha = new Alpha();

  whenDone(function() {
    alpha.beta = obj.beta;
  });

  return alpha;
}

whenDone functions will be called just before the Dry.undry() function exits, so all the references will have been revived by then.

toObject

While Dry.stringify will return you with a json-valid string, Dry.toObject will give you a valid simplified object.

In fact: Dry.stringify is just a function that performs JON.stringify on Dry.toObject's output.

Why would you want to use this? Things like Workers and IndexedDB communicate data using the structured clone algorithm. So instead of performing expensive stringify operations you can just use these objects.

Cloning objects & instances

JSON-Dry offers a specialized clone method. While in theory you could clone an object by drying end reviving it, like so:

var cloned = Dry.parse(Dry.toObject(jelle))

This is 14x slower than using clone, because toObject needs to generate paths, escape certain string values and create wrapper objects. These expensive things can be ignored when cloning:

var cloned = Dry.clone(jelle);

Clone methods

If you've added a toDry and unDry method to your class, by default the clone method will use those to create the clone.

However, you can also create another method that gets precedence:

dryClone

Person.prototype.dryClone = function dryClone(seen_map, custom_method) {
    return new Person({
        firstname : this.firstname,
        lastname  : this.lastname
    });
}    

Custom clone methods

The clone method takes an extra parameter called custom_method. If you're cloning something that has a function property with the same name, that'll be used.

This can be used when you want to redact certain parts, for example:

Person.prototype.specialOccasionClone = function specialOccasionClone(seen_map, custom_method) {
    return new Person({
        firstname : this.firstname[0] + '.', // Only add the first letter of the name
        lastname  : this.lastname
    });
};

var special_clone = Dry.clone(jelle, 'specialOccasionClone');
special_clone.fullname();
// Returns "J. De Loecker"

Project history

Earlier versions of the project were heavily based on circular-json, a small library that adds (circular) reference support to JSON.

A lot of the JavaScript code on my websites was already shared between the server & client side, but I also wanted an easy way of sending data to the client while retaining references & class instances, so I started adding features to circular-json and called it json-dry (dry as in don't repeat yourself).

After version 0.1.6 I integrated json-dry into my protoblast library, and development continued in there. But now it has deserved its own repository once again.

This version is a rewrite of earlier versions. circular-json used (and still uses) multiple arrays to keep track of already used objects, but json-dry now uses WeakMaps, something that makes the code easier to maintain and is also faster.

circular-json was also implemented as a replacer and reviver function to JSON.stringify and JSON.parse respectively. json-dry actually creates a new object before stringifying it.

Because multiple references are represented as ~paths~to~the~first~reference, the size of the JSON string can be a lot smaller. Can be, though, because sometimes reference paths are longer than the object they are refering to.

Because of this, as soon as json-dry encounters a new path that is smaller than the previous one, it'll use that in the future. This helps a bit, though more improvements could be made in the future.

Project future

  • Possibly use objects or arrays instead of string primitives for references. This would speed up serializing and parsing, but be a bit more verbose. Tell me what you think in issue #2

Versioning

We use SemVer for versioning. For the versions available, see the tags on this repository.

License

This project is licensed under the MIT License - see the LICENSE file for details

Acknowledgments

Many thanks to WebReflection, whose circular-json was the basis for earlier versions of this project.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].