Упрощаем переход от JSON к C++ структурам и
обратноНиколай Гродзицкий
О чем пойдет речь?
2
О чем пойдет речь?DTO
struct message_source_t{ // Worker thread. std::int32_t m_thread_id;
// Sender. std::string m_subsystem;};
struct message_t{ // Who sent a message. message_source_t m_from;
// When the message was sent (unixtime). std::tm m_when;
// Message text. std::string m_text;}; 3
О чем пойдет речь?DTO
struct message_source_t{ // Worker thread. std::int32_t m_thread_id;
// Sender. std::string m_subsystem;};
struct message_t{ // Who sent a message. message_source_t m_from;
// When the message was sent (unixtime). std::tm m_when;
// Message text. std::string m_text;};
JSON
“JSON (JavaScript Object Notation) is a lightweight data-interchange format.”
http://www.json.org/
4
О чем пойдет речь?DTO
struct message_source_t{ // Worker thread. std::int32_t m_thread_id;
// Sender. std::string m_subsystem;};
struct message_t{ // Who sent a message. message_source_t m_from;
// When the message was sent (unixtime). std::tm m_when;
// Message text. std::string m_text;};
JSON
“JSON (JavaScript Object Notation) is a lightweight data-interchange format.”
http://www.json.org/
{ "from" : { "thread_id" : 4242, "sybsystem" : "json_dto" }, "when" : "2016.09.28 19:55:00" , "text" : "Hello world!"}
5
Это кому-нибудь нужно?
6
Это кому-нибудь нужно?Да, похоже, что нужно:
● http://stackoverflow.com/questions/8220130/converting-c-class-to-json● http://stackoverflow.com/questions/17549906/c-json-serialization● http://stackoverflow.com/questions/35955137/convert-json-string-to-c-object-u
sing-casablanca-rest-sdk
7
Это кому-нибудь нужно?
8
Это кому-нибудь нужно?I'd like to create a JSON string containing the instance variables of my class.For example,
class Example { std::string string; std::map<std::string, std:string> map; std::vector<int> vector; };
would become:
{ "string":"the-string-value", "map": { "key1":"val1", "key2":"val2" }, "vector":[1,2,3,4]}
9
Это кому-нибудь нужно?“I want a way to serialize and deserialize Objects to JSON, as automatic as possible.”
“Serialize: For me, the ideal way is that if I call in an instance JSONSerialize() it returns an string with a JSON object that has all the public properties of the object as "name_of_property": "value".”
“Deserialize: Just make an instance of the given object (let's say a dog) and call JSONDeserialize(json_string), and that should fill all the public properties, creating the needed objects in case that the properties are not primitives, or the needed collections.”
10
Это кому-нибудь нужно?
“Is there any simple way to convert a json string in an object and back as shown in this example? (http://www.newtonsoft.com/json/help/html/serializingjson.htm)”
11
Это кому-нибудь нужно?
В целом, хочется для заданной структуры (класса) иметь возможность конвертировать инстанс в JSON и наоборот получить инстанс из JSON.
При этом чтобы дополнительного кода требовалось как можно меньше.
12
Что такое json_dto?
13
Что такое json_dto?● Нет, это не еще один JSON парсер
14
Что такое json_dto?● Нет, это не еще один JSON парсер
○ В качестве парсера используется RapidJSON
15
Что такое json_dto?● Нет, это не еще один JSON парсер
○ В качестве парсера используется RapidJSONВыбор был сделан на основе nativejson-benchmark
16
Что такое json_dto?● Нет, это не еще один JSON парсер
○ В качестве парсера используется RapidJSONВыбор был сделан на основе nativejson-benchmark
● Инструмент для отображения DTO в JSON и обратно по заданным правилам
17
Что такое json_dto?● Нет, это не еще один JSON парсер
○ В качестве парсера используется RapidJSONВыбор был сделан на основе nativejson-benchmark
● Инструмент для отображения DTO в JSON и обратно по заданным правилам
○ Header-only (C++14)
18
Что такое json_dto?● Нет, это не еще один JSON парсер
○ В качестве парсера используется RapidJSONВыбор был сделан на основе nativejson-benchmark
● Инструмент для отображения DTO в JSON и обратно по заданным правилам
○ Header-only (C++14)■ зависит только от RapidJSON (тоже header-only)
19
Что такое json_dto?● Нет, это не еще один JSON парсер
○ В качестве парсера используется RapidJSONВыбор был сделан на основе nativejson-benchmark
● Инструмент для отображения DTO в JSON и обратно по заданным правилам
○ Header-only (C++14)○ Требует немного дополнительного кода
20
Что такое json_dto?● Нет, это не еще один JSON парсер
○ В качестве парсера используется RapidJSONВыбор был сделан на основе nativejson-benchmark
● Инструмент для отображения DTO в JSON и обратно по заданным правилам
○ Header-only (C++14)○ Требует немного дополнительного кода
■ Механика описания правил позаимствована у Boost Serialization
21
Что такое json_dto?● Нет, это не еще один JSON парсер
○ В качестве парсера используется RapidJSONВыбор был сделан на основе nativejson-benchmark
● Инструмент для отображения DTO в JSON и обратно по заданным правилам
○ Header-only (C++14)○ Требует немного дополнительного кода
■ Механика описания правил позаимствована у Boost Serialization■ Для одного DTO требуется написать одну функцию
22
Что такое json_dto?● Нет, это не еще один JSON парсер
○ В качестве парсера используется RapidJSONВыбор был сделан на основе nativejson-benchmark
● Инструмент для отображения DTO в JSON и обратно по заданным правилам
○ Header-only (C++14)○ Требует немного дополнительного кода○ Интуитивно понятная поддержка типов
23
Что такое json_dto?● Нет, это не еще один JSON парсер
○ В качестве парсера используется RapidJSONВыбор был сделан на основе nativejson-benchmark
● Инструмент для отображения DTO в JSON и обратно по заданным правилам
○ Header-only (C++14)○ Требует немного дополнительного кода○ Интуитивно понятная поддержка типов
■ Простые типы: String, Number, Bool
24
Что такое json_dto?● Нет, это не еще один JSON парсер
○ В качестве парсера используется RapidJSONВыбор был сделан на основе nativejson-benchmark
● Инструмент для отображения DTO в JSON и обратно по заданным правилам
○ Header-only (C++14)○ Требует немного дополнительного кода○ Интуитивно понятная поддержка типов
■ Простые типы: String, Number, Bool■ Массивы (Array)
25
Что такое json_dto?● Нет, это не еще один JSON парсер
○ В качестве парсера используется RapidJSONВыбор был сделан на основе nativejson-benchmark
● Инструмент для отображения DTO в JSON и обратно по заданным правилам
○ Header-only (C++14)○ Требует немного дополнительного кода○ Интуитивно понятная поддержка типов
■ Простые типы: String, Number, Bool■ Массивы (Array)■ Объекты (Object)
26
Что такое json_dto?● Нет, это не еще один JSON парсер
○ В качестве парсера используется RapidJSONВыбор был сделан на основе nativejson-benchmark
● Инструмент для отображения DTO в JSON и обратно по заданным правилам
○ Header-only (C++14)○ Требует немного дополнительного кода○ Интуитивно понятная поддержка типов○ Поддержка null-полей
27
Что такое json_dto?● Нет, это не еще один JSON парсер
○ В качестве парсера используется RapidJSONВыбор был сделан на основе nativejson-benchmark
● Инструмент для отображения DTO в JSON и обратно по заданным правилам
○ Header-only (C++14)○ Требует немного дополнительного кода○ Интуитивно понятная поддержка типов○ Поддержка null-полей○ Опциональные поля и значения по умолчанию
28
Давайте посмотрим, что умеет json_dto
29
Hello world!struct message_t{ std::string m_from; std::string m_text;};
30
Hello world!struct message_t{ std::string m_from; std::string m_text;};
{ "from" : "<from>", "text" : "<text>" }
31
Hello world!struct message_t{ std::string m_from; std::string m_text;};
#include <json_dto/pub.hpp>// ...
struct message_t{ std::string m_from; std::string m_text;
template < typename JSON_IO > void json_io( JSON_IO & io ) { io & json_dto::mandatory( "from", m_from ) & json_dto::mandatory( "text", m_text ); }};
32
Hello world!Чтение:const std::string json_data{ R"({ "from" : "json_dto", "text" : "Hello world!" })" };
auto msg = json_dto::from_json< message_t >( json_data );
Запись:auto json_str = json_dto::to_json( msg );
#include <json_dto/pub.hpp >// ...
struct message_t{ std::string m_from; std::string m_text;
template < typename JSON_IO > void json_io( JSON_IO & io ) { io & json_dto::mandatory( "from", m_from ) & json_dto::mandatory( "text", m_text ); }};
33
Hello world!Чтение:const std::string json_data{ R"({ "from" : "json_dto", "text" : "Hello world!" })" };
auto msg = json_dto::from_json< message_t >( json_data );
Запись:auto json_str = json_dto::to_json( msg );
template < typename TYPE, unsigned RAPIDJSON_PARSEFLAGS = rapidjson::kParseDefaultFlags >TYPEfrom_json( const std::string & json );
34
Hello world!Чтение:const std::string json_data{ R"({ "from" : "json_dto", "text" : "Hello world!" })" };
auto msg = json_dto::from_json< message_t >( json_data );
Запись:auto json_str = json_dto::to_json( msg );
template < typename DTO >std::stringto_json( const DTO & dto );
35
Какую роль играет json_io()
#include <json_dto/pub.hpp>// ...
struct message_t{ std::string m_from; std::string m_text;
template < typename JSON_IO > void json_io( JSON_IO & io ) { io & json_dto::mandatory( "from", m_from ) & json_dto::mandatory( "text", m_text ); }};
36
Какую роль играет json_io()Это входная точка для json_dto.
#include <json_dto/pub.hpp>// ...
struct message_t{ std::string m_from; std::string m_text;
template < typename JSON_IO > void json_io( JSON_IO & io ) { io & json_dto::mandatory( "from", m_from ) & json_dto::mandatory( "text", m_text ); }};
37
Какую роль играет json_io()Это входная точка для json_dto, она служит для описания:
● как читать DTO из JSON;● как писать DTO в JSON.
#include <json_dto/pub.hpp>// ...
struct message_t{ std::string m_from; std::string m_text;
template < typename JSON_IO > void json_io( JSON_IO & io ) { io & json_dto::mandatory( "from", m_from ) & json_dto::mandatory( "text", m_text ); }};
38
Какую роль играет json_io()Это входная точка для json_dto, она служит для описания:
● как читать DTO из JSON;● как писать DTO в JSON.
Шаблонной она является, для того чтобы иметь всего одну логику для записи и чтения.
#include <json_dto/pub.hpp>// ...
struct message_t{ std::string m_from; std::string m_text;
template < typename JSON_IO > void json_io( JSON_IO & io ) { io & json_dto::mandatory( "from", m_from ) & json_dto::mandatory( "text", m_text ); }};
39
Какую роль играет json_io()Это входная точка для json_dto, она служит для описания:
● как читать DTO из JSON;● как писать DTO в JSON.
Шаблонной она является, для того чтобы иметь всего одну логику для записи и чтения.
json_dto подставляет в нее объекты двух типов:
● json_dto::json_input_t● json_dto::json_output_t
#include <json_dto/pub.hpp>// ...
struct message_t{ std::string m_from; std::string m_text;
template < typename JSON_IO > void json_io( JSON_IO & io ) { io & json_dto::mandatory( "from", m_from ) & json_dto::mandatory( "text", m_text ); }};
40
Внутри json_io()#include <json_dto/pub.hpp>// ...
struct message_t{ std::string m_from; std::string m_text;
template < typename JSON_IO > void json_io( JSON_IO & io ) { io & json_dto::mandatory( "from", m_from ) & json_dto::mandatory( "text", m_text ); }};
41
Внутри json_io()#include <json_dto/pub.hpp>// ...
struct message_t{ std::string m_from; std::string m_text;
template < typename JSON_IO > void json_io( JSON_IO & io ) { io & json_dto::mandatory( "from", m_from ) & json_dto::mandatory( "text", m_text ); }};
42
io & binder
Внутри json_io()#include <json_dto/pub.hpp>// ...
struct message_t{ std::string m_from; std::string m_text;
template < typename JSON_IO > void json_io( JSON_IO & io ) { io & json_dto::mandatory( "from", m_from ) & json_dto::mandatory( "text", m_text ); }};
43
io & binder
json_input_t
json_ouput_t
Внутри json_io()#include <json_dto/pub.hpp>// ...
struct message_t{ std::string m_from; std::string m_text;
template < typename JSON_IO > void json_io( JSON_IO & io ) { io & json_dto::mandatory( "from", m_from ) & json_dto::mandatory( "text", m_text ); }};
44
io & binder
json_input_t
json_ouput_tАналог
operator<< operator>>
Внутри json_io()#include <json_dto/pub.hpp>// ...
struct message_t{ std::string m_from; std::string m_text;
template < typename JSON_IO > void json_io( JSON_IO & io ) { io & json_dto::mandatory( "from", m_from ) & json_dto::mandatory( "text", m_text ); }};
45
io & binder
json_input_t
json_ouput_tАналог
operator<< operator>>
Привязка
Какие бывают привязки
46
Какие бывают привязки● mandatory (обязательные)
template < typename FIELD_TYPE, typename VALIDATOR = empty_validator_t >automandatory( string_ref_t field_name, FIELD_TYPE & field, VALIDATOR validator = VALIDATOR{} );
struct message_t{ std::string m_from{}; std::string m_text{}; std::string m_text_format{ "text/plain" }; bool m_is_private{ false };
template < typename JSON_IO > void json_io( JSON_IO & io ) { io & json_dto::mandatory( "from", m_from ) & json_dto::mandatory( "text", m_text ) & json_dto::optional( "text_format", m_text_format, "text/plain" ) & json_dto::optional_no_default( "is_private", m_is_private ); }};
47
Какие бывают привязки● optional (необязательные со
значением по умолчанию)
template < typename FIELD_TYPE, typename FIELD_DEFAULT_VALUE_TYPE, typename VALIDATOR = empty_validator_t >autooptional( string_ref_t field_name, FIELD_TYPE & field, FIELD_DEFAULT_VALUE_TYPE default_value, VALIDATOR validator = VALIDATOR{} );
struct message_t{ std::string m_from{}; std::string m_text{}; std::string m_text_format{ "text/plain" }; bool m_is_private{ false };
template < typename JSON_IO > void json_io( JSON_IO & io ) { io & json_dto::mandatory( "from", m_from ) & json_dto::mandatory( "text", m_text ) & json_dto::optional( "text_format", m_text_format, "text/plain" ) & json_dto::optional_no_default( "is_private", m_is_private ); }};
48
Какие бывают привязкиПусть мы имеем:auto msg = json_dto::from_json<message_t>(json );
тогда:1. {"from":"...","text":"..." }
msg.m_text_format == "text/plain"
2. {"from":"...","text":"...", "text_format": "text/html" }
msg.m_text_format == "text/html"
struct message_t{ std::string m_from{}; std::string m_text{}; std::string m_text_format{ "text/plain" }; bool m_is_private{ false };
template < typename JSON_IO > void json_io( JSON_IO & io ) { io & json_dto::mandatory( "from", m_from ) & json_dto::mandatory( "text", m_text ) & json_dto::optional( "text_format", m_text_format, "text/plain" ) & json_dto::optional_no_default( "is_private", m_is_private ); }};
49
Какие бывают привязки● optional_no _default
(необязательные, без значения по умолчанию)
template < typename FIELD_TYPE, typename VALIDATOR = empty_validator_t >autooptional_no_default( string_ref_t field_name, FIELD_TYPE & field, VALIDATOR validator = VALIDATOR{} );
struct message_t{ std::string m_from{}; std::string m_text{}; std::string m_text_format{ "text/plain" }; bool m_is_private{ false };
template < typename JSON_IO > void json_io( JSON_IO & io ) { io & json_dto::mandatory( "from", m_from ) & json_dto::mandatory( "text", m_text ) & json_dto::optional( "text_format", m_text_format, "text/plain" ) & json_dto::optional_no_default( "is_private", m_is_private ); }};
50
Почему отдельные имена optional_no_default() и optional()template < typename FIELD_TYPE, typename FIELD_DEFAULT_VALUE_TYPE, typename VALIDATOR = empty_validator_t >autooptional( string_ref_t field_name, FIELD_TYPE & field, FIELD_DEFAULT_VALUE_TYPE default_value, VALIDATOR validator = VALIDATOR{} );
template < typename FIELD_TYPE, typename VALIDATOR = empty_validator_t >autooptional_no_default( string_ref_t field_name, FIELD_TYPE & field, VALIDATOR validator = VALIDATOR{} );
51
Какие бывают привязки● mandatory (обязательные)
● optional (необязательные со значением по умолчанию)
● optional_no _default (необязательные, без значения по умолчанию)
52
Поддерживаемые типы
53
Простые типыC++
● Bool: bool;● Number:
std::int16_t, std::uint16_t, std::int32_t, std::uint32_t, std::int64_t, std::uint64_t, double;
http://json.org/
JSON
56
Простые типыC++
● Bool: bool;● Numeric:
std::int16_t, std::uint16_t, std::int32_t, std::uint32_t, std::int64_t, std::uint64_t, double;
● String: std::stringhttp://json.org/
JSON
57
“Сложные” типыC++
В json_dto также поддерживаются:
● Массивы● Вложенные DTO
http://json.org/
JSON
58
“Сложные” типыC++
В json_dto также поддерживаются:
● Массивы● Вложенные DTO
А также в состав json_dto входит обертка для обработки null-значений
http://json.org/
JSON
59
Поддержка массивовjson_dto автоматически понимает, что значение поля должно быть массивом, если в качестве второго аргумента для привязки указывается ссылка на std::vector< ELEMENT_TYPE > &
Например:
struct str_array_t{ std::vector< std::string > m_strings;
template < typename JSON_IO > void json_io( JSON_IO & io ) { io & json_dto::mandatory( "strings", m_strings ); }};
60
Поддержка массивовНо есть два существенных ограничения:
61
Поддержка массивовНо есть два существенных ограничения:
● При чтении массива все элементы должны быть одного типа
62
Поддержка массивовНо есть два существенных ограничения:
● При чтении массива все элементы должны быть одного типа
● Значение по умолчанию для массивов в общем случае не работает
63
Поддержка вложенных DTOВложенные объекты поддерживаются аналогично простым типам.
Достаточно чтобы тип был уже интегрирован с json_dto.
64
Поддержка вложенных DTOstruct needle_t{ std::string m_death{};
template < typename JSON_IO > void json_io( JSON_IO & io ) { io & json_dto::mandatory( "death", m_death ); }};
65
Поддержка вложенных DTOstruct egg_t{ needle_t m_needle{};
template < typename JSON_IO > void json_io( JSON_IO & io ) { io & json_dto::mandatory( "needle", m_needle ); }};
struct needle_t{ std::string m_death{};
template < typename JSON_IO > void json_io( JSON_IO & io ) { io & json_dto::mandatory( "death", m_death ); }};
66
Поддержка вложенных DTOstruct duck_t{ egg_t m_egg{};
template < typename JSON_IO > void json_io( JSON_IO & io ) { io & json_dto::mandatory( "egg", m_egg ); }};
struct needle_t{ std::string m_death{};
template < typename JSON_IO > void json_io( JSON_IO & io ) { io & json_dto::mandatory( "death", m_death ); }};
struct egg_t{ needle_t m_needle{};
template < typename JSON_IO > void json_io( JSON_IO & io ) { io & json_dto::mandatory( "needle",m_needle ); }}; 67
Поддержка вложенных DTOstruct duck_t{ egg_t m_egg{};
template < typename JSON_IO > void json_io( JSON_IO & io ) { io & json_dto::mandatory( "egg", m_egg ); }};
struct needle_t{ std::string m_death{};
template < typename JSON_IO > void json_io( JSON_IO & io ) { io & json_dto::mandatory( "death", m_death ); }};
struct egg_t{ needle_t m_needle{};
template < typename JSON_IO > void json_io( JSON_IO & io ) { io & json_dto::mandatory( "needle",m_needle ); }}; 68
Обработка null-значенийДля поддержки null значений в json_dto предусмотрен класс json_dto::nullable_t<T>.
69
Обработка null-значенийДля поддержки null значений в json_dto предусмотрен класс json_dto::nullable_t<T>.
Интерфейс json_dto::nullable_t<T> подражает std::optional (C++17).
70
Обработка null-значенийДля поддержки null значений в json_dto предусмотрен класс json_dto::nullable_t<T>.
Интерфейс json_dto::nullable_t<T> подражает std::optional (C++17).
Требует явного объявления члена-данных с типом json_dto::nullable_t<T>.
71
Обработка null-значенийstruct message_t{ std::string m_from; std::string m_text; json_dto::nullable_t< std::vector< std::string > > m_tags;
template < typename JSON_IO > void json_io( JSON_IO & io ) { io & json_dto::mandatory( "from", m_from ) & json_dto::mandatory( "text", m_text ) & json_dto::optional( "tags", m_tags, nullptr ); }};
72
Обработка null-значенийstruct message_t{ std::string m_from; std::string m_text; json_dto::nullable_t< std::vector< std::string > > m_tags;
template < typename JSON_IO > void json_io( JSON_IO & io ) { io & json_dto::mandatory( "from", m_from ) & json_dto::mandatory( "text", m_text ) & json_dto::optional( "tags", m_tags, nullptr ); }};
{ "from" : "json_dto", "text" : "Hello CoreHard!", "tags" : [ "C++", "JSON", "CoreHard.by" ]}
73
Обработка null-значенийstruct message_t{ std::string m_from; std::string m_text; json_dto::nullable_t< std::vector< std::string > > m_tags;
template < typename JSON_IO > void json_io( JSON_IO & io ) { io & json_dto::mandatory( "from", m_from ) & json_dto::mandatory( "text", m_text ) & json_dto::optional( "tags", m_tags, nullptr ); }};
{ "from" : "json_dto", "text" : "Hello world!", "tags" : [ "C++", "JSON", "CoreHard.by" ]}
{ "from" : "json_dto", "text" : "Hello world!", "tags" : null}
74
Обработка null-значенийstruct message_t{ std::string m_from; std::string m_text; json_dto::nullable_t< std::vector< std::string > > m_tags;
template < typename JSON_IO > void json_io( JSON_IO & io ) { io & json_dto::mandatory( "from", m_from ) & json_dto::mandatory( "text", m_text ) & json_dto::optional( "tags", m_tags, nullptr ); }};
{ "from" : "json_dto", "text" : "Hello world!", "tags" : [ "C++", "JSON", "CoreHard.by" ]}
{ "from" : "json_dto", "text" : "Hello world!", "tags" : null}
{ "from" : "json_dto", "text" : "Hello world!"} 75
Обработка null-значенийstruct message_t{ std::string m_from; std::string m_text; json_dto::nullable_t< std::vector< std::string > > m_tags;
template < typename JSON_IO > void json_io( JSON_IO & io ) { io & json_dto::mandatory( "from", m_from ) & json_dto::mandatory( "text", m_text ) & json_dto::optional( "tags", m_tags, nullptr ); }};
auto msg = json_dto::from_json< message_t >( json_data );
// ...
if( msg.m_tags ){ for( const auto & tag : *msg.m_tags ) { do_smth( tag ); }}else do_smth_else();
76
Обработка null-значенийstruct message_t{ std::string m_from; std::string m_text; json_dto::nullable_t< std::vector< std::string > > m_tags;
template < typename JSON_IO > void json_io( JSON_IO & io ) { io & json_dto::mandatory( "from", m_from ) & json_dto::mandatory( "text", m_text ) & json_dto::optional( "tags", m_tags, nullptr ); }};
auto msg = json_dto::from_json< message_t >( json_data );
// ...
if( msg.m_tags ){ for( const auto & tag : *msg.m_tags ) { do_smth( tag ); }}else do_smth_else();
nullable_t::operator bool () const;77
Обработка null-значенийstruct message_t{ std::string m_from; std::string m_text; json_dto::nullable_t< std::vector< std::string > > m_tags;
template < typename JSON_IO > void json_io( JSON_IO & io ) { io & json_dto::mandatory( "from", m_from ) & json_dto::mandatory( "text", m_text ) & json_dto::optional( "tags", m_tags, nullptr ); }};
auto msg = json_dto::from_json< message_t >( json_data );
// ...
if( msg.m_tags ){ for( const auto & tag : *msg.m_tags ) { do_smth( tag ); }}else do_smth_else();
const FIELD_TYPE &nullable_t::operator * () const; 78
Обработка null-значенийstruct message_t{ std::string m_from; std::string m_text; json_dto::nullable_t< std::vector< std::string > > m_tags;
template < typename JSON_IO > void json_io( JSON_IO & io ) { io & json_dto::mandatory( "from", m_from ) & json_dto::mandatory( "text", m_text ) & json_dto::optional( "tags", m_tags, nullptr ); }};
message_t msg = create_msg( /* ... */ );
// ...
msg.m_tags.reset();
// ...
msg.m_tags = std::vector< std::string >{ "1", "23" };
msg.m_tags->push_back( "42" );
voidnullable_t::reset(); 79
Обработка null-значенийstruct message_t{ std::string m_from; std::string m_text; json_dto::nullable_t< std::vector< std::string > > m_tags;
template < typename JSON_IO > void json_io( JSON_IO & io ) { io & json_dto::mandatory( "from", m_from ) & json_dto::mandatory( "text", m_text ) & json_dto::optional( "tags", m_tags, nullptr ); }};
message_t msg = create_msg( /* ... */ );
// ...
msg.m_tags.reset();
// ...
msg.m_tags = std::vector< std::string >{ "1", "23" };
msg.m_tags->push_back( "42" );
nullable_t &nullable_t::operator= ( FIELD_TYPE && value ); 80
Обработка null-значенийstruct message_t{ std::string m_from; std::string m_text; json_dto::nullable_t< std::vector< std::string > > m_tags;
template < typename JSON_IO > void json_io( JSON_IO & io ) { io & json_dto::mandatory( "from", m_from ) & json_dto::mandatory( "text", m_text ) & json_dto::optional( "tags", m_tags, nullptr ); }};
message_t msg = create_msg( /* ... */ );
// ...
msg.m_tags.reset();
// ...
msg.m_tags = std::vector< std::string >{ "1", "23" };
msg.m_tags->push_back( "42" );
FIELD_TYPE *nullable_t::operator-> (); 81
Что еще?Есть возможность задать неинтрузивный json_io().
Еще есть валидаторы, которые можно задавать самому, но есть и немного стандартных.
Можно определять способ чтения и записи кастомных типов.
82
Неинтрузивный json_io()struct message_t{ std::string m_from{}; std::string m_text{}; std::string m_text_format{ "text/plain"}; bool m_is_private{ false };};
83
Неинтрузивный json_io()struct message_t{ std::string m_from{}; std::string m_text{}; std::string m_text_format{ "text/plain"}; bool m_is_private{ false };};
84
namespace json_dto{
template < typename JSON_IO > void json_io( JSON_IO & io, message_t & msg ) { io & json_dto::mandatory( "from", msg.m_from ) & json_dto::mandatory( "text", msg.m_text ) & json_dto::optional( "text_format", msg.m_text_format, "text/plain" ) & json_dto::optional_no_default( "is_private", msg.m_is_private ); }
} /* namespace json_dto */
Неинтрузивный json_io()struct message_t{ std::string m_from{}; std::string m_text{}; std::string m_text_format{ "text/plain"}; bool m_is_private{ false };};
85
namespace json_dto{
template < typename JSON_IO > void json_io( JSON_IO & io, message_t & msg ) { io & json_dto::mandatory( "from", msg.m_from ) & json_dto::mandatory( "text", msg.m_text ) & json_dto::optional( "text_format", msg.m_text_format, "text/plain" ) & json_dto::optional_no_default( "is_private", msg.m_is_private ); }
} /* namespace json_dto */
Неинтрузивный json_io()struct message_t{ std::string m_from{}; std::string m_text{}; std::string m_text_format{ "text/plain"}; bool m_is_private{ false };};
86
namespace json_dto{
template < typename JSON_IO > void json_io( JSON_IO & io, message_t & msg ) { io & json_dto::mandatory( "from", msg.m_from ) & json_dto::mandatory( "text", msg.m_text ) & json_dto::optional( "text_format", msg.m_text_format, "text/plain" ) & json_dto::optional_no_default( "is_private", msg.m_is_private ); }
} /* namespace json_dto */
Поддержка кастомных типов
87
Поддержка кастомных типовstruct message_t{ std::string m_from; std::tm m_when; std::string m_text;
template < typename JSON_IO > void json_io( JSON_IO & io ) { io & json_dto::mandatory( "from", m_from ) & json_dto::mandatory( "when", m_when ) & json_dto::mandatory( "text", m_text ); }};
88
Поддержка кастомных типовstruct message_t{ std::string m_from; std::tm m_when; std::string m_text;
template < typename JSON_IO > void json_io( JSON_IO & io ) { io & json_dto::mandatory( "from", m_from ) & json_dto::mandatory( "when", m_when ) & json_dto::mandatory( "text", m_text ); }};
89
Поддержка кастомных типовstruct message_t{ std::string m_from; std::tm m_when; std::string m_text;
template < typename JSON_IO > void json_io( JSON_IO & io ) { io & json_dto::mandatory( "from", m_from ) & json_dto::mandatory( "when", m_when ) & json_dto::mandatory( "text", m_text ); }};
namespace json_dto{
template <>voidread_json_value( const rapidjson::Value & object, std::tm & v ){ // ...}
template <>voidwrite_json_value( const std::tm & v, rapidjson::Value & object, rapidjson::MemoryPoolAllocator<> & allocator ){ // ...}
} /* namespace json_dto */
90
ВалидаторыФункциональный объект (function object), который получает один параметр.
Если значение корректно, то валидатор просто штатно завершает свою работу.
Если значение некорректное, то валидатор должен выбросить исключение.
91
Валидаторыio & json_dto::mandatory( "from", m_from ) & json_dto::mandatory( "text", m_text ) & json_dto::optional( "log_level", m_log_level, nullptr );
92
Валидаторыio & json_dto::mandatory( "from", m_from ) & json_dto::mandatory( "text", m_text ) & json_dto::optional( "log_level", m_log_level, nullptr );
io & json_dto::mandatory( "from", m_from, []( const auto & from ){ if( from.empty() ) throw std::runtime_error{ "from cannot be empty" }; } ) & json_dto::mandatory( "text", m_text, check_all_7bit ) & json_dto::optional( "log_level", m_log_level,nullptr, json_dto::one_of_constraint( { std::string{ "trace" }, std::string{ "info" },std::string{ "error" } } ) );
93
Спасибо!Николай Гродзицкий[email protected]
https://bitbucket.org/sobjectizerteam/json_dto-0.1
https://github.com/miloyip/rapidjson
http://www.boost.org/doc/libs/1_62_0/libs/serialization/doc/index.html
http://en.cppreference.com/w/cpp/utility/optional
Альтернативы: https://github.com/Loki-Astari/ThorsSerializer.git
94
Recommended