All Projects → spotify → Spotify Json

spotify / Spotify Json

Licence: apache-2.0
Fast and nice to use C++ JSON library.

Projects that are alternatives of or similar to Spotify Json

Thorsserializer
C++ Serialization library for JSON
Stars: ✭ 241 (+66.21%)
Mutual labels:  json, json-parser, json-serialization
Waargonaut
JSON decoding/encoding/manipulation library.
Stars: ✭ 82 (-43.45%)
Mutual labels:  json, json-parser, json-serialization
Json Dry
🌞 JSON-dry allows you to serialize & revive objects containing circular references, dates, regexes, class instances,...
Stars: ✭ 214 (+47.59%)
Mutual labels:  json, json-parser, json-serialization
Spray Json
A lightweight, clean and simple JSON implementation in Scala
Stars: ✭ 917 (+532.41%)
Mutual labels:  json, json-parser, json-serialization
Fastjson
A fast JSON parser/generator for Java.
Stars: ✭ 23,997 (+16449.66%)
Mutual labels:  json, json-parser, json-serialization
Easyjson
Fast JSON serializer for golang.
Stars: ✭ 3,512 (+2322.07%)
Mutual labels:  json, json-parser, json-serialization
Mir Ion
WIP, use libmir/asdf package for now
Stars: ✭ 78 (-46.21%)
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 (+175.86%)
Mutual labels:  json, json-parser, json-serialization
Json
JSON for Modern C++
Stars: ✭ 27,824 (+19088.97%)
Mutual labels:  json, json-parser, json-serialization
Jsondoc
JSON object for Delphi based on IUnknown and Variant
Stars: ✭ 20 (-86.21%)
Mutual labels:  json, json-parser, json-serialization
Gjson
Get JSON values quickly - JSON parser for Go
Stars: ✭ 9,453 (+6419.31%)
Mutual labels:  json, json-parser
Jsmnsol
A JSON parser for solidity
Stars: ✭ 56 (-61.38%)
Mutual labels:  json, json-parser
Lazyjson
A very fast, very lazy JSON parser for Java.
Stars: ✭ 55 (-62.07%)
Mutual labels:  json, json-parser
Gofasion
A lightweight json parsing library for golang.
Stars: ✭ 52 (-64.14%)
Mutual labels:  json, json-parser
Zzzjson
The fastest JSON parser written in pure C
Stars: ✭ 66 (-54.48%)
Mutual labels:  json, json-parser
Njson
Unmarshal/Decode nested JSON by JSON Path
Stars: ✭ 61 (-57.93%)
Mutual labels:  json, json-parser
Dictfier
Python library to convert/serialize class instances(Objects) both flat and nested into a dictionary data structure. It's very useful in converting Python Objects into JSON format
Stars: ✭ 67 (-53.79%)
Mutual labels:  json, json-parser
Univalue
High performance RAII C++ JSON library and universal value object class
Stars: ✭ 46 (-68.28%)
Mutual labels:  json, json-parser
Fastjson
Fast JSON parser and validator for Go. No custom structs, no code generation, no reflection
Stars: ✭ 1,164 (+702.76%)
Mutual labels:  json, json-parser
Msgpack Unity3d
MessagePack and JSON serializer for Unity3D
Stars: ✭ 74 (-48.97%)
Mutual labels:  json, json-serialization

spotify-json

License macOS & Linux Builds Windows Build

A C++17 JSON writer and parser library. It

  • parses and serializes directly to and from statically typed C++ objects,
  • requires very little boilerplate code,
  • is fast and makes use of vectorization,
  • supports UTF-8,
  • comes with a good suite of tests,
  • is deployed and in active use on over 250 million devices,
  • and has API documentation.

spotify-json depends on Google's double-conversion library, which must be linked in to the code that uses spotify-json.

Example

#include <iostream>
#include <map>
#include <string>

#include <spotify/json.hpp>

using namespace spotify::json;

struct Track {
  std::string uri;
  std::string uid;
  std::map<std::string, std::string> metadata;
};

namespace spotify {
namespace json {

// Specialize spotify::json::default_codec_t to specify default behavior when
// encoding and decoding objects of certain types.
template <>
struct default_codec_t<Track> {
  static object_t<Track> codec() {
    auto codec = object<Track>();
    codec.required("uri", &Track::uri);
    codec.optional("uid", &Track::uid);
    codec.optional("metadata", &Track::metadata);
    return codec;
  }
};

}  // namespace json
}  // namespace spotify

int main() {
  const auto parsed_track = decode<Track>(R"({ "uri": "spotify:track:xyz", "metadata": { "a": "b" } })");
  std::cout << "Parsed track with uri " << parsed_track.uri << std::endl;

  Track track;
  track.uri = "spotify:track:abc";
  track.uid = "a-uid";
  const auto json = encode(track);
  std::cout << "Encoded the track into " << json << std::endl;

  return 0;
}

Usage

spotify-json offers a range of codec types that can serialize and parse specific JSON values. There are codecs for each of the basic data types that JSON offers: strings, numbers, arrays, booleans, objects and null.

Constructing and composing codecs

A codec for integers can be made using codec::number<int>(). The codec for strings can be instantiated with codec::string().

Codecs are composable. It is for example possible to construct a codec for parsing and serialization of JSON arrays of numbers, such as [1,4,2]: codec::array<std::vector<int>>(codec::number<int>()).

Constructing deeply nested codecs manually as above can become tedious. To ease this pain, default_codec is a helper function that makes it easy to construct codecs for built-in types. For example, default_codec<int>() is a codec that can parse and serialize numbers, and default_codec<std::vector<int>>() is one that works on arrays of numbers.

It is possible to work with JSON objects with arbitrary keys. For example, default_codec<std::map<std::string, bool>>() is a codec for JSON objects with strings as keys and booleans as values.

Parsing and serialization

Parsing is done using the decode function:

try {
  decode(codec::number<int>(), "123") == 123;
  decode<int>("123") == 123;  // Shortcut for decode(default_codec<int>(), "123")
  decode<std::vector<int>>("[1,2,3]") == std::vector{ 1, 2, 3 };
} catch (const decode_exception &e) {
  std::cout << "Failed to decode: " << e.what() << std::endl;
}

decode throws decode_exception when parsing fails. There is also a function try_decode that doesn't throw on parse errors:

int result = 0;
if (try_decode(result, "123")) {
  result == 123;
} else {
  // Decoding failed!
}

Similarly, serialization is done using encode:

encode(codec::number<int>(), 123) == "123";
encode(123) == "123";  // Shortcut for encode(default_codec<int>(), 123)
encode(std::vector<int>{ 1, 2, 3 }) == "[1,2,3]";

Working with rich objects

Working with basic types such as numbers, strings, booleans and arrays is all nice and dandy, but most practical applications need to deal with rich JSON schemas that involve objects.

Many JSON libraries work by parsing JSON strings into a tree structure that can be read by the application. In our experience, this approach often leads to large amounts of boilerplate code to extract the information in this tree object into statically typed counterparts that are practical to use in C++. This boilerplate is painful to write, bug-prone and slow due to unnecessary copying. SAX-style event based libraries such as yajl avoid the slowdown but require even more boilerplate.

spotify-json avoids these issues by parsing the JSON directly into statically typed data structures. To explain how, let's use the example of a basic two-dimensional coordinate, represented in JSON as {"x":1,"y":2}. In C++, such a coordinate may be represented as a struct:

struct Coordinate {
  Coordinate() = default;
  Coordinate(int x, int y) : x(x), y(y) {}

  int x = 0;
  int y = 0;
};

With spotify-json, it is possible to construct a codec that can convert Coordinate directly to and from JSON:

auto coordinate_codec = object<Coordinate>();
coordinate_codec.required("x", &Coordinate::x);
coordinate_codec.required("y", &Coordinate::y);

The use of required will cause parsing to fail if the fields are missing. There is also an optional method. For more information, see object_t's API documentation.

This codec can be used with encode and decode:

encode(coordinate_codec, Coordinate(10, 0)) == R"({"x":10,"y":0})";

const Coordinate coord = decode(coordinate_codec, R"({ "x": 12, "y": 13 })");
coord.x == 12;
coord.y == 13;

Objects can be nested. To demonstrate this, let's introduce another data type:

struct Player {
  std::string name;
  std::string instrument;
  Coordinate position;
};

A codec for Player might be created with

auto player_codec = object<Player>();
player_codec.required("name", &Player::name);
player_codec.required("instrument", &Player::instrument);
// Because there is no default_codec for Coordinate, we need to pass in the
// codec explicitly:
player_codec.required("position", &Player::position, coordinate_codec);

// Let's use it:
Player player;
player.name = "Daniel";
player.instrument = "guitar";
encode(player_codec, player) == R"({"name":"Daniel","instrument":"guitar","position":{"x":0,"y":0}})";

Since codecs are just normal objects, it is possible to create and use several different codecs for any given data type. This makes it possible to parameterize parsing and do other fancy things, but for most data types there will only really exist one codec. For these cases, it is possible to extend the default_codec helper to support your own data types.

namespace spotify {
namespace json {

template <>
struct default_codec_t<Coordinate> {
  static object_t<Coordinate> codec() {
    auto codec = object<Coordinate>();
    codec.required("x", &Coordinate::x);
    codec.required("y", &Coordinate::y);
    return codec;
  }
};

template <>
struct default_codec_t<Player> {
  static object_t<Player> codec() {
    auto codec = object<Player>();
    codec.required("name", &Player::name);
    codec.required("instrument", &Player::instrument);
    codec.required("position", &Player::position);
    return codec;
  }
};

}  // namespace json
}  // namespace spotify

Coordinate and Player can now be used like any other type that spotify-json supports out of the box:

encode(Coordinate(10, 0)) == R"({"x":10,"y":0})";
decode<std::vector<Coordinate>>(R"([{ "x": 1, "y": -1 }])") == std::vector<Coordinate>{ Coordinate(1, -1) };

Player player;
player.name = "Martin";
player.instrument = "drums";
encode(player) == R"({"name":"Martin","instrument":"drums","position":{"x":0,"y":0}})";

Advanced usage

The examples above cover the most commonly used parts of spotify-json. The library supports more things that sometimes come in handy:

Detailed API documentation

Linking against the library in a project

If your project is built with CMake, it is easy to use spotify-json. Here is an example of how it can be done:

  1. Add spotify-json as a git submodule under vendor/
  2. Add the following lines to the CMakeLists.txt of your project:
add_subdirectory(vendor/spotify-json)
target_link_libraries([YOUR TARGET] spotify-json)

Building and running tests

Requirements

1. Make CMake find Boost

export BOOST_ROOT=/path/to/boost
export BOOST_LIBRARYDIR=/path/to/boost/lib/

2. Run CMake

mkdir build
cd build
cmake -G <generator-name> ..

Run "cmake --help" for a list of generators available on your system.

3. Build project with Visual Studio / Xcode / Ninja

4. Run CTest

cd build
ctest -j 8

Code of conduct

This project adheres to the Open Code of Conduct. By participating, you are expected to honor this code.

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].