Encapsulating rapid JSON for database and network data transmission


I want to complete json as the data medium to operate the database and network transmission. Looking up the data, we found that rapid json is a popular json library, and it is fast. But in my way of use, it's very cumbersome to use, and my purpose is data exchange. Rapid json is very common. It seems that it should be a value transfer operation. In fact, it is a memory move. Although this can achieve the goal of high efficiency, it will make mistakes if you are not careful, and it looks ugly when you write it, so I wrote a proxy class to meet my needs.

design idea

Just add some convenient operation methods, provide a variety of constructors to easily create objects, provide a copy constructor, provide a convenient interface to add elements, provide object traversal methods and so on. In fact, it's a rapidjson object. All the actual operations are based on rapidjson. Rjson is just a proxy. It changes the way of use and provides value transmission, which will cause some performance degradation, but it's a necessary change to meet my needs.

Specific implementation

Class structure

Document * json is the actual json object. I encapsulate it to provide a new access interface without exposing other details, such as the value object. Therefore, the traversal design of Rjson objects is rather cumbersome. Finally, I chose a way similar to ES6, providing a GetAllKeys method first, and then accessing each value one by one for traversal.

class Rjson {
    Document* json;
    Rjson(const char* jstr);
    Rjson ExtendObject(Rjson& obj);
    void AddValueInt(string k, int v);
    void AddValueString(string k, string v) ;

Default constructor

Rjson() {
        json = new Document();          //After a Document object is created by rapidjosn, you must add Value or call SetObject() to form an empty json, otherwise an error will be reported
        json->SetObject();              //I merge two operations to create an empty json

Constructor, accepts char * parameter

Rjson(const char* jstr) {           //Note that this is const char *, otherwise from string.c_str() will be forced to transfer when it is passed, otherwise it will be matched with the overloaded constructor of string parameter.
        json = new Document();      //The combination of two-step operation, simple processing, can facilitate a lot of code creation

Constructor, accepts string parameter

Rjson(string jstr) {            //Notice the way to call the overloaded constructor in the constructor.
        new (this)Rjson(jstr.c_str());

copy constructor

Rjson(const Rjson& origin) {
        json = new Document();      //Copy from
        json->CopyFrom(*(origin.json), json->GetAllocator());

Assignment operation

Rjson& operator = (const Rjson& origin) {
        new (this)Rjson(origin);        //Using copy constructor to implement

Overload [] operator

string operator[](string key) {     //Values are returned as strings
        string rs = "";
        if (json->HasMember(key.c_str())) {
            int vType;
            GetValueAndTypeByKey(key.c_str(), &rs, &vType);
        return rs;

Add value type

void AddValueInt(string k, int v) {
        string* newK = new string(k);   //New must be created
        Value aInt(kNumberType);
        json->AddMember(StringRef(newK->c_str()), aInt, json->GetAllocator());     //The addMember method is address passing

Add string type

    void AddValueString(string k, string v) {
        string* newK = new string(k);
        Value aStr(kStringType);        //New must be created
        aStr.SetString(v.c_str(), json->GetAllocator());
        json->AddMember(StringRef(newK->c_str()), aStr, json->GetAllocator());

Add object array

    void AddValueArray(string k, vector<string>& arr) {
        string* newK = new string(k);
        int len = arr.size();
        Value rows(kArrayType);
        for (int i = 0; i < len; i++) {
            Value al(kStringType);                  //New must be created
            rows.PushBack(al, json->GetAllocator());
        json->AddMember(StringRef(newK->c_str()), rows, json->GetAllocator());

Get all keys

vector<string> GetAllKeys() {   
    //Do not want to expose the Value object, use this interface plus the [] operator to complete the traversal. If you need a Value type, use the GetValueAndTypeByKey method.
        vector<string> keys;
        for (auto iter = json->MemberBegin(); iter != json->MemberEnd(); ++iter)
        return keys;

Gets the specified value and its type

There are seven value types defined by rapidjson, which need to be handled one by one

enum Type {
    kNullType = 0,      //!< null
    kFalseType = 1,     //!< false
    kTrueType = 2,      //!< true
    kObjectType = 3,    //!< object
    kArrayType = 4,     //!< array 
    kStringType = 5,    //!< string
    kNumberType = 6     //!< number

Only numeric value, string and array type are processed temporarily

void GetValueAndTypeByKey(string key, string* v, int* vType) {
        Value::ConstMemberIterator iter = json->FindMember(key.c_str());
        if (iter != json->MemberEnd()) {
            *vType = (int)(iter->value.GetType());
            if (iter->value.IsInt()) {
                std::stringstream s;
                s << iter->value.GetInt();
                *v = s.str();
            else if (iter->value.IsString()) {
                *v = iter->value.GetString();
            else if (iter->value.IsArray()) {
                *v = GetJsonString((Value&)iter->value);
            else {
                *v = "";
        else {
            *vType = kStringType;
            *v = "";

Get json string

string GetJsonString() {
        StringBuffer strBuffer;
        Writer<StringBuffer> writer(strBuffer);
        return strBuffer.GetString();

Extending json objects

Rjson ExtendObject(Rjson& obj) {
        Document* src = obj.GetOriginRapidJson();
        for (auto iter = src->MemberBegin(); iter != src->MemberEnd(); ++iter)
            if (json->HasMember(iter->name)) {          //Key exists, update
                Value& v = (*json)[iter->name];
                v.CopyFrom(iter->value, json->GetAllocator());
                //v = (Value&)std::move(vTmp);
            else {                                      //Key does not exist, new
                string* newK = new string(iter->name.GetString());
                Value vTmp;
                vTmp.CopyFrom(iter->value, json->GetAllocator());
                json->AddMember(StringRef(newK->c_str()), vTmp, json->GetAllocator());
        return *(this);

Use example

Rjson obj;
obj.AddValueString("username", "Insert test");
obj.AddValueInt("password", 3245);
cout << obj.GetJsonString() << endl;

Rjson obj2(obj);

Rjson obj3("{\"user\":\"bill\",\"age\":12}");

Project address


Series article planning

  • Design of general interface for c + + operational relational database (JSON ORM version c + +)
  • Design and implementation of rjson -- rapid JSON agent
  • Implementation and analysis of SQL it 3 database operation
  • Implementation and analysis of mysql database operation
  • Implementation and analysis of postgres database operation
  • Implementation and analysis of oracle database operation
  • Implementation and analysis of mssql database operation
  • Summary (if required)


This is the first step to encapsulate the database universal access interface, providing convenient json object operation, or writing a json object will be depressing. I miss the feeling of operating json in javascript, silky lubrication

Tags: C++ JSON Database network github

Posted on Sat, 27 Jun 2020 21:28:01 -0400 by rajeevbharti