В C++ приложениях, которые по тем или иным причинам используют JSON, как правило есть необходимость трансформировать данные из JSON представления в С++ структуры и наоборот. Речь пойдет об одной небольшой header-only библиотеке, которая позволяет облегчить этот рутинный кусок работы (https://bitbucket.org/sobjectizerteam/json_dto-0.1).
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;
}; 3
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/
4
5. О чем пойдет речь?
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
9. Это кому-нибудь нужно?
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
10. Это кому-нибудь нужно?
“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
11. Это кому-нибудь нужно?
“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
12. Это кому-нибудь нужно?
В целом, хочется для заданной
структуры (класса) иметь
возможность конвертировать
инстанс в JSON и наоборот
получить инстанс из JSON.
При этом чтобы дополнительного
кода требовалось как можно
меньше.
12
15. Что такое json_dto?
● Нет, это не еще один JSON парсер
○ В качестве парсера используется RapidJSON
15
16. Что такое json_dto?
● Нет, это не еще один JSON парсер
○ В качестве парсера используется RapidJSON
Выбор был сделан на основе nativejson-benchmark
16
17. Что такое json_dto?
● Нет, это не еще один JSON парсер
○ В качестве парсера используется RapidJSON
Выбор был сделан на основе nativejson-benchmark
● Инструмент для отображения DTO в JSON и обратно по заданным
правилам
17
18. Что такое json_dto?
● Нет, это не еще один JSON парсер
○ В качестве парсера используется RapidJSON
Выбор был сделан на основе nativejson-benchmark
● Инструмент для отображения DTO в JSON и обратно по заданным
правилам
○ Header-only (C++14)
18
19. Что такое json_dto?
● Нет, это не еще один JSON парсер
○ В качестве парсера используется RapidJSON
Выбор был сделан на основе nativejson-benchmark
● Инструмент для отображения DTO в JSON и обратно по заданным
правилам
○ Header-only (C++14)
■ зависит только от RapidJSON (тоже header-only)
19
20. Что такое json_dto?
● Нет, это не еще один JSON парсер
○ В качестве парсера используется RapidJSON
Выбор был сделан на основе nativejson-benchmark
● Инструмент для отображения DTO в JSON и обратно по заданным
правилам
○ Header-only (C++14)
○ Требует немного дополнительного кода
20
21. Что такое json_dto?
● Нет, это не еще один JSON парсер
○ В качестве парсера используется RapidJSON
Выбор был сделан на основе nativejson-benchmark
● Инструмент для отображения DTO в JSON и обратно по заданным
правилам
○ Header-only (C++14)
○ Требует немного дополнительного кода
■ Механика описания правил позаимствована у Boost Serialization
21
22. Что такое json_dto?
● Нет, это не еще один JSON парсер
○ В качестве парсера используется RapidJSON
Выбор был сделан на основе nativejson-benchmark
● Инструмент для отображения DTO в JSON и обратно по заданным
правилам
○ Header-only (C++14)
○ Требует немного дополнительного кода
■ Механика описания правил позаимствована у Boost Serialization
■ Для одного DTO требуется написать одну функцию
22
23. Что такое json_dto?
● Нет, это не еще один JSON парсер
○ В качестве парсера используется RapidJSON
Выбор был сделан на основе nativejson-benchmark
● Инструмент для отображения DTO в JSON и обратно по заданным
правилам
○ Header-only (C++14)
○ Требует немного дополнительного кода
○ Интуитивно понятная поддержка типов
23
24. Что такое json_dto?
● Нет, это не еще один JSON парсер
○ В качестве парсера используется RapidJSON
Выбор был сделан на основе nativejson-benchmark
● Инструмент для отображения DTO в JSON и обратно по заданным
правилам
○ Header-only (C++14)
○ Требует немного дополнительного кода
○ Интуитивно понятная поддержка типов
■ Простые типы: String, Number, Bool
24
25. Что такое json_dto?
● Нет, это не еще один JSON парсер
○ В качестве парсера используется RapidJSON
Выбор был сделан на основе nativejson-benchmark
● Инструмент для отображения DTO в JSON и обратно по заданным
правилам
○ Header-only (C++14)
○ Требует немного дополнительного кода
○ Интуитивно понятная поддержка типов
■ Простые типы: String, Number, Bool
■ Массивы (Array)
25
26. Что такое json_dto?
● Нет, это не еще один JSON парсер
○ В качестве парсера используется RapidJSON
Выбор был сделан на основе nativejson-benchmark
● Инструмент для отображения DTO в JSON и обратно по заданным
правилам
○ Header-only (C++14)
○ Требует немного дополнительного кода
○ Интуитивно понятная поддержка типов
■ Простые типы: String, Number, Bool
■ Массивы (Array)
■ Объекты (Object)
26
27. Что такое json_dto?
● Нет, это не еще один JSON парсер
○ В качестве парсера используется RapidJSON
Выбор был сделан на основе nativejson-benchmark
● Инструмент для отображения DTO в JSON и обратно по заданным
правилам
○ Header-only (C++14)
○ Требует немного дополнительного кода
○ Интуитивно понятная поддержка типов
○ Поддержка null-полей
27
28. Что такое json_dto?
● Нет, это не еще один JSON парсер
○ В качестве парсера используется RapidJSON
Выбор был сделан на основе nativejson-benchmark
● Инструмент для отображения DTO в JSON и обратно по заданным
правилам
○ Header-only (C++14)
○ Требует немного дополнительного кода
○ Интуитивно понятная поддержка типов
○ Поддержка null-полей
○ Опциональные поля и значения по умолчанию
28
37. Какую роль играет 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
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 );
}
};
38
39. Какую роль играет 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
40. Какую роль играет 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
51. Почему отдельные имена
optional_no_default() и optional()
template <
typename FIELD_TYPE,
typename FIELD_DEFAULT_VALUE_TYPE,
typename VALIDATOR = empty_validator_t
>
auto
optional(
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
>
auto
optional_no_default(
string_ref_t field_name,
FIELD_TYPE & field,
VALIDATOR validator = VALIDATOR{} );
51
52. Какие бывают привязки
● mandatory (обязательные)
● optional (необязательные со значением по умолчанию)
● optional_no _default (необязательные, без значения по умолчанию)
52
59. “Сложные” типы
C++
В json_dto также поддерживаются:
● Массивы
● Вложенные DTO
А также в состав json_dto входит
обертка для обработки null-значений
http://json.org/
JSON
59
60. Поддержка массивов
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
62. Поддержка массивов
Но есть два существенных ограничения:
● При чтении массива все элементы должны быть одного типа
62
63. Поддержка массивов
Но есть два существенных ограничения:
● При чтении массива все элементы должны быть одного типа
● Значение по умолчанию для массивов в общем случае не работает
63
64. Поддержка вложенных DTO
Вложенные объекты поддерживаются
аналогично простым типам.
Достаточно чтобы тип был уже интегрирован
с json_dto.
64
70. Обработка null-значений
Для поддержки null значений в json_dto предусмотрен класс
json_dto::nullable_t<T>.
Интерфейс json_dto::nullable_t<T> подражает std::optional
(C++17).
70
71. Обработка null-значений
Для поддержки null значений в json_dto предусмотрен класс
json_dto::nullable_t<T>.
Интерфейс json_dto::nullable_t<T> подражает std::optional
(C++17).
Требует явного объявления члена-данных с типом
json_dto::nullable_t<T>.
71
82. Что еще?
Есть возможность задать неинтрузивный json_io().
Еще есть валидаторы, которые можно задавать самому, но есть и немного
стандартных.
Можно определять способ чтения и записи кастомных типов.
82
91. Валидаторы
Функциональный объект (function object), который получает один параметр.
Если значение корректно, то валидатор просто штатно завершает свою
работу.
Если значение некорректное, то валидатор должен выбросить исключение.
91