Giter VIP home page Giter VIP logo

simplejson's Introduction

SimpleJSON Travis CI

  1. Preface
  2. Introduction
  3. Example 1
  4. Example 2
  5. Useful Utility
  6. Details
  1. Reference

Preface

Please submit pull requests if you don't agree with some behavior or found a bug, I would appreciate it. The library is further matured now and changes less.

This library can parse and stringify and is designed for ease of use. Nobody wants to write parsing and stringification methods for every class they write. We rather want it to work "just like that" without thinking about it. This is where this library fits in. This idea of producing and consuming JSON has become the "Hello World of Introspection".

Since release 0.3, the library also features basic JSON beautification using boost iostreams.

Introduction

A JSON stringifier / parser that uses boost fusion introspection methods for automagic struct <-> JSON conversion

It supports almost all STL contstructs in stringify and the most important for parse. With the STL as a basis it is an easy to extend mechanism using classes. Use boost fusion and the provided utility (see example below) or provide your own parse/stringify methods.

NOTE: The performance of this library is mostly influenced by boost property tree which is used for parsing JSON. The main focus of this library is not speed, but ease of use and convenience. If you want to be fast, try RapidJson (not saying it is particularly slow, but probably not suitable for high data frequency or big bulk data application)

Dependencies:

boost/property_tree
boost/fusion
boost/mpl

Example 0

#ifndef Q_MOC_RUN // A Qt workaround, for those of you who use Qt
#   include <SimpleJSON/parse/jsd.hpp>
#   include <SimpleJSON/stringify/jss.hpp>
#   include <SimpleJSON/stringify/jss_fusion_adapted_struct.hpp>
#endif

struct Object : public JSON::Stringifiable <Object>
              , public JSON::Parsable <Object>
{
    int A;
    std::string B;
    float C;
}; 
BOOST_FUSION_ADAPT_STRUCT(Object, A, B, C)

int main()
{
	auto o = JSON::make_from_json <Object> (R"(  
		{
			"A": 0,
			"B": "Hello",
			"C": 2.4
		}
	)");
}

Example 1

#include <string>
#include <vector>
#include <sstream>

struct ConfigContent
{
    int id;
    std::string libPath;
    std::vector <std::string> someContainer;
};

BOOST_FUSION_ADAPT_STRUCT
(
    ConfigContent,
    (int, id)
    (std::string, libPath)
    (std::vector <std::string>, someContainer)
)

SJSON_INJECT_STRINGIFY(ConfigContent)
SJSON_INJECT_PARSE(ConfigContent)

int main()
{
    ConfigContent cc;
    cc.id = 2;
    cc.libPath = "./somewhere";
    cc.someContainer = {"Hello", "World"};

    std::stringstream sstr;
    JSON::stringify(sstr, "", cc);
    ConfigContent unnecessarilyComplexCopy;
    JSON::parse(unnecessarilyComplexCopy, "", JSON::parse_json(sstr));

    /////////////////////////////////////////////////////////////////////////
    // Lets check if we got what we set
    /////////////////////////////////////////////////////////////////////////

    std::cout << sstr.str() << "\n\n";
    std::cout << unnecessarilyComplexCopy.id << "\n";
    std::cout << unnecessarilyComplexCopy.libPath << "\n";
    for (auto const& i : unnecessarilyComplexCopy.someContainer)
        std::cout << i << "\n";
}

Example 1B

An alternatvie to deriving. Does not handle polymorphic structs. Especially useful for structs, you did not create.

struct ConfigContent
{
    int id;
    std::string libPath;
    std::vector <std::string> someContainer;
};

BOOST_FUSION_ADAPT_STRUCT
(
    ConfigContent,
    (int, id)
    (std::string, libPath)
    (std::vector <std::string>, someContainer)
)

SJSON_INJECT_STRINGIFY(ConfigContent)
SJSON_INJECT_PARSE(ConfigContent)

Example 2

(Showing polymorphic serlialization / deserialization)

#ifndef Q_MOC_RUN // A Qt workaround, for those of you who use Qt
#   include <SimpleJSON/parse/jsd.hpp>
#   include <SimpleJSON/parse/jsd_convenience.hpp>
#   include <SimpleJSON/stringify/jss.hpp>
#   include <SimpleJSON/stringify/jss_fusion_adapted_struct.hpp>
#endif

#include "SimpleJSON/utility/polymorphy.hpp"

#include <string>
#include <vector>
#include <sstream>
#include <fstream>

struct Base
{
    virtual ~Base() = default;
};

struct Line : Base
            , public JSON::Stringifiable <Line>
            , public JSON::Parsable <Line>
{
    std::string text;
};

struct PrimalList : Base
                  , public JSON::Stringifiable <PrimalList>
                  , public JSON::Parsable <PrimalList>
{
    std::vector <std::shared_ptr <Base>> elements;
};

JSON_DECLARE_POLYMORPHIC
(
    Base, (Line)(PrimalList)
)

BOOST_FUSION_ADAPT_STRUCT
(
    Base
)

BOOST_FUSION_ADAPT_STRUCT
(
    Line,
    text
)

BOOST_FUSION_ADAPT_STRUCT
(
    PrimalList,
    elements
)

template <typename T>
void parse(T& cc, std::istream& json)
{
    auto tree = JSON::parse_json(json);
    JSON::parse(cc, "json_pno", tree);
}

template <typename T>
std::ostream& stringify(std::ostream& stream, T const& cc)
{
    stream << "{";
    JSON::stringify(stream, "json_pno", cc, JSON::ProduceNamedOutput);
    stream << "}";
    return stream;
}

template <typename T>
//using smart_ptr_t = std::shared_ptr <T>;
using smart_ptr_t = std::unique_ptr<T>;

int main()
{
    smart_ptr_t <Base> a {new Line};
    static_cast <Line*> (a.get())->text = "test";

    std::stringstream sstr;
    stringify(sstr, a);

    smart_ptr_t <Base> b;
    parse(b, sstr);

    if (b)
        std::cout << "b!\n";

    //std::cout << JSON::polydecls <Base>::identify_type(b.get()) << "\n";

    /////////////////////////////////////////////////////////////////////////
    // Lets check if we got what we set
    /////////////////////////////////////////////////////////////////////////

    std::cout << static_cast <Line*> (b.get())->text << "\n";
}

Example 3

Shows formatted output to a file

#ifndef Q_MOC_RUN // A Qt workaround, for those of you who use Qt
#   include <SimpleJSON/parse/jsd.hpp>
#   include <SimpleJSON/stringify/jss.hpp>
#   include <SimpleJSON/stringify/jss_fusion_adapted_struct.hpp>
#endif

struct Object : public JSON::Stringifiable <Object>
              , public JSON::Parsable <Object>
{
    int A;
    std::string B;
    float C;
}; 
BOOST_FUSION_ADAPT_STRUCT(Object, A, B, C)

int main()
{
    Object o;
    try_stringifiy_beautiful("myfile.json", "root", o);

    // alternative:
    {
        boost::iostreams::filtering_ostream filter;

        // or however else, refer to boost::iostreams doc
        filter.push(JSON::BeautifiedStreamWrapper{});
        filter.push(boost::iostreams::file_sink(file));

        // will not compile with a readable message, 
        // if Object is not a JSON::Stringifiable
        JSON::try_stringify_start(filter, o);
    }
}

Useful Utility

JSON::Base64 < T> mem;

mem will be handled as a base64 string. useful if mem can contain any character or binary sequence, including quotes.

JSON::fill_missing

auto tree = JSON::parse_json(str); // str contains some JSON.
JSON::fill_missing <MyJsonType> ("", tree); // missing members in the tree of MyJsonType get default constructed.

JSON::rename <T, Name>

Renames a member. This is necessary if something is not a valid C++ identifier, such as "." or "6".

struct MyJsonType : /* ... */
{
	/**
	 *	SJSON_SHORT_STRING -> handles up to 16 characters. (prefer whenever possible)
	 *	SJSON_STRING -> handles up to 64 characters.
	 *	SJSON_LONG_STRING -> 256 chars. (dont use if possible, heavy compiler performance hit)
	 *	SJSON_LONG_LONG_STRING -> 1024 chars. (dont use if possible, heavy compiler performance hit)
	 */
	JSON::rename <std::string, SJSON_SHORT_STRING("__.bla")> blaProperty;
};

Details

How does stringify work?

There is just one function for stringification. This stringify function is heavily overloaded and makes use of SFINAE in almost every overload. The compiler then finds the correct overload to stringify the parameter.

  • The library supports almost all STL containers (stringify supports even more) as well as fundamental types.
  • Containers will decay into json arrays, if their value_type is a stringifiable (this is recursive).
  • Classes will turn into objects, if it is adapted, derives from Stringifiable<> and each member is stringifiable.
  • For other classes, the "stringify" method is called, if provided, but then you will have to make sure on your own to produce a valid output. (The base64 wrapper uses this).

stringify behaviour (and STL stuff stringification)

It is quite import to know how certain STL constructs translate into JSON and here is a brief summary:

What it is What it becomes Remarks
std::vector [...]
std::deque [...]
std::list [...]
std::forward_list [...] Who uses forward_list anyway?
std::array [...]
std::pair {"first": ..., "second": ...}
std::atomic <T> What T would produce. Caution! Obviously calls load().
std::bitset [1, 0, ...]
std::string "..."
fundamental types themselves
JSON::IteratorRange <STL_IteratorT> [...]
std::map <std::string, T> {"key": "value", "key2": "value2", ...} A map basically represents a JSON object
std::mutex nothing ??? why would you???
std::set [...]
std::stack [...] Don't use if possible, better use deque.
std::queue [...] Don't use if possible, better use deque.
std::shared_ptr <T> What T would produce. Throws if invalid.
std::unique_ptr <T> What T would produce. Throws if invalid.
std::weak_ptr <T> What T would produce Throws if invalid.
std::tuple {"_1": ..., "_2": ..., ...}
std::valarray <T> [...]
boost::optional T or nothing Very useful for making things optional... ofc

Reference

Please visit the wiki: Wiki

simplejson's People

Contributors

5cript avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

Forkers

linecode alex2425

simplejson's Issues

improve container stringification

The implementation of boost::optional made clear that the current
differentiation between different iterator types is not needed.
Either try to improve performance or remove code dupe.

Decide how non-binary strings are treated when they contain quotes

Non binary strings could contain quotes, which will break the JSON format.
Previously the stringify function automatically escaped all quotes and parse did nothing according to that.
Now that strings can all be stored as base64 if desired, this question arose.
I suggest (to myself) to change the option for that to an enum, so the user can choose what to do.
Because automatic escaping adds potentially unnnecessary overhead.

Improve the StringificationOptions and ParsingOptions

The options are ugly and clunky => make them pretty and nice too look at.
They should also rather be called contexts.

Make it easier to set options too.

Can the following be abbreviated into one line, without JSON::ProduceNamedOutput?

JSON::StringificationOptions options;
options.in_object = true; // what does this mean? what will it change? => produce names
stringify(..., options);

Maybe something like:

stringify(..., JSON::StringificationOptions{} << JSON::InObject); // InObject, if the name stays this way.

Parsing does not null data anymore

Smart pointers cannot be assigned a value, which makes it impossible to generically null all members of an object.
This behaviour is removed until a suitable is_copy_assignable alternative has been created.

Add Option for ADL empowered custom functions.

Some library objects cannot be adapted etc, so it sometimes is needed to go around the usual SimpleJSON way of doing things.
Its currently possible by providing your own overloads, but this is undocumented and icky and sometimse defeats the purpose entirely.

Find a solution to enable pimpl optimization

fusion_adapted_struct has a huge include hierarchy and hits compilation time on weak devices hard.
Maybe there is a way to hide some of it away in translation units, instead of headers.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.