{"id":13431237,"url":"https://github.com/jorgen/json_struct","last_synced_at":"2025-03-16T11:31:20.709Z","repository":{"id":6295789,"uuid":"7530309","full_name":"jorgen/json_struct","owner":"jorgen","description":"json_struct is a single header only C++ library for parsing JSON directly to C++ structs and vice versa","archived":false,"fork":false,"pushed_at":"2024-09-19T22:33:44.000Z","size":3292,"stargazers_count":421,"open_issues_count":3,"forks_count":57,"subscribers_count":16,"default_branch":"master","last_synced_at":"2024-10-28T11:52:07.288Z","etag":null,"topics":["c-plus-plus","deserialization","json","parse","serialization","template-metaprogramming","template-specialisations"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jorgen.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"COPYING","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2013-01-09T22:32:58.000Z","updated_at":"2024-10-26T11:44:32.000Z","dependencies_parsed_at":"2023-02-10T23:00:46.571Z","dependency_job_id":"d9c6d6d2-9b54-4db4-8ef7-f2f5e9157a34","html_url":"https://github.com/jorgen/json_struct","commit_stats":{"total_commits":534,"total_committers":13,"mean_commits":41.07692307692308,"dds":"0.14794007490636707","last_synced_commit":"9b719771470536763430703b7f04acc558dafe56"},"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jorgen%2Fjson_struct","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jorgen%2Fjson_struct/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jorgen%2Fjson_struct/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jorgen%2Fjson_struct/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jorgen","download_url":"https://codeload.github.com/jorgen/json_struct/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243862807,"owners_count":20360213,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["c-plus-plus","deserialization","json","parse","serialization","template-metaprogramming","template-specialisations"],"created_at":"2024-07-31T02:01:01.562Z","updated_at":"2025-03-16T11:31:19.588Z","avatar_url":"https://github.com/jorgen.png","language":"C++","readme":"# **Structurize your JSON**\n\n[![Build status](https://ci.appveyor.com/api/projects/status/mduab0w8u12atfbu?svg=true)](https://ci.appveyor.com/project/jorgen36373/json-struct)\n[![ClusterFuzzLite PR fuzzing](https://github.com/jorgen/json_struct/actions/workflows/cflite_pr.yml/badge.svg)](https://github.com/jorgen/json_struct/actions/workflows/cflite_pr.yml)\n\njson_struct is a single header only library that parses JSON to C++ structs/classes\nand serializing structs/classes to JSON.\n\nIt is intended to be used by copying the json_struct.h file from the include\nfolder into the include path for the project. It is only the json_struct.h file\nthat is needed to serialize and deserialize json from structures.\n\nIt is dependent on some C++11 features and is tested on newer versions of gcc\nand clang. It is also tested on VS 2015 and newer.\n\n### Structs\n\njson_struct can parse JSON and automatically populate structures with content\nby adding some metadata to the C++ structs.\n\n```json\n{\n    \"One\" : 1,\n    \"Two\" : \"two\",\n    \"Three\" : 3.333\n}\n```\n\ncan be parsed into a structure defined like this:\n\n```c++\nstruct JsonObject\n{\n    int One;\n    std::string Two;\n    double Three;\n\n    JS_OBJ(One, Two, Three);\n};\n```\n\nor\n\n```c++\nstruct JsonObject\n{\n    int One;\n    std::string Two;\n    double Three;\n};\nJS_OBJ_EXT(JsonObject, One, Two, Three);\n```\n\nPopulating the struct would look like this:\n\n```c++\nJS::ParseContext context(json_data);\nJsonObject obj;\ncontext.parseTo(obj);\n```\n\nSerializing the struct to json could be done like this:\n\n```c++\nstd::string pretty_json = JS::serializeStruct(obj);\n// or\nstd::string compact_json = JS::serializeStruct(obj, JS::SerializerOptions(JS::SerializerOptions::Compact));\n```\n\n### Maps\n\nSometimes the structure of the JSON is dependent on some value in the JSON. Say there is some input JSON that describes a transportation vehicle.\nIt can looks something like this\n```json\n{\n  \"type\" : \"car\",\n  \"wheels\" : 4,\n  \"electric\" : true,\n...\n}\n```\nor it could look like this:\n```json\n{\n  \"type\" : \"sailboat\",\n  \"sail_area_m2\" : 106.5,\n  \"swimming_platform\": true,\n...\n}\n```\n\nThis doesn't fit well with the static nature of json_struct. However, it is\npossible to parse the JSON into a map structure, query some child members for\ndata and then dispatch the conversion into an appropriate type.\n\n```c++\nvoid handle_data(const char *data, size_t size)\n{\n  JS::Map map;\n  JS::ParseContext parseContext(data, size, map);\n  if (parseContext.error != JS::Error::NoError)\n  {\n    fprintf(stderr, \"Failed to parse Json:\\n%s\\n\", parseContext.makeErrorString().c_str());\n    return;\n  }\n  VehicleType vehicleType = map.castTo\u003cVehicleType\u003e(\"type\", parseContext);\n  if (parseContext.error != JS::Error::NoError)\n  {\n    fprintf(stderr, \"Failed to extract type:\\n%s\\n\", parseContext.makeErrorString().c_str());\n    return;\n  }\n  switch (vehicleType)\n  {\n  case VehicleType::car:\n  {\n    Car car = map.castTo\u003cCar\u003e(parseContext);\n    if (parseContext.error != JS::Error::NoError)\n    {\n      //error handling \n    }\n    handle_car(car);\n    break;\n  }\n  case VehicleType::sailboat:\n    Sailboat sailboat;\n    map.castToType(parseContext, sailboat);\n    if (parseContext.error != JS::Error::NoError)\n    {\n      //error handling \n    }\n    handle_sailboat(sailboat);\n    break;\n  }\n}\n```\n\nHere we parse the JSON into a `JS::Map`. This map lets us query if the map\ncontains a member and it enables us to convert that member into a type. In the example we convert it to the VehicleType:\n```c++\n  VehicleType vehicleType = map.castTo\u003cVehicleType\u003e(\"type\", parseContext);\n```\nThen we can inspect the value of the type child and cast the entire object into\nthe desired type. The `cast` functions have two signatures: `castTo` and\n`castToValue`. `castTo` returnes the value type, however, if the object has\nalready been allocated and just needs to populated then `castToType`.\n`castToType` has the added bonus of not needing to specify the template type\nsince this is deduced by the parameter. Casting the whole object has the same semantics it only misses the \"name\" parameter:\n```c++\n    Car car = map.castTo\u003cCar\u003e(parseContext);\n    // or\n    Sailboat sailboat;\n    map.castToType(parseContext, sailboat);\n```\n\n### Demystifying the Macros\nThe JS_OBJ macro adds a static meta object to the struct/class. It does not\naffect the semantics or size of the struct/class. It automatically applies\nanother macro to the member arguments, getting the name and member pointer.\nThere are other macros that are more verbose, but that gives more flexibility.\n\nThe JS_OBJECT macro requires that all the members are passed in a JS_MEMBER\nmacro. An example of these macros being applied would look like this:\n```c++\nstruct JsonObject\n{\n    int One;\n    std::string Two;\n    double Three;\n\n    JS_OBJECT(JS_MEMBER(One)\n            , JS_MEMBER(Two)\n            , JS_MEMBER(Three));\n};\n```\n\nThis doesn't add any value, but say you want to have a different JSON key for a\nmember than the name, or maybe you want to add some alias keys, then this\ncould be done like this:\n```c++\nstruct JsonObject\n{\n    int One;\n    std::string Two;\n    double Three;\n\n    JS_OBJECT(JS_MEMBER(One)\n            , JS_MEMBER_WITH_NAME(Two, \"TheTwo\")\n            , JS_MEMBER_ALIASES(Three, \"TheThree\", \"the_three\"));\n};\n```\n\nThe difference between the _WITH_NAME and _ALIASES macros is that the\n_WITH_NAME macro ignores the member name and uses the supplied name, while the\naliases adds a list of names to be checked after the name of the member is\nchecked.\n\nIts not possible to use the JS_MEMBER macros with the JS_OBJ macro, since then\nit tries to apply the JS_MEMBER macro twice on member.\n\n### TypeHandler\nFor objects the meta information is generated with JS_OBJ and JS_OBJECT macros,\nbut there might be types that doesn't fit the meta information interface, ie\nthey are not JSON Object types. Then its possible to define how these specific\nclasses are serialized and deserialized with the TypeHandler interface.\n\nWhen the JS::ParseContext tries to parse a type it will look for a template\nspecialisation of the type:\n\n```c++\nnamespace JS {\n    template\u003ctypename T\u003e\n    struct TypeHandler;\n}\n```\n\nThere are a number of predefined template specialisations for types such as:\n\n* `std::string`\n* `double`\n* `float`\n* `uint8_t`\n* `int16_t`\n* `uint16_t`\n* `int32_t`\n* `uint32_t`\n* `int64_t`\n* `uint64_t`\n* `std::unique_ptr`\n* `bool`\n* `std::vector`\n* `[T]`\n\nIts not often necessary, but when you need to define your own serialization and\ndeserialization it's done like this:\n\n```c++\nnamespace JS {\ntemplate\u003c\u003e\nstruct TypeHandler\u003cuint32_t\u003e\n{\npublic:\n    static inline Error to(uint32_t \u0026to_type, ParseContext \u0026context)\n    {\n        char *pointer;\n        unsigned long value = strtoul(context.token.value.data, \u0026pointer, 10);\n        to_type = static_cast\u003cunsigned int\u003e(value);\n        if (context.token.value.data == pointer)\n            return Error::FailedToParseInt;\n        return Error::NoError;\n    }\n\n    static void from(const uint32_t \u0026from_type, Token \u0026token, Serializer \u0026serializer)\n    {\n        std::string buf = std::to_string(from_type);\n        token.value_type = Type::Number;\n        token.value.data = buf.data();\n        token.value.size = buf.size();\n        serializer.write(token);\n    }\n};\n}\n```\n\nThis gives you complete control of serialization deserialization of a type and it can unfold to a JSON object or array if needed.\n\nFor more information checkout the examples at:\nhttps://github.com/jorgen/json_struct/tree/master/examples\n\nand have a look at the more complete unit tests at:\nhttps://github.com/jorgen/json_struct/tree/master/tests\n\n\n## SAST Tools\n\n- [PVS-Studio](https://pvs-studio.com/pvs-studio/?utm_source=website\u0026utm_medium=github\u0026utm_campaign=open_source) - static analyzer for C, C++, C#, and Java code.\n\n## DAST Tools\nAll tests are run with Clang Address Sanitizer and Memory Sanitizers on pull requests.\n- [Clang Address Sanitizer](https://clang.llvm.org/docs/AddressSanitizer.html)\n- [Clang Memory Sanitizer](https://clang.llvm.org/docs/MemorySanitizer.html)\n","funding_links":[],"categories":["C++","JSON","Data Formats","Libraries"],"sub_categories":["Parsing \u0026 Serialization"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjorgen%2Fjson_struct","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjorgen%2Fjson_struct","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjorgen%2Fjson_struct/lists"}