Skip to content

A tool for JSON & C++ Mapping. Convert json string to c++ class, and convert c++ class to json string in reverse.

License

Notifications You must be signed in to change notification settings

nasacj/json2cpp

 
 

Repository files navigation

json2cpp

Join the chat at https://gitter.im/nasacj/json2cpp

A tool for JSON & C++ Mapping

Copyright (C) 2016, ICSON company, ZhengFeng Rao, NASaCJ. All rights reserved.

Build Status

Platfrom Linux
Status Build Status

Introduction

JSON is a kind of Object notation. When programmers deal with the json strings by C++ json APIs (eg, RapidJSON, jsoncpp) they have to write codes for parsing each different Class, which there may be a lot of similar repeated API calling codes. So json2cpp can help programmer to auto-generate the C++ codes for transferring form JSON to C++ and conversely. json2cpp is a script tool written in python language. It uses pyparsing to parse a Modeling file to C++ files and RapidJSON, jsoncpp for C++ to parse the JSON.

Installation before use

  • json2cpp depends on Python and pyparsing, so make sure that Python has been installed on your System
  • For installing pyparsing, use "easy_install" to install it through command line:
user@localhost $ sudo easy_install pyparsing

Download & Run Sample

Thie simple instruction shows a common running command of json2cpp

git clone https://github.com/nasacj/json2cpp
cd json2cpp
./json2cpp.py rapidjson sample.jsf test
cd test/test
make
./test

License

See the LICENSE file for details. In summary, json2cpp is licensed under the MIT license, or public domain if desired and recognized in your jurisdiction. json2cpp uses RapidJSON & jsoncpp, which 2 are both under MIT license.

Usage

Before use json2cpp, a definition file is required:

Define the class

As sample.jsf file shows, user can define the class structure as C++ sytle. The classes are according to the JSON objects:

Sample JSON Object for Request

{
    "sourceId": 1,
    "orgId": 10,
    "ivcType": 100,
    "reqNo": "asd",
    "payerNo": "10032-11",
    "businessIds": [
        "saddd",
        "xxxx"
    ],
    "invoiceTicket": {
        "invoiceType": "Normal",
        "invoiceCode": "200001",
        "invoiceAddress": {
            "provinceNo": 10001,
            "provinceStr": "New York",
        },
        "optionalAddress": [
            {
                "provinceNo": 10002,
                "provinceStr": "Shanghi",
            },
            {
                "provinceNo": 10003,
                "provinceStr": "Beijing",
            }
        ]
    }
}

Sample JSON Object for Response:

{
    "code": "200",
    "msg": "This is msg",
    "reqNo": "100200012",
    "businessIds": [
        "111asd",
        "2cde2"
    ],
    "invoiceTicket": {
        "invoiceType": "Normal",
        "invoiceCode": "200001",
        "invoiceAddress": {
            "provinceNo": 10001,
            "provinceStr": "Shanghai",
        },
        "optionalAddress": [
            {
                "provinceNo": 10002,
                "provinceStr": "Beijing",
            },
            {
                "provinceNo": 10003,
                "provinceStr": "Hong Kong",
            }
        ]
    }
}

Definitation of Class, Request and Response:

//namespace Definition
namespace jsf;

//Class Definition
@description="Address Structure"  //@descpription is optional
class Address
{
    @jsonname="provinceNo", description="Province ID" //@descpription is optional
    int provinceNo;	
	
    @jsonname="provinceStr", description="Province"
    string province;
};

//@descpription is optional
class InvoiceTicket
{
    @jsonname="invoiceType" //@descpription is optional
    string invoiceType;
	
    @jsonname="invoiceCode", description="Invoice Code"
    string invoiceCode;

    @jsonname="invoiceAddress", description="Inoice Address"
    Address address;

    @jsonname="optionalAddress"
    vector<Address> optionalAddress; //Only use vector for list handling
};

//The Interface which handles the serialization of JSON
@description="Add Invoice Interface"
Interface AddInvoice {
    Request {
        @jsonname="sourceId", description="Source"
        int source;

        @jsonname="orgId", description="Organization"
        int organizationId;

        @jsonname="ivcType",description="Type"
        int invoiceType;

        @jsonname="reqNo", description="Rquest Number"
        string requestNo;

        @jsonname="payerNo", description="Payer No"
        string payNo;

        @jsonname="receiverNo", description="ReceiverNo", optional="true" //Optional member
        string receiverNo ;

        @jsonname="businessIds", description="Business ID List"
        vector<string> bussinessIds;
		
        @jsonname="invoiceTicket", description="Invoice Ticket"
        InvoiceTicket invoiceTicket;
	};

	Response {
        @jsonname="code", description="Return Code"
        string code;

        @jsonname="msg", description="Message"
        string message;

        @jsonname="reqNo", description="Require Number"
        string requestNo;

        @jsonname="businessIds", description="BusinessID", optional="true"
        vector<string> bussinessIds ;
		
        @jsonname="invoiceTicket", description="Invoice Ticket"
        InvoiceTicket invoiceTicket;
	};
};

Generate the C++ Class files

./json2cpp.py rapidjson sample.jsf dir_test

Command json2cpp takes 3 arguements: {rapidjson/jsoncpp} {Class definitation File} {Directory} Outputs in dir_test path is organized by the namespace defined in sample.jsf:

dir_test
├── jsf
     ├── AddInvoice.h
     ├── Address.h
     ├── InvoiceTicket.h
     ├── json2cpp.h
     ├── base.h
     ├── macro.h
     └── rapidjson
            ├── ......
          ......

Class Usage

base.h: defines the basic object access:

  • Field<>: Every json object in interface class are all Field type. It has Get/SetVaule()
  • IRequest: ToJson() serialize C++ Object to JSON string
  • IResponse: FromJson() unserialize JSON string to C++ Object macro.h: defines some marcos for internel use. json2cpp.h: include all header files, provide for other to use.

json2cpp will generate a hpp file each user defined class and interface. AddInvoice.h: interface AddInvoice implemention. AddWare.h: interface AddWare implemention. Address.h: user define class Address implemention. InvoiceTicket.h: user define class InvoiceTicket implemetion.

all you have to do is include header file "json2cpp.h", and use the classes generated.

C++ Sample Code:

#include "json2cpp.h"

/**** Request Sample ****/
AddInvoiceRequest request;
Address address;
Address address1;
InvoiceTicket invoTic;

address.m_provinceNo.SetValue(10001);
... //set address and address1 members
invoTic.m_invoiceType.SetValue("Normal");
... //set invoTic members

vector<Address> v_addr;
v_addr.push_back(address1);
invoTic.m_optionalAddress.SetValue(v_addr);

//Set the Request values:
request.m_source.SetValue(1);
request.m_organizationId.SetValue(10);
request.m_invoiceType.SetValue(100);
request.m_requestNo.SetValue("asd");
request.m_payNo.SetValue("10032-11");
std::vector<std::string> bid;
bid.push_back("saddd");
bid.push_back("xxxx");
request.m_bussinessIds.SetValue(bid);
request.m_invoiceTicket.SetValue(invoTic);

std::string str;
std::string error;
uint32_t ret = request.ToJson(str, error);
if (json2cpp::ERR_OK != ret)
{
    std::cout<<"error:"<<ret<<", "<<error<<std::endl;
    return;
}

/**** Response Sample ****/
ifstream fin("json.txt");
getline(fin,str);
uint32_t status = 200;
AddInvoiceResponse response;
uint32_t ret = response.FromJson(str, status);
if(ret != json2cpp::ERR_OK)
{
    std::cout<<"error:"<<ret<<", "<<response.m_JSFMessage.GetValue()<<std::endl;
    return;
}

Grammar

//namespace, allow 0 or more
(namespace {name_space};)

//user define class, allow 0 or more
(
(@description="{description_str}")
class {class_name}{
	@jsonname={json_filed_name}(,description="{description_str}", optional=["true","false"], default="{default_value_str}")
	[field_type] {field_name}; 
};
)
 
 //interface, allow 1 or more
(@description="{description_str}")
Interface {interface_name}{
	//request, must have only 1 for every interface
	Request{
		@jsonname={json_filed_name}(,description="{description_str}", optional=["true","false"], default="{default_value_str}")
		[field_type] {field_name} (optional); 
	};
	
	//response, must have only 1 for every interface
	Response{
		@jsonname={json_filed_name}(,description="{description_str}", optional=["true","false"], default="{default_value_str}")
		[field_type] {field_name} (optional); 
	};
};

Conventions:

  1. () means the grammar token is optional, it can be defined 0 or 1
  2. {} means variable name
  3. @ means comments
  4. [] means specified value of the set

Details:

  1. {name_space} means C++ style namespace

  2. {class_name}, {interface_name}, {field_name}, {json_filed_name} means self-defined struct/class, Interface, Field Name, JSON Field name. They can be any valid string

  3. User can define 1 or more class, the definitation sequence should follow the C++ style

  4. User can define 1 or more Interface,each Interface MUST have a pair of request/response objects

  5. @ means comments,now it supports jsonname, description, optional, default key-words:

    Key-Word Description
    jsonname JSON Field Name [It MUST be specified]
    description It will be generated into C++ code for comments [Optional]
    optional Specifies the JSON field is optional,value should be "true" or "false",default is"false" [Optional]
    default Specifies the default value of C++ member feild [Optional]
  6. [field_type] Filed Type. Now supporting short, int, bool, uint32_t, uint64_t, int64_t, double, self-define class T and vector<T>.

  7. Supports C++ sytle comments like //comments and /*comments*/ , the commots will be ignored when being parsing.

Anonymous Array

json2cpp supports anonymous array Request/Response, like the following JSON string:

[
    {
        "provinceNo": 10002,
        "provinceStr": "Beijing",
    },
    {
        "provinceNo": 10003,
        "provinceStr": "Hong Kong",
    }
]

This JSON string only contains an anonymous array of "Address", so the grammar is defined as following style:

@description="AddWare"
Interface AddWare{
	Request {
		@jsonname="", description="Request Addresses"
		vector<Address> addresses;
	};
	
	Response {
		.......
	};

When Request/Respons is an anonymous array JSON string, the @jsonname MUST be defined as "" (null), and the Field should ONLY contains ONE AND ONLY ONE vector type class or normal type (e.g. vector<Address>, vector<int>).

Inheritance

User can use defined Class to be inherited to Request/Response, which means user can reuse the definitation of a Class, put the fields of that class into Request/Response. For instance, Address has 2 fields: {int, string}. If the Request and Response are both required as a single Address Object (NOT an Object contains an Address). So the definitation file can be written as following:

// Tedious definitation:
@description="AddWare"
Interface AddWare{
	Request {
		@jsonname="provinceNo", description="Province ID" //@descpription is optional
		int provinceNo;	
	
		@jsonname="provinceStr", description="Province"
		string province;
	};

	Response {
		@jsonname="provinceNo", description="Province ID" //@descpription is optional
		int provinceNo;	
	
		@jsonname="provinceStr", description="Province"
		string province;
	};
};

// Can be simplified as following --->
@description="AddWare"
Interface AddWare{
	Request(Address) {};
	Response(Address){};
};
Inheritance Grammar Explanation
  • If (class_type) follows Request/Response, the Fields in Request/Response is optional (ZeroOrMore).
  • If Inheritance is not used, Fields in Request/Response is OneOrMore

About

A tool for JSON & C++ Mapping. Convert json string to c++ class, and convert c++ class to json string in reverse.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • C++ 81.5%
  • Python 13.9%
  • C 4.5%
  • Shell 0.1%