{"id":18723554,"url":"https://github.com/ngrodzitski/json_dto","last_synced_at":"2025-04-12T14:54:17.687Z","repository":{"id":114561988,"uuid":"87241874","full_name":"ngrodzitski/json_dto","owner":"ngrodzitski","description":"A small header-only helper for converting data between json representation and c++ structs.","archived":false,"fork":false,"pushed_at":"2018-05-01T18:51:06.000Z","size":55,"stargazers_count":11,"open_issues_count":3,"forks_count":4,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-26T09:39:49.017Z","etag":null,"topics":["cplusplus","json"],"latest_commit_sha":null,"homepage":null,"language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ngrodzitski.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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":"2017-04-04T22:41:35.000Z","updated_at":"2021-03-22T03:08:04.000Z","dependencies_parsed_at":"2023-07-26T17:02:17.829Z","dependency_job_id":null,"html_url":"https://github.com/ngrodzitski/json_dto","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ngrodzitski%2Fjson_dto","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ngrodzitski%2Fjson_dto/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ngrodzitski%2Fjson_dto/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ngrodzitski%2Fjson_dto/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ngrodzitski","download_url":"https://codeload.github.com/ngrodzitski/json_dto/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248586238,"owners_count":21128995,"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":["cplusplus","json"],"created_at":"2024-11-07T13:49:07.319Z","updated_at":"2025-04-12T14:54:17.682Z","avatar_url":"https://github.com/ngrodzitski.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# MOVED\n\nCheckout actual repository here: https://github.com/Stiffstream/json_dto\n\n# What Is json_dto?\n\n*json_dto* library is a small header-only helper\nfor converting data between json representation\nand c++ structs. DTO here stands for data transfer object.\nIt was made and used as a part of a larger project\ninside [Stiffstream](http://stiffstream.com)..\nAnd since Fall 2016 is ready for public.\nWe are still using it for working with JSON in various projects.\n\nGit repository is a mirror for bitbucket repo:\n[bitbucket.org/sobjectizerteam/json_dto-0.2](https://bitbucket.org/sobjectizerteam/json_dto-0.2)\n\nA full commit history and version changes can be viewed there.\n\n# Obtain and build\n\n## Prerequisites\n\nTo use *json_dto* it is necessary to have:\n\n* C++14 compiler (VC++14.0, GCC 5.2 or above, clang 3.6 or above)\n* [rapidjson](https://github.com/miloyip/rapidjson)\n\nAnd for building with mxxru:\n\n* [rapidjson_mxxru](https://bitbucket.org/sobjectizerteam/rapidjson_mxxru-1.0)\n\t(v.1.0.0 or above)\n* [Mxx_ru](https://sourceforge.net/projects/mxxru/) 1.6.13 or above\n\nAnd for running test:\n\n* [CATCH](https://github.com/philsquared/Catch) 1.10.0\n\n## Obtaining\n\nAssuming that *Mercurial*, *Git* and *Mxx_ru* are already installed.\n\n### Cloning of Git Repository\n\n```\ngit clone https://github.com/ngrodzitski/json_dto.git\n```\nAnd then:\n```\ncd json_dto\nmxxruexternals\n```\nto download and extract *json_dto*'s dependencies.\n\n### MxxRu::externals recipe\n\nFor *json_dto* itself:\n```Ruby\nMxxRu::arch_externals :json_dto do |e|\n  e.url 'https://bitbucket.org/sobjectizerteam/json_dto-0.1/get/v.0.1.2.tar.bz2'\n\n  e.map_dir 'dev/json_dto' =\u003e 'dev'\nend\n```\n\nFor *rapidjson* and *rapidjson_mxxru* dependencies:\n```Ruby\nMxxRu::arch_externals :rapidjson do |e|\n  e.url 'https://github.com/miloyip/rapidjson/archive/v1.1.0.zip'\n\n  e.map_dir 'include/rapidjson' =\u003e 'dev/rapidjson/include'\nend\n\nMxxRu::arch_externals :rapidjson_mxxru do |e|\n  e.url 'https://bitbucket.org/sobjectizerteam/rapidjson_mxxru-1.0/get/v.1.0.0.tar.bz2'\n\n  e.map_dir 'dev/rapidjson_mxxru' =\u003e 'dev'\nend\n```\n\n## Build\n\nWhile *json_dto* is header-only library test and samples require a build.\n\nCompiling with Mxx_ru:\n```\ngit clone https://github.com/ngrodzitski/json_dto.git\ncd json_dto\nmxxruexternals\ncd dev\nruby build.rb\n```\n\n*NOTE.* It might be necessary to set up `MXX_RU_CPP_TOOLSET` environment variable,\nsee Mxxx_ru documentation for further details.\n\n# How to use it?\n\n## Getting started\n\nTo start using *json_dto* simply include `\u003cjson_dto/pub.hpp\u003e` header.\n\nThe usage principle of *json_dto* is borrowed from\n[Boost serialization](http://www.boost.org/doc/libs/1_61_0/libs/serialization/doc/tutorial.html)\nwhere *rapidjson::Value* plays the role of archive.\n\nLet's assume we have a c++ structure that must be serialized to JSON\nand deserialized from JSON:\n```C++\nstruct message_t\n{\n  std::string m_from;\n  std::int64_t m_when;\n  std::string m_text;\n};\n```\n\nFor integrating this struct with *json_dto* facilities the struct must be\nmodified as follows:\n```C++\nstruct message_t\n{\n  std::string m_from;\n  std::int64_t m_when;\n  std::string m_text;\n\n  // Entry point for json_dto.\n  template \u003c typename JSON_IO \u003e\n  void\n  json_io( JSON_IO \u0026 io )\n  {\n    io\n      \u0026 json_dto::mandatory( \"from\", m_from )\n      \u0026 json_dto::mandatory( \"when\", m_when )\n      \u0026 json_dto::mandatory( \"text\", m_text );\n  }\n};\n```\n\nHere `json_io()` function is an entry point for *json_dto* library.\nIt describes how to read the data from *rapidjson::Value*\n(that is usualy parsed from string) and how to set the data\nin *rapidjson::Value*.\n`json_io()` is a template function. It allows to have a single\ndescription for read and write operations.\nThe template is instantiated with `JSON_IO=json_dto::json_input_t`\nfor reading dto from JSON-value and `JSON_IO=json_dto::json_output_t` for writing\ndto to JSON-value. Both `json_dto::json_input_t` and `json_dto::json_output_t`\noverride `operator\u0026` for splitting io functionality.\n\nThere are also iostream-like overrides for `operator\u003c\u003c` and `operator\u003e\u003e`:\n```C++\ntemplate \u003c typename Dto \u003e\njson_input_t \u0026\noperator \u003e\u003e ( json_input_t \u0026 i, Dto \u0026 v );\n\ntemplate \u003c typename Dto \u003e\ninline json_output_t \u0026\noperator \u003c\u003c ( json_output_t \u0026 o, const Dto \u0026 v );\n```\n\nBut they are only helpful for top level read/write operations.\n\nIn general *json_dto* gets data from `rapidjson::Value` and puts\nthe data into `rapidjson::Value`. So read/write operations look like this:\n```C++\n// Read\nrapidjson::Document document;\n\n// ...\n\njson_dto::json_input_t jin{ document };\n\nmessage_t msg;\njin \u003e\u003e msg;\n\n// If no exceptions were thrown DTO contains data received from JSON.\n```\n\n```C++\n// Write\nrapidjson::Document document;\n\n// ...\n\njson_dto::json_output_t jout{ document, document.GetAllocator() };\n\nconst message_t msg = get_message();\njout \u003c\u003c msg;\n\n// If no exceptions were thrown document contains data received from DTO.\n```\n\nBut usually it is enough to work with `std::string` objects, so *json_dto*\ncomes with handy to/from string helpers:\n```C++\ntemplate \u003c typename Dto \u003e\nstd::string\nto_json( const Dto \u0026 dto );\n\ntemplate \u003c typename Type \u003e\nType\nfrom_json( const std::string \u0026 json );\n```\n\n[See full example](./dev/sample/tutorial1/main.cpp).\n\n[See full example without to/from string helpers](./dev/sample/tutorial1.1/main.cpp).\n\n## Non intrusive `json_io()`\n\nWhen it is unwanted to add an extra function to C++ structure\nit is possible to use a non intrusive `json_io()` version.\nIn previous example dto part will look like this:\n```C++\nstruct message_t\n{\n  std::string m_from;\n  std::int64_t m_when;\n  std::string m_text;\n};\n\nnamespace json_dto\n{\n\ntemplate \u003c typename Json_Io \u003e\nvoid json_io( Json_Io \u0026 io, message_t \u0026 msg )\n{\n  io\n    \u0026 json_dto::mandatory( \"from\", msg.m_from )\n    \u0026 json_dto::mandatory( \"when\", msg.m_when )\n    \u0026 json_dto::mandatory( \"text\", msg.m_text );\n}\n\n} /* namespace json_dto */\n```\n\n[See full example](./dev/sample/tutorial2/main.cpp).\n\n**Note** that it is necessary to define `json_io()` in namespace `json_dto`.\n\n## Supported field types\n\nOut of the box *json_dto* lib supports following types:\n\n* Bool: bool;\n* Numeric:\n\tstd::int16_t, std::uint16_t,\n\tstd::int32_t, std::uint32_t,\n\tstd::int64_t, std::uint64_t,\n\tdouble;\n* Strings: std::string.\n* C++17 specific: std::optional (or std::experimental::optional)\n\nExample:\n```C++\nstruct supported_types_t\n{\n  bool m_bool{ false };\n\n  std::int16_t m_int16{};\n  std::uint16_t m_uint16{};\n\n  std::int32_t m_int32{};\n  std::uint32_t m_uint32{};\n\n  std::int64_t m_int64{};\n  std::uint64_t m_uint64{};\n  double m_double{};\n\n  std::string m_string{};\n};\n\nnamespace json_dto\n{\n\ntemplate \u003c typename Json_Io \u003e\nvoid json_io( Json_Io \u0026 io, supported_types_t \u0026 obj )\n{\n  io\n    \u0026 json_dto::mandatory( \"bool\", obj.m_bool )\n    \u0026 json_dto::mandatory( \"int16\", obj.m_int16 )\n    \u0026 json_dto::mandatory( \"uint16\", obj.m_uint16 )\n    \u0026 json_dto::mandatory( \"int32\", obj.m_int32 )\n    \u0026 json_dto::mandatory( \"uint32\", obj.m_uint32 )\n    \u0026 json_dto::mandatory( \"int64\", obj.m_int64 )\n    \u0026 json_dto::mandatory( \"uint64\", obj.m_uint64 )\n    \u0026 json_dto::mandatory( \"double\", obj.m_double )\n    \u0026 json_dto::mandatory( \"string\", obj.m_string );\n}\n\n} /* namespace json_dto */\n```\n\n[See full example](./dev/sample/tutorial3/main.cpp)\n\n## Mandatory and optional fields\n\nEach data member (at least those of them which are considered to be present in JSON)\nin C++ struct binds to JSON field. Bind can be mandatory or optional.\nOptional bind is extended with default value, but it is also possible\nto set optional fields without defaults.\nAlso it is possible to add a value validator to the bind.\n\nBinds are created by `mandatory()`, `optional()` and\n`optional_no_default()` functions. These functions returns a *field binder*.\n*Binder* is an instantiation of `binder_t` template class\nwhich carries a part of internal logic\ncapable for handling field input/output operations.\nWith the help of *binders* `JSON_IO` object understands how read, write and validate\nthe underlying field.\n\n### Mandatory fields\n\nBinders for mandatory fields are created via `mandatory()` function:\n```C++\ntemplate \u003c\n    typename Field_Type,\n    typename Validator = empty_validator_t\u003e\nauto mandatory(\n  string_ref_t field_name,\n  Field_Type \u0026 field,\n  Validator validator = Validator{} );\n```\n\nFirst parameter *field_name* is of type `string_ref_t`\nwhich is an alias for `rapidjson::Value::StringRefType`.\nTypically it is enough to pass `std::string` or `char *` args\n(see *rapidjson*\n[documentation](http://rapidjson.org/classrapidjson_1_1_generic_value.html)\nfor further details).\nThe second parameter is a reference to the instance of the field value.\nThe third parameter is optional and it sets validator on fields value.\nValidators will be described later. By default `empty_validator_t`\nis used, and as it says it does nothing.\n\n### Optional fields\n\nBinders for optional fields are created via `optional()` and\n`optional_no_default()` functions:\n```C++\ntemplate \u003c\n    typename Field_Type,\n    typename Field_Default_Value_Type,\n    typename Validator = empty_validator_t\u003e\nauto optional(\n  string_ref_t field_name,\n  Field_Type \u0026 field,\n  Field_Default_Value_Type default_value,\n  Validator validator = Validator{} );\n\ntemplate \u003c\n    typename Field_Type,\n    typename Validator = empty_validator_t \u003e\nauto optional_no_default(\n  string_ref_t field_name,\n  Field_Type \u0026 field,\n  Validator validator = Validator{} );\n```\n\nParameters for functions are pretty much the same as for\n`mandatory()` functon.\n\nThe only difference is the third parameter for `optional()` function,\nit defines default value for a field if it is not defined in JSON.\n\nIn case of reading DTO, if optional field has default value\nand JSON object doesn't define this field then default value is used.\nIn case of writing DTO, if value equals to default\nthen this field wouldn't be included in JSON.\n\nFor `optional()` there is a partial specification that accepts\n`nullptr` argument as *default_value* parameter, it is usefull for\n`nullable_t\u003cT\u003e` fields.\n\nExample of using optional fields:\n```C++\nstruct message_t\n{\n  std::string m_from;\n  std::int64_t m_when;\n  std::string m_text;\n  std::string m_text_format;\n  bool m_is_private{ false };\n};\n\nnamespace json_dto\n{\n\ntemplate \u003c typename Json_Io \u003e\nvoid json_io( Json_Io \u0026 io, message_t \u0026 msg )\n{\n  io\n    \u0026 json_dto::mandatory( \"from\", msg.m_from )\n    \u0026 json_dto::mandatory( \"when\", msg.m_when )\n    \u0026 json_dto::mandatory( \"text\", msg.m_text )\n    \u0026 json_dto::optional( \"text_format\", msg.m_text_format, \"text/plain\" )\n    \u0026 json_dto::optional_no_default( \"is_private\", msg.m_is_private );\n}\n\n} /* namespace json_dto */\n```\n[See full example](./dev/sample/tutorial4/main.cpp)\n\n#### Optional fields and std::optional\n\nSince v.0.2 it is possible to use C++17's `std::optional` template as a type\nfor field. In this case `std::nullopt` can be passed as third argument to\n`json_dto::optional()` function:\n\n~~~~~{.cpp}\nstruct email_data_t\n{\n  std::string m_from;\n  std::string m_to;\n  std::string m_subject;\n  std::optional\u003c std::vector\u003c std::string \u003e \u003e m_cc;\n  std::optional\u003c std::vector\u003c std::string \u003e \u003e m_bcc;\n  ...\n  template\u003ctypename Json_Io\u003e\n  void json_io(Json_Io \u0026 io)\n  {\n    io \u0026 json_dto::mandatory(\"from\", m_from)\n      \u0026 json_dto::mandatory(\"to\", m_to)\n      \u0026 json_dto::mandatory(\"subject\", m_subject)\n      \u0026 json_dto::optional(\"cc\", m_cc, std::nullopt)\n      \u0026 json_dto::optional(\"bcc\", m_bcc, std::nullopt)\n      ...\n  }\n};\n~~~~~\n\n*Note.* If a compiler doesn't have `std::optional` but have\n`std::experimental::optional` then `std::experimental::optional` and\n`std::experimental::nullopt` can be used.\n\n## Array support\n\nJSON arrays are supported by *json_dto*, but there is one very important\nlimitation: all elements of the array must have the same type.\nTo set up an array simply use `std::vector\u003cT\u003e`.\nIf DTO member is of `std::vector\u003cT\u003e` type,\nthen corresponding JSON field is considered to be an array.\nWhile for output the elements of the array-field will be automatically\nof the same type, for successful input it is mandatory\nthat all elements of the array are convertible to vector value type.\n\nExample for array-fields:\n```C++\nstruct vector_types_t\n{\n  std::vector\u003c bool \u003e m_bool{};\n\n  std::vector\u003c std::int16_t \u003e m_int16{};\n  std::vector\u003c std::uint16_t \u003e m_uint16{};\n\n  std::vector\u003c std::int32_t \u003e m_int32{};\n  std::vector\u003c std::uint32_t \u003e m_uint32{};\n\n  std::vector\u003c std::int64_t \u003e m_int64{};\n  std::vector\u003c std::uint64_t \u003e m_uint64{};\n  std::vector\u003c double \u003e m_double{};\n\n  std::vector\u003c std::string \u003e m_string{};\n};\n\nnamespace json_dto\n{\n\ntemplate \u003c typename Json_Io \u003e\nvoid json_io( Json_Io \u0026 io, vector_types_t \u0026 obj )\n{\n  io\n    \u0026 json_dto::mandatory( \"bool\", obj.m_bool )\n    \u0026 json_dto::mandatory( \"int16\", obj.m_int16 )\n    \u0026 json_dto::mandatory( \"uint16\", obj.m_uint16 )\n    \u0026 json_dto::mandatory( \"int32\", obj.m_int32 )\n    \u0026 json_dto::mandatory( \"uint32\", obj.m_uint32 )\n    \u0026 json_dto::mandatory( \"int64\", obj.m_int64 )\n    \u0026 json_dto::mandatory( \"uint64\", obj.m_uint64 )\n    \u0026 json_dto::mandatory( \"double\", obj.m_double )\n    \u0026 json_dto::mandatory( \"string\", obj.m_string );\n}\n\n} /* namespace json_dto */\n```\n[See full example](./dev/sample/tutorial5/main.cpp)\n\n## Nullable fields\n\nTo support JSON null values, *json_dto* introduces `nullable_t\u003cT\u003e`.\nIt is required that nullable field is explicitly defined as\ndata member of type `nullable_t\u003cT\u003e`.\n\nInterface of `nullable_t\u003cT\u003e` tries to mimic `std::optional` interface.\n\nExample for `nullable_t\u003cT\u003e` field:\n```C++\nstruct message_t\n{\n  message_t() {}\n\n  message_t(\n    std::string from,\n    std::int64_t when,\n    std::string text )\n    :  m_from{ std::move( from ) }\n    ,  m_when{ when }\n    ,  m_text{ std::move( text ) }\n  {}\n\n  std::string m_from;\n  std::int64_t m_when;\n  std::string m_text;\n\n  // Log level.\n  // By default is constructed with null value.\n  json_dto::nullable_t\u003c std::int32_t \u003e m_log_level{};\n};\n\nnamespace json_dto\n{\n\ntemplate \u003c typename Json_Io \u003e\nvoid json_io( Json_Io \u0026 io, message_t \u0026 msg )\n{\n  io\n    \u0026 json_dto::mandatory( \"from\", msg.m_from )\n    \u0026 json_dto::mandatory( \"when\", msg.m_when )\n    \u0026 json_dto::mandatory( \"text\", msg.m_text )\n    \u0026 json_dto::optional( \"log_level\", msg.m_log_level, nullptr );\n}\n\n} /* namespace json_dto */\n\nvoid\nsome_function( ... )\n{\n  // ...\n  auto msg = json_dto::from_json\u003c message_t \u003e( json_data );\n\n  // ...\n\n  // If field is defined then its value can be obtained and used.\n  if( msg.m_log_level )\n    use_value( *msg.m_log_level );\n\n  // ...\n\n  msg.m_log_level = 1; // Set new value.\n\n  // ...\n\n  // equivalent to msg.m_log_level.reset();\n  msg.m_log_level = nullptr; // Reset value.\n\n  // ...\n}\n```\n[See full example](./dev/sample/tutorial6/main.cpp)\n\nHere default value for optional nullble field is `nullptr`.\nAnd it means that absence of value is a default state for a field.\nSo when converting to JSON no-value nullable field\nwouldn't be included in JSON as `\"field\":null` piece.\n\nNullable fields can be used with arrays:\n```C++\nstruct message_t\n{\n  message_t() {}\n\n  message_t(\n    std::string from,\n    std::int64_t when,\n    std::string text )\n    :  m_from{ std::move( from ) }\n    ,  m_when{ when }\n    ,  m_text{ std::move( text ) }\n  {}\n\n  // Who sent a message.\n  std::string m_from;\n\n  // When the message was sent (unixtime).\n  std::int64_t m_when;\n\n  // Message text.\n  std::string m_text;\n\n  // Log level.\n  // By default is constructed with null value.\n  json_dto::nullable_t\u003c std::int32_t \u003e m_log_level{};\n\n  json_dto::nullable_t\u003c std::vector\u003c std::string \u003e \u003e m_tags{};\n};\n\nnamespace json_dto\n{\n\ntemplate \u003c typename Json_Io \u003e\nvoid json_io( Json_Io \u0026 io, message_t \u0026 msg )\n{\n  io\n    \u0026 json_dto::mandatory( \"from\", msg.m_from )\n    \u0026 json_dto::mandatory( \"when\", msg.m_when )\n    \u0026 json_dto::mandatory( \"text\", msg.m_text )\n    \u0026 json_dto::optional( \"log_level\", msg.m_log_level, nullptr )\n    \u0026 json_dto::optional( \"tags\", msg.m_tags, nullptr );\n}\n\n} /* namespace json_dto */\n\nvoid some_function( ... )\n{\n  // ...\n  auto msg = json_dto::from_json\u003c message_t \u003e( json_data );\n\n  // ...\n\n  if( msg.m_tags )\n    use_tags( *msg.m_tags );\n\n  // ...\n}\n\nvoid some_other_function( ... )\n{\n  message_t msg{ ... };\n  // ...\n\n  // Add tags:\n  msg.m_tags.emplace(); // equivalent to msg = std::vector\u003c std::string \u003e{};\n  msg.m_tags-\u003eemplace_back( \"sample\" );\n  msg.m_tags-\u003eemplace_back( \"tutorial\" );\n\n  // ...\n}\n```\n[See full example](./dev/sample/tutorial7/main.cpp)\n\n## Complex types\n\n*json_dto* allows to construct complex types with nested objects.\nUsing nested objects is pretty much the same as using data of a simple types.\nNested objects can be optional, nullable and be elements of array-fields.\nHowever there are some constraints:\n\n* nested type must be itself integrated with *json_dto*;\n* type must be default-constructible (for input);\n* for optional fields with default value equality operator must be defined\n(more precisely an equality operator between nested type and type of p[assed default value).\n\nSuppose there is a type which is already integrated with *json_dto*:\n```C++\nstruct message_source_t\n{\n  std::int32_t m_thread_id{ 0 };\n  std::string m_subsystem{};\n\n  template \u003c typename Json_Io \u003e\n  void json_io( Json_Io \u0026 io )\n  {\n    io\n      \u0026 json_dto::optional( \"thread_id\", m_thread_id, 0 )\n      \u0026 json_dto::mandatory( \"subsystem\", m_subsystem );\n  }\n};\n```\n\nThen it can be used as a nested object in other type:\n```C++\nstruct message_t\n{\n  message_source_t m_from;\n  std::int64_t m_when;\n  std::string m_text;\n\n  template \u003c typename Json_Io \u003e\n  void json_io( Json_Io \u0026 io )\n  {\n    io\n      \u0026 json_dto::mandatory( \"from\", m_from ) // Exactly as with simple types.\n      \u0026 json_dto::mandatory( \"when\", m_when )\n      \u0026 json_dto::mandatory( \"text\", m_text );\n  }\n};\n```\n[See full example](./dev/sample/tutorial8/main.cpp)\n\nAnd\n[See full example using nested objects as nullable and arrays](./dev/sample/tutorial9/main.cpp)\n\n## Inheritance\n\n*json_dto* works well with inheritance. It is possible to use\nbase implementation of `json_io()` function or completely override it.\n\nFor example derived class can use base class like this:\n```C++\nstruct derived_t : public base_t\n{\n  //...\n\n  template \u003c typename Json_Io \u003e\n  void json_io( Json_Io \u0026 io )\n  {\n    base_t::json_io( io ); // Run io on base class.\n\n    // Run io on extra data:\n    io\n      \u0026 json_dto::mandatory( \"some_field\", m_some_field )\n      // ...\n      ;\n  }\n};\n```\n\nHowever for easier maintenance it is recommended to use non intrusive\n`json_io()` function. Because if base class is integrated with *json_dto*\nin non intrusive manner, then the following wouldn't work:\n```C++\n  template \u003c typename Json_Io \u003e\n  void\n  json_io( Json_Io \u0026 io )\n  {\n    // Base class doesn't provide such member function.\n    base_t::json_io( io ); // Run io on base class.\n    // ...\n  }\n```\n\nSo it is preferred to put inheritance this way:\n```C++\nstruct message_source_t\n{\n  std::int32_t m_thread_id{ 0 };\n  std::string m_subsystem{};\n};\n\nnamespace json_dto\n{\n\ntemplate \u003c typename Json_Io \u003e\nvoid json_io( Json_Io \u0026 io, message_source_t \u0026 m )\n{\n  io\n    \u0026 json_dto::optional( \"thread_id\", m.m_thread_id, 0 )\n    \u0026 json_dto::mandatory( \"subsystem\", m.m_subsystem );\n}\n\n} /* namespace json_dto */\n\nstruct message_t : public message_source_t\n{\n  std::int64_t m_when;\n  std::string m_text;\n\n  template \u003c typename Json_Io \u003e\n  void json_io( Json_Io \u0026 io )\n  {\n    json_dto::json_io( io, static_cast\u003c message_source_t \u0026 \u003e( *this ) );\n\n    io\n      \u0026 json_dto::mandatory( \"when\", m_when )\n      \u0026 json_dto::mandatory( \"text\", m_text );\n  }\n};\n```\n[See full example](./dev/sample/tutorial10/main.cpp)\n\n## Validators\n\n*json_dto* allows to set validator on each field.\nValidator is a function object (an object of a type supporting an\n`operator()` member function) that receives a single parameter.\n\nWhen handling input *json_dto* calls specified validator\nand passes resulting field value as an argument.\nIf validator returns without throwing exception,\nthen field value considered to be valid, and execution continues.\nOtherwise exception is catched and another will be thrown:\n`json_dto::ex_t`. This exeption contains original exception description\nsupplemented with field name information.\n\nWhen handling ouput *json_dto* calls specified validator before\ntrying to assign field value of JSON object. In all other respects\nvalidation is the same as for input.\n\nA simple example of using validators:\n```C++\nvoid\ncheck_all_7bit(\n  const std::string \u0026 text )\n{\n  auto it =\n    std::find_if(\n      std::begin( text ),\n      std::end( text ),\n      []( char c ){ return c \u0026 0x80; } );\n\n  if( std::end( text ) != it )\n  {\n    throw std::runtime_error{\n      \"non 7bit char at pos \" +\n      std::to_string( std::distance( std::begin( text ), it ) ) };\n  }\n}\n\nstruct message_t\n{\n  std::string m_from;\n  std::int64_t m_when;\n\n  // Message text. Must be 7bit ascii.\n  std::string m_text;\n\n  template \u003c typename Json_Io \u003e\n  void json_io( Json_Io \u0026 io )\n  {\n    io\n      \u0026 json_dto::mandatory( \"from\", m_from )\n      \u0026 json_dto::mandatory( \"when\", m_when )\n      \u0026 json_dto::mandatory( \"text\", m_text, check_all_7bit );\n  }\n};\n```\n[See full example](./dev/sample/tutorial11/main.cpp)\n\n### Standard validators\n\n*json_dto* comes with some useful ready to use validators for simple types.\nThey are defined in `\u003cjson_dto/pub.hpp\u003e` header.\n\nStandard validators curently available:\n\n* `min_max_constraint_t\u003c Num \u003e` - range validator, targeted for numeric types;\n* `one_of_validator_t\u003c T \u003e` - validator for set of values.\n\nStandard validators are template classes with overloaded `operator()`.\nAnd as they are template classes so for convenience\nfor each validator there is an auxiliary function that helps deduce\ntype of template instance from arguments:\n```C++\ntemplate \u003c typename Number \u003e\nauto min_max_constraint( Number min_value, Number max_value );\n\ntemplate \u003c typename Field_Type \u003e\nauto one_of_constraint( std::initializer_list\u003c Field_Type \u003e values );\n```\n\n[See full example with standard validators](./dev/sample/tutorial12/main.cpp)\n\n## User defined IO\n\nIt is possible to define custom IO logic for a specific type.\nIt might be useful for types when using object is an overkill,\nfor example time point that can be stored in format of 'YYYY.MM.DD hh:mm:ss'\nor some token composed of several small items like '\u003citem1\u003e-\u003citem1\u003e-\u003citem3\u003e'.\n\nThere are two way to introduce custom IO logic.\n\nThe first way uses C++'s Argument Dependent Lookup feature:\nan user should define `read_json_value` and `write_json_value` in the same\nnamespace where types are defined. The right implementations of\n`read_json_value` and `write_json_value` will be found by C++ compiler automatically.\nFor example:\n```C++\nnamespace importance_levels\n{\n\nenum class level_t\n  {\n    low,\n    normal,\n    high\n  };\n\n// read_json_value and write_json_value for level_t are\n// defined in importance_levels namespace.\n// They will be found by argument dependent lookup.\nvoid read_json_value(\n  level_t \u0026 value,\n  const rapidjson::Value \u0026 from)\n{...}\n\nvoid\nwrite_json_value(\n  const level_t \u0026 value,\n  rapidjson::Value \u0026 object,\n  rapidjson::MemoryPoolAllocator\u003c\u003e \u0026 allocator)\n{...}\n\n} /* namespace importance_levels */\n```\nhis approach also allows to define `read_json_value` and `write_json_value`\nfor user's template type. For example:\n```C++\nnamespace demo\n{\n\ntemplate\u003ctypename T\u003e\nclass some_template\n{...}\n\ntemplate\u003ctypename T\u003e\nvoid\nread_json_value(\n  some_template\u003cT\u003e \u0026 value,\n  const rapidjson::Value \u0026 from)\n{...}\n\ntemplate\u003ctypename T\u003e\nvoid\nwrite_json_value(\n  const some_template\u003cT\u003e \u0026 value,\n  rapidjson::Value \u0026 object,\n  rapidjson::MemoryPoolAllocator\u003c\u003e \u0026 allocator)\n{...}\n\n} /* namespace demo */\n\nstruct my_data_t\n{\n  demo::some_template\u003cint\u003e m_first;\n  demo::some_template\u003cdouble\u003e m_second;\n  ...\n  template\u003ctypename Json_Io\u003e\n  void json_io(Json_Io \u0026 io)\n  {\n    io \u0026 json_dto::mandatory(\"first\", m_first)\n      \u0026 json_dto::mandatory(\"second\", m_second)\n      ...\n  }\n};\n```\n[See full example with custom IO and ADL](./dev/sample/tutorial15/main.cpp)\n\nThe second way uses explicit template specialization for 2 functons\ninside `json_dto` namespace:\n```c++\nnamespace json_dto\n{\n\ntemplate\u003c\u003e\nvoid read_json_value(\n  Custom_Type \u0026 v,\n  const rapidjson::Value \u0026 object)\n{\n  // ...\n}\n\ntemplate\u003c\u003e\nvoid write_json_value(\n  const Custom_Type \u0026 v,\n  rapidjson::Value \u0026 object,\n  rapidjson::MemoryPoolAllocator\u003c\u003e \u0026 allocator)\n{\n  // ...\n}\n\n} /* namespace json_dto */\n```\n\n*json_dto* will consider these specializations for using with\nspecified `Custom_Type`. This way can be used when it is impossible\nto place `read_json_value` and `write_json_value` into the namespace where\nthe type if defined (for example if it is standard type like `std::filesystem::path`).\n\n[See full example with custom IO](./dev/sample/tutorial14/main.cpp)\n\n# License\n\n*json_dto* is distributed under\n[BSD-3-Clause](http://spdx.org/licenses/BSD-3-Clause.html) license. See LICENSE\nfile for more information.\n\nFor the license of *rapidson* library see LICENSE file in *rapidson*\ndistributive.\n\nFor the license of *rapidson_mxxru* library see LICENSE file in *rapidson_mxxru*\ndistributive.\n\nFor the license of *CATCH* library see LICENSE file in *CATCH*\ndistributive.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fngrodzitski%2Fjson_dto","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fngrodzitski%2Fjson_dto","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fngrodzitski%2Fjson_dto/lists"}