Reflection for RapidJSON  0.0.5
Reflection for serializing/deserializing with RapidJSON
reflector.h
Go to the documentation of this file.
1 #ifndef REFLECTIVE_RAPIDJSON_JSON_REFLECTOR_H
2 #define REFLECTIVE_RAPIDJSON_JSON_REFLECTOR_H
3 
10 #include <c++utilities/conversion/types.h>
11 #include <c++utilities/misc/traits.h>
12 
13 #include <rapidjson/document.h>
14 #include <rapidjson/rapidjson.h>
15 #include <rapidjson/stringbuffer.h>
16 #include <rapidjson/writer.h>
17 
18 #include <limits>
19 #include <map>
20 #include <memory>
21 #include <set>
22 #include <string>
23 #include <tuple>
24 #include <unordered_map>
25 #include <unordered_set>
26 
27 #include "./errorhandling.h"
28 
30 
31 template <typename Type> struct JsonSerializable;
32 
36 template <typename T> struct AdaptedJsonSerializable : public Traits::Bool<false> {
37  static constexpr const char *name = "AdaptedJsonSerializable";
38  static constexpr const char *qualifiedName = "ReflectiveRapidJSON::AdaptedJsonSerializable";
39 };
40 
44 namespace JsonReflector {
45 
49 constexpr RAPIDJSON_NAMESPACE::SizeType rapidJsonSize(std::size_t size)
50 {
51  return size > std::numeric_limits<RAPIDJSON_NAMESPACE::SizeType>::max() ? std::numeric_limits<RAPIDJSON_NAMESPACE::SizeType>::max()
52  : static_cast<RAPIDJSON_NAMESPACE::SizeType>(size);
53 }
54 
58 inline RAPIDJSON_NAMESPACE::StringBuffer serializeJsonDocToString(RAPIDJSON_NAMESPACE::Document &document)
59 {
60  RAPIDJSON_NAMESPACE::StringBuffer buffer;
61  RAPIDJSON_NAMESPACE::Writer<RAPIDJSON_NAMESPACE::StringBuffer> writer(buffer);
62  document.Accept(writer);
63  return buffer;
64 }
65 
69 inline RAPIDJSON_NAMESPACE::Document parseJsonDocFromString(const char *json, std::size_t jsonSize)
70 {
71  RAPIDJSON_NAMESPACE::Document document(RAPIDJSON_NAMESPACE::kObjectType);
72  const RAPIDJSON_NAMESPACE::ParseResult parseRes = document.Parse(json, jsonSize);
73  if (parseRes.IsError()) {
74  throw parseRes;
75  }
76  return document;
77 }
78 
79 // define traits to distinguish between "built-in" types like int, std::string, std::vector, ... and custom structs/classes
80 template <typename Type>
81 using IsBuiltInType = Traits::Any<std::is_integral<Type>, std::is_floating_point<Type>, std::is_pointer<Type>, std::is_enum<Type>,
82  Traits::IsSpecializationOf<Type, std::tuple>, Traits::IsIteratable<Type>, Traits::IsSpecializationOf<Type, std::unique_ptr>,
83  Traits::IsSpecializationOf<Type, std::shared_ptr>, Traits::IsSpecializationOf<Type, std::weak_ptr>>;
84 template <typename Type> using IsCustomType = Traits::Not<IsBuiltInType<Type>>;
85 
86 // define trait to check for custom structs/classes which are JSON serializable
87 // NOTE: the check for Traits::IsComplete is required because std::is_base_of fails for incomplete types when using GCC
88 template <typename Type>
90  = Traits::Any<Traits::Not<Traits::IsComplete<Type>>, std::is_base_of<JsonSerializable<Type>, Type>, AdaptedJsonSerializable<Type>>;
91 
92 // define trait to check for map or hash
93 template <typename Type>
94 using IsMapOrHash = Traits::Any<Traits::IsSpecializationOf<Type, std::map>, Traits::IsSpecializationOf<Type, std::unordered_map>>;
95 template <typename Type> using IsSet = Traits::Any<Traits::IsSpecializationOf<Type, std::set>, Traits::IsSpecializationOf<Type, std::unordered_set>>;
96 template <typename Type>
97 using IsMultiSet = Traits::Any<Traits::IsSpecializationOf<Type, std::multiset>, Traits::IsSpecializationOf<Type, std::unordered_multiset>>;
98 template <typename Type>
99 using IsArrayOrSet
100  = Traits::All<Traits::IsIteratable<Type>, Traits::Not<Traits::IsSpecializationOf<Type, std::basic_string>>, Traits::Not<IsMapOrHash<Type>>>;
101 template <typename Type>
102 using IsArray = Traits::All<Traits::IsIteratable<Type>, Traits::Not<Traits::IsSpecializationOf<Type, std::basic_string>>,
103  Traits::Not<IsMapOrHash<Type>>, Traits::Not<IsSet<Type>>, Traits::Not<IsMultiSet<Type>>>;
104 
105 // define functions to "push" values to a RapidJSON array or object
106 
110 template <typename Type, Traits::DisableIf<IsBuiltInType<Type>>* = nullptr>
111 void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator);
112 
116 template <typename Type, Traits::DisableIf<IsJsonSerializable<Type>>* = nullptr>
117 void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value::Array &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator);
118 
122 template <typename Type, Traits::EnableIf<IsJsonSerializable<Type>>* = nullptr>
123 void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value::Array &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator);
124 
128 template <typename Type, Traits::EnableIf<IsJsonSerializable<Type>>* = nullptr>
129 void push(
130  const Type &reflectable, const char *name, RAPIDJSON_NAMESPACE::Value::Object &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator);
131 
135 template <typename Type, Traits::DisableIf<IsJsonSerializable<Type>>* = nullptr>
136 void push(
137  const Type &reflectable, const char *name, RAPIDJSON_NAMESPACE::Value::Object &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator);
138 
143 template <typename Type, Traits::DisableIf<IsBuiltInType<Type>>* = nullptr>
144 void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value::Object &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator);
145 
149 template <typename Type, Traits::DisableIf<IsBuiltInType<Type>>*>
150 inline void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
151 {
152  value.SetObject();
153  RAPIDJSON_NAMESPACE::Value::Object obj(value.GetObject());
154  push(reflectable, obj, allocator);
155 }
156 
160 template <typename Type, Traits::EnableIfAny<std::is_integral<Type>, std::is_floating_point<Type>>* = nullptr>
161 inline void push(Type reflectable, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
162 {
163  value.Set(reflectable, allocator);
164 }
165 
169 template <typename Type, Traits::EnableIfAny<std::is_enum<Type>>* = nullptr>
170 inline void push(Type reflectable, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
171 {
172  value.Set(static_cast<Traits::Conditional<std::is_unsigned<typename std::underlying_type<Type>::type>, uint64, int64>>(reflectable), allocator);
173 }
174 
178 template <typename Type, Traits::EnableIf<std::is_same<Type, const char *>>* = nullptr>
179 inline void push(Type reflectable, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
180 {
181  value.SetString(RAPIDJSON_NAMESPACE::StringRef(reflectable), allocator);
182 }
183 
187 template <typename Type, Traits::EnableIf<std::is_same<Type, const char *const &>>* = nullptr>
188 inline void push(const char *const &reflectable, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
189 {
190  value.SetString(RAPIDJSON_NAMESPACE::StringRef(reflectable), allocator);
191 }
192 
196 template <typename Type, Traits::EnableIf<std::is_same<Type, std::string>>* = nullptr>
197 inline void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
198 {
199  value.SetString(RAPIDJSON_NAMESPACE::StringRef(reflectable.data(), reflectable.size()), allocator);
200 }
201 
205 template <typename Type, Traits::EnableIf<IsArrayOrSet<Type>, Traits::HasSize<Type>>* = nullptr>
206 void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
207 {
208  value.SetArray();
209  RAPIDJSON_NAMESPACE::Value::Array array(value.GetArray());
210  array.Reserve(reflectable.size(), allocator);
211  for (const auto &item : reflectable) {
212  push(item, array, allocator);
213  }
214 }
215 
219 template <typename Type, Traits::EnableIf<IsArrayOrSet<Type>, Traits::Not<Traits::HasSize<Type>>>* = nullptr>
220 void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
221 {
222  value.SetArray();
223  RAPIDJSON_NAMESPACE::Value::Array array(value.GetArray());
224  for (const auto &item : reflectable) {
225  push(item, array, allocator);
226  }
227 }
228 
232 template <typename Type, Traits::EnableIf<IsMapOrHash<Type>>* = nullptr>
233 void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
234 {
235  value.SetObject();
236  RAPIDJSON_NAMESPACE::Value::Object object(value.GetObject());
237  for (const auto &item : reflectable) {
238  push(item.second, item.first.data(), object, allocator);
239  }
240 }
241 
242 namespace Detail {
243 
247 template <class Tuple, std::size_t N> struct TuplePushHelper {
248  static void push(const Tuple &tuple, RAPIDJSON_NAMESPACE::Value::Array &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
249  {
250  TuplePushHelper<Tuple, N - 1>::push(tuple, value, allocator);
251  JsonReflector::push(std::get<N - 1>(tuple), value, allocator);
252  }
253 };
254 
255 template <class Tuple> struct TuplePushHelper<Tuple, 1> {
256  static void push(const Tuple &tuple, RAPIDJSON_NAMESPACE::Value::Array &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
257  {
258  JsonReflector::push(std::get<0>(tuple), value, allocator);
259  }
260 };
261 } // namespace Detail
262 
266 template <typename Type, Traits::EnableIf<Traits::IsSpecializationOf<Type, std::tuple>>* = nullptr>
267 void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
268 {
269  value.SetArray();
270  RAPIDJSON_NAMESPACE::Value::Array array(value.GetArray());
271  array.Reserve(std::tuple_size<Type>::value, allocator);
272  Detail::TuplePushHelper<Type, std::tuple_size<Type>::value>::push(reflectable, array, allocator);
273 }
274 
278 template <typename Type,
279  Traits::EnableIfAny<Traits::IsSpecializationOf<Type, std::unique_ptr>, Traits::IsSpecializationOf<Type, std::shared_ptr>,
280  Traits::IsSpecializationOf<Type, std::weak_ptr>>* = nullptr>
281 void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
282 {
283  if (!reflectable) {
284  value.SetNull();
285  return;
286  }
287  push(*reflectable, value, allocator);
288 }
289 
293 template <typename Type, Traits::EnableIf<IsJsonSerializable<Type>>*>
294 void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value::Array &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
295 {
296  RAPIDJSON_NAMESPACE::Value objectValue(RAPIDJSON_NAMESPACE::kObjectType);
297  RAPIDJSON_NAMESPACE::Value::Object object(objectValue.GetObject());
298  push(reflectable, object, allocator);
299  value.PushBack(objectValue, allocator);
300 }
301 
305 template <typename Type, Traits::DisableIf<IsJsonSerializable<Type>>*>
306 void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value::Array &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
307 {
308  RAPIDJSON_NAMESPACE::Value genericValue;
309  push(reflectable, genericValue, allocator);
310  value.PushBack(genericValue, allocator);
311 }
312 
316 template <typename Type, Traits::EnableIf<IsJsonSerializable<Type>>*>
317 void push(
318  const Type &reflectable, const char *name, RAPIDJSON_NAMESPACE::Value::Object &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
319 {
320  RAPIDJSON_NAMESPACE::Value objectValue(RAPIDJSON_NAMESPACE::kObjectType);
321  RAPIDJSON_NAMESPACE::Value::Object object(objectValue.GetObject());
322  push(reflectable, object, allocator);
323  value.AddMember(RAPIDJSON_NAMESPACE::StringRef(name), objectValue, allocator);
324 }
325 
329 template <typename Type, Traits::DisableIf<IsJsonSerializable<Type>>*>
330 void push(
331  const Type &reflectable, const char *name, RAPIDJSON_NAMESPACE::Value::Object &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
332 {
333  RAPIDJSON_NAMESPACE::Value genericValue;
334  push(reflectable, genericValue, allocator);
335  value.AddMember(RAPIDJSON_NAMESPACE::StringRef(name), genericValue, allocator);
336 }
337 
338 // define functions to "pull" values from a RapidJSON array or object
339 
344 template <typename Type, Traits::DisableIf<IsBuiltInType<Type>>* = nullptr>
345 void pull(Type &reflectable, const RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>>::ConstObject &value,
346  JsonDeserializationErrors *errors);
347 
351 template <typename Type, Traits::DisableIf<IsBuiltInType<Type>>* = nullptr>
352 void pull(Type &reflectable, const RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors);
353 
357 template <typename Type, Traits::EnableIf<IsArrayOrSet<Type>, Traits::Not<Traits::IsReservable<Type>>>* = nullptr>
358 void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors);
359 
363 template <typename Type, Traits::EnableIf<IsArrayOrSet<Type>, Traits::IsReservable<Type>>* = nullptr>
364 void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors);
365 
369 template <typename Type, Traits::EnableIf<IsArray<Type>>* = nullptr>
370 void pull(Type &reflectable, rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>>::ConstArray array, JsonDeserializationErrors *errors);
371 
375 template <typename Type, Traits::EnableIf<IsSet<Type>>* = nullptr>
376 void pull(Type &reflectable, rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>>::ConstArray array, JsonDeserializationErrors *errors);
377 
381 template <typename Type, Traits::EnableIf<IsMultiSet<Type>>* = nullptr>
382 void pull(Type &reflectable, rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>>::ConstArray array, JsonDeserializationErrors *errors);
383 
387 template <typename Type, Traits::EnableIf<IsMapOrHash<Type>>* = nullptr>
388 void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors);
389 
393 template <typename Type, Traits::EnableIf<Traits::IsSpecializationOf<Type, std::tuple>>* = nullptr>
394 void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors);
395 
399 template <typename Type, Traits::EnableIf<Traits::IsSpecializationOf<Type, std::unique_ptr>>* = nullptr>
400 void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors);
401 
405 template <typename Type, Traits::EnableIf<Traits::IsSpecializationOf<Type, std::shared_ptr>>* = nullptr>
406 void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors);
407 
411 template <typename Type>
412 inline void pull(
413  Type &reflectable, rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>>::ValueIterator &value, JsonDeserializationErrors *errors);
414 
420 template <typename Type>
421 inline void pull(Type &reflectable, const char *name, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>>::ConstObject &value,
422  JsonDeserializationErrors *errors);
423 
427 template <typename Type, Traits::DisableIf<IsBuiltInType<Type>>*>
428 void pull(Type &reflectable, const RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors);
429 
433 template <typename Type,
434  Traits::EnableIf<Traits::Not<std::is_same<Type, bool>>, Traits::Any<std::is_integral<Type>, std::is_floating_point<Type>>>* = nullptr>
435 inline void pull(
436  Type &reflectable, const RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors)
437 {
438  if (!value.IsNumber()) {
439  if (errors) {
440  errors->reportTypeMismatch<Type>(value.GetType());
441  }
442  return;
443  }
444  reflectable = value.Is<Type>() ? value.Get<Type>() : static_cast<Type>(value.GetDouble());
445 }
446 
450 template <typename Type, Traits::EnableIf<std::is_same<Type, bool>>* = nullptr>
451 inline void pull(
452  Type &reflectable, const RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors)
453 {
454  if (!value.IsBool()) {
455  if (errors) {
456  errors->reportTypeMismatch<Type>(value.GetType());
457  }
458  return;
459  }
460  reflectable = value.GetBool();
461 }
462 
467 template <typename Type, Traits::EnableIfAny<std::is_enum<Type>>* = nullptr>
468 inline void pull(
469  Type &reflectable, const RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors)
470 {
471  using ExpectedType = Traits::Conditional<std::is_unsigned<typename std::underlying_type<Type>::type>, uint64, int64>;
472  if (!value.Is<ExpectedType>()) {
473  if (errors) {
474  errors->reportTypeMismatch<ExpectedType>(value.GetType());
475  }
476  return;
477  }
478  reflectable = static_cast<Type>(value.Get<ExpectedType>());
479 }
480 
484 template <typename Type, Traits::EnableIf<std::is_same<Type, std::string>>* = nullptr>
485 inline void pull(
486  Type &reflectable, const RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors)
487 {
488  if (!value.IsString()) {
489  if (errors) {
490  errors->reportTypeMismatch<std::string>(value.GetType());
491  }
492  return;
493  }
494  reflectable = value.GetString();
495 }
496 
501 template <typename Type, Traits::EnableIfAny<std::is_same<Type, const char *>, std::is_same<Type, const char *const &>>* = nullptr>
502 inline void pull(Type &, const RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors)
503 {
504  if (!value.IsString()) {
505  if (errors) {
506  errors->reportTypeMismatch<std::string>(value.GetType());
507  }
508  return;
509  }
510 }
511 
515 template <typename Type, Traits::EnableIf<IsArrayOrSet<Type>, Traits::Not<Traits::IsReservable<Type>>>*>
516 void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors)
517 {
518  if (!value.IsArray()) {
519  if (errors) {
520  errors->reportTypeMismatch<Type>(value.GetType());
521  }
522  return;
523  }
524  pull(reflectable, value.GetArray(), errors);
525 }
526 
530 template <typename Type, Traits::EnableIf<IsArrayOrSet<Type>, Traits::IsReservable<Type>>*>
531 void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors)
532 {
533  if (!value.IsArray()) {
534  if (errors) {
535  errors->reportTypeMismatch<Type>(value.GetType());
536  }
537  return;
538  }
539  auto array = value.GetArray();
540  reflectable.reserve(array.Size());
541  pull(reflectable, array, errors);
542 }
543 
547 template <typename Type, Traits::EnableIf<IsArray<Type>>*>
548 void pull(Type &reflectable, rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>>::ConstArray array, JsonDeserializationErrors *errors)
549 {
550  // clear previous contents of the array
551  reflectable.clear();
552 
553  // pull all array elements of the specified value
554  std::size_t index = 0;
555  for (const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &item : array) {
556  // set error context for current index
557  if (errors) {
558  errors->currentIndex = index;
559  }
560  ++index;
561  reflectable.emplace_back();
562  pull(reflectable.back(), item, errors);
563  }
564 
565  // clear error context
566  if (errors) {
568  }
569 }
570 
574 template <typename Type, Traits::EnableIf<IsMultiSet<Type>>*>
575 void pull(Type &reflectable, rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>>::ConstArray array, JsonDeserializationErrors *errors)
576 {
577  // clear previous contents of the array
578  reflectable.clear();
579 
580  // pull all array elements of the specified value
581  std::size_t index = 0;
582  for (const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &item : array) {
583  // set error context for current index
584  if (errors) {
585  errors->currentIndex = index;
586  }
587  ++index;
588  typename Type::value_type itemObj;
589  pull(itemObj, item, errors);
590  reflectable.emplace(move(itemObj));
591  }
592 
593  // clear error context
594  if (errors) {
596  }
597 }
598 
602 template <typename Type, Traits::EnableIf<IsSet<Type>>*>
603 void pull(Type &reflectable, rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>>::ConstArray array, JsonDeserializationErrors *errors)
604 {
605  // clear previous contents of the array
606  reflectable.clear();
607 
608  // pull all array elements of the specified value
609  std::size_t index = 0;
610  for (const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &item : array) {
611  // set error context for current index
612  if (errors) {
613  errors->currentIndex = index;
614  }
615  ++index;
616  typename Type::value_type itemObj;
617  pull(itemObj, item, errors);
618  if (!reflectable.emplace(move(itemObj)).second) {
619  errors->reportUnexpectedDuplicate(JsonType::Array);
620  }
621  }
622 
623  // clear error context
624  if (errors) {
625  errors->currentIndex = JsonDeserializationError::noIndex;
626  }
627 }
628 
632 template <typename Type, Traits::EnableIf<IsMapOrHash<Type>>*>
633 void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors)
634 {
635  if (!value.IsObject()) {
636  if (errors) {
637  errors->reportTypeMismatch<Type>(value.GetType());
638  }
639  return;
640  }
641  auto obj = value.GetObject();
642  for (auto i = obj.MemberBegin(), end = obj.MemberEnd(); i != end; ++i) {
643  pull(reflectable[i->name.GetString()], i->value, errors);
644  }
645 }
646 
647 namespace Detail {
648 
653 template <class Tuple, std::size_t N> struct TuplePullHelper {
654  static void pull(Tuple &tuple, const RAPIDJSON_NAMESPACE::Value::ConstArray value, JsonDeserializationErrors *errors)
655  {
656  TuplePullHelper<Tuple, N - 1>::pull(tuple, value, errors);
657  JsonReflector::pull<typename std::tuple_element<N - 1, Tuple>::type>(std::get<N - 1>(tuple), value[N - 1], errors);
658  }
659 };
660 
661 template <class Tuple> struct TuplePullHelper<Tuple, 1> {
662  static void pull(Tuple &tuple, const RAPIDJSON_NAMESPACE::Value::ConstArray value, JsonDeserializationErrors *errors)
663  {
664  JsonReflector::pull<typename std::tuple_element<0, Tuple>::type>(std::get<0>(tuple), value[0], errors);
665  }
666 };
667 } // namespace Detail
668 
672 template <typename Type, Traits::EnableIf<Traits::IsSpecializationOf<Type, std::tuple>>*>
673 void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors)
674 {
675  if (!value.IsArray()) {
676  if (errors) {
677  errors->reportTypeMismatch<Type>(value.GetType());
678  }
679  return;
680  }
681  auto array = value.GetArray();
682  if (array.Size() != std::tuple_size<Type>::value) {
683  if (errors) {
684  // FIXME: report expected and actual size
685  errors->reportArraySizeMismatch();
686  }
687  return;
688  }
689  Detail::TuplePullHelper<Type, std::tuple_size<Type>::value>::pull(reflectable, array, errors);
690 }
691 
695 template <typename Type, Traits::EnableIf<Traits::IsSpecializationOf<Type, std::unique_ptr>>*>
696 void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors)
697 {
698  if (value.IsNull()) {
699  reflectable.reset();
700  return;
701  }
702  reflectable = std::make_unique<typename Type::element_type>();
703  pull(*reflectable, value, errors);
704 }
705 
709 template <typename Type, Traits::EnableIf<Traits::IsSpecializationOf<Type, std::shared_ptr>>*>
710 void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors)
711 {
712  if (value.IsNull()) {
713  reflectable.reset();
714  return;
715  }
716  reflectable = std::make_shared<typename Type::element_type>();
717  pull(*reflectable, value, errors);
718 }
719 
723 template <typename Type>
724 inline void pull(Type &reflectable, rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>>::ValueIterator &value, JsonDeserializationErrors *errors)
725 {
726  pull<Type>(reflectable, *value, errors);
727  ++value;
728 }
729 
735 template <typename Type>
736 inline void pull(Type &reflectable, const char *name, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>>::ConstObject &value,
738 {
739  // find member
740  const auto member = value.FindMember(name);
741  if (member == value.MemberEnd()) {
742  return; // TODO: handle member missing
743  }
744 
745  // set error context for current member
746  const char *previousMember;
747  if (errors) {
748  previousMember = errors->currentMember;
749  errors->currentMember = name;
750  }
751 
752  // actually pull value for member
753  pull<Type>(reflectable, member->value, errors);
754 
755  // restore previous error context
756  if (errors) {
757  errors->currentMember = previousMember;
758  }
759 }
760 
764 template <typename Type, Traits::DisableIf<IsBuiltInType<Type>>*>
765 void pull(Type &reflectable, const RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors)
766 {
767  if (!value.IsObject()) {
768  if (errors) {
769  errors->reportTypeMismatch<Type>(value.GetType());
770  }
771  return;
772  }
773  pull(reflectable, value.GetObject(), errors);
774 }
775 
776 // define functions providing high-level JSON serialization
777 
781 template <typename Type, Traits::EnableIfAny<IsJsonSerializable<Type>, IsMapOrHash<Type>>* = nullptr>
782 RAPIDJSON_NAMESPACE::StringBuffer toJson(const Type &reflectable)
783 {
784  RAPIDJSON_NAMESPACE::Document document(RAPIDJSON_NAMESPACE::kObjectType);
785  RAPIDJSON_NAMESPACE::Document::Object object(document.GetObject());
786  push(reflectable, object, document.GetAllocator());
787  return serializeJsonDocToString(document);
788 }
789 
793 template <typename Type, Traits::EnableIfAny<std::is_integral<Type>, std::is_floating_point<Type>>* = nullptr>
794 RAPIDJSON_NAMESPACE::StringBuffer toJson(Type reflectable)
795 {
796  RAPIDJSON_NAMESPACE::Document document(RAPIDJSON_NAMESPACE::kNumberType);
797  document.Set(reflectable, document.GetAllocator());
798  return serializeJsonDocToString(document);
799 }
800 
804 template <typename Type, Traits::EnableIf<std::is_same<Type, std::string>>* = nullptr>
805 RAPIDJSON_NAMESPACE::StringBuffer toJson(const std::string &reflectable)
806 {
807  RAPIDJSON_NAMESPACE::Document document(RAPIDJSON_NAMESPACE::kStringType);
808  document.SetString(RAPIDJSON_NAMESPACE::StringRef(reflectable.data(), reflectable.size()), document.GetAllocator());
809  return serializeJsonDocToString(document);
810 }
811 
815 template <typename Type, Traits::EnableIf<std::is_same<Type, const char *>>* = nullptr> RAPIDJSON_NAMESPACE::StringBuffer toJson(const char *reflectable)
816 {
817  RAPIDJSON_NAMESPACE::Document document(RAPIDJSON_NAMESPACE::kStringType);
818  document.SetString(RAPIDJSON_NAMESPACE::StringRef(reflectable), document.GetAllocator());
819  return serializeJsonDocToString(document);
820 }
821 
825 template <typename Type, Traits::EnableIf<IsArray<Type>>* = nullptr> RAPIDJSON_NAMESPACE::StringBuffer toJson(const Type &reflectable)
826 {
827  RAPIDJSON_NAMESPACE::Document document(RAPIDJSON_NAMESPACE::kArrayType);
828  push(reflectable, document, document.GetAllocator());
829  return serializeJsonDocToString(document);
830 }
831 
832 // define functions providing high-level JSON deserialization
833 
837 template <typename Type, Traits::EnableIfAny<IsJsonSerializable<Type>, IsMapOrHash<Type>>* = nullptr>
838 Type fromJson(const char *json, std::size_t jsonSize, JsonDeserializationErrors *errors = nullptr)
839 {
840  RAPIDJSON_NAMESPACE::Document doc(parseJsonDocFromString(json, jsonSize));
841  if (!doc.IsObject()) {
842  if (errors) {
843  errors->reportTypeMismatch<Type>(doc.GetType());
844  }
845  return Type();
846  }
847 
848  Type res;
849  pull<Type>(res, doc.GetObject(), errors);
850  return res;
851 }
852 
856 template <typename Type, Traits::EnableIfAny<std::is_integral<Type>, std::is_floating_point<Type>>* = nullptr>
857 Type fromJson(const char *json, std::size_t jsonSize, JsonDeserializationErrors *errors = nullptr)
858 {
859  RAPIDJSON_NAMESPACE::Document doc(parseJsonDocFromString(json, jsonSize));
860  if (!doc.Is<Type>()) {
861  if (errors) {
862  errors->reportTypeMismatch<Type>(doc.GetType());
863  }
864  return Type();
865  }
866 
867  return doc.Get<Type>();
868 }
869 
873 template <typename Type, Traits::EnableIf<std::is_same<Type, std::string>>* = nullptr>
874 Type fromJson(const char *json, std::size_t jsonSize, JsonDeserializationErrors *errors = nullptr)
875 {
876  RAPIDJSON_NAMESPACE::Document doc(parseJsonDocFromString(json, jsonSize));
877  if (!doc.IsString()) {
878  if (errors) {
879  errors->reportTypeMismatch<Type>(doc.GetType());
880  }
881  return Type();
882  }
883 
884  return doc.GetString();
885 }
886 
890 template <typename Type, Traits::EnableIf<IsArray<Type>>* = nullptr>
891 Type fromJson(const char *json, std::size_t jsonSize, JsonDeserializationErrors *errors = nullptr)
892 {
893  RAPIDJSON_NAMESPACE::Document doc(parseJsonDocFromString(json, jsonSize));
894  if (!doc.IsArray()) {
895  if (errors) {
896  errors->reportTypeMismatch<Type>(doc.GetType());
897  }
898  return Type();
899  }
900 
901  Type res;
902  pull<Type>(res, doc.GetArray(), errors);
903  return res;
904 }
905 
909 template <typename Type> Type fromJson(const char *json, JsonDeserializationErrors *errors = nullptr)
910 {
911  return fromJson<Type>(json, std::strlen(json), errors);
912 }
913 
917 template <typename Type> Type fromJson(const std::string &json, JsonDeserializationErrors *errors = nullptr)
918 {
919  return fromJson<Type>(json.data(), json.size(), errors);
920 }
921 
922 } // namespace JsonReflector
923 } // namespace ReflectiveRapidJSON
924 
925 #endif // REFLECTIVE_RAPIDJSON_JSON_REFLECTOR_H
Contains helper for error handling when deserializing JSON files.
RAPIDJSON_NAMESPACE::StringBuffer serializeJsonDocToString(RAPIDJSON_NAMESPACE::Document &document)
Serializes the specified JSON document.
Definition: reflector.h:58
static void pull(Tuple &tuple, const RAPIDJSON_NAMESPACE::Value::ConstArray value, JsonDeserializationErrors *errors)
Definition: reflector.h:662
static void push(const Tuple &tuple, RAPIDJSON_NAMESPACE::Value::Array &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
Definition: reflector.h:256
RAPIDJSON_NAMESPACE::Document parseJsonDocFromString(const char *json, std::size_t jsonSize)
Parses the specified JSON string.
Definition: reflector.h:69
The AdaptedJsonSerializable class allows considering 3rd party classes as serializable.
Definition: reflector.h:36
Traits::Any< Traits::Not< Traits::IsComplete< Type > >, std::is_base_of< JsonSerializable< Type >, Type >, AdaptedJsonSerializable< Type > > IsJsonSerializable
Definition: reflector.h:90
const char * currentMember
The name of the member (in currentRecord) which is currently being processed.
constexpr RAPIDJSON_NAMESPACE::SizeType rapidJsonSize(std::size_t size)
Casts the specified size to the size type used by RapidJSON ensuring no overflow happens.
Definition: reflector.h:49
Traits::Any< Traits::IsSpecializationOf< Type, std::set >, Traits::IsSpecializationOf< Type, std::unordered_set > > IsSet
Definition: reflector.h:95
static constexpr const char * qualifiedName
Definition: reflector.h:38
static void push(const Tuple &tuple, RAPIDJSON_NAMESPACE::Value::Array &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
Definition: reflector.h:248
Traits::Any< Traits::IsSpecializationOf< Type, std::multiset >, Traits::IsSpecializationOf< Type, std::unordered_multiset > > IsMultiSet
Definition: reflector.h:97
Traits::Any< Traits::IsSpecializationOf< Type, std::map >, Traits::IsSpecializationOf< Type, std::unordered_map > > IsMapOrHash
Definition: reflector.h:94
RAPIDJSON_NAMESPACE::StringBuffer toJson(const Type &reflectable)
Serializes the specified reflectable which has a custom type or can be mapped to and object...
Definition: reflector.h:782
static constexpr const char * name
Definition: reflector.h:37
Traits::All< Traits::IsIteratable< Type >, Traits::Not< Traits::IsSpecializationOf< Type, std::basic_string > >, Traits::Not< IsMapOrHash< Type > >, Traits::Not< IsSet< Type > >, Traits::Not< IsMultiSet< Type > >> IsArray
Definition: reflector.h:103
std::size_t currentIndex
The index in the array which is currently processed.
Traits::Not< IsBuiltInType< Type > > IsCustomType
Definition: reflector.h:84
static void pull(Tuple &tuple, const RAPIDJSON_NAMESPACE::Value::ConstArray value, JsonDeserializationErrors *errors)
Definition: reflector.h:654
void reportTypeMismatch(RAPIDJSON_NAMESPACE::Type presentType)
Reports a type mismatch between.
The JsonDeserializationErrors struct can be passed to fromJson() for error handling.
The TuplePullHelper class helps deserializing tuples from JSON arrays.
Definition: reflector.h:653
The TuplePushHelper class helps serializing tuples to JSON arrays.
Definition: reflector.h:247
static constexpr std::size_t noIndex
Indicates no array was being processed when the error occured.
Type fromJson(const char *json, std::size_t jsonSize, JsonDeserializationErrors *errors=nullptr)
Deserializes the specified JSON to.
Definition: reflector.h:838
Traits::All< Traits::IsIteratable< Type >, Traits::Not< Traits::IsSpecializationOf< Type, std::basic_string > >, Traits::Not< IsMapOrHash< Type > >> IsArrayOrSet
Definition: reflector.h:100
void reportArraySizeMismatch()
Reports an array size mismatch.
void pull(Type &reflectable, const RAPIDJSON_NAMESPACE::GenericValue< RAPIDJSON_NAMESPACE::UTF8< char >>::ConstObject &value, JsonDeserializationErrors *errors)
Pulls the reflectable which has a custom type from the specified object.
Traits::Any< std::is_integral< Type >, std::is_floating_point< Type >, std::is_pointer< Type >, std::is_enum< Type >, Traits::IsSpecializationOf< Type, std::tuple >, Traits::IsIteratable< Type >, Traits::IsSpecializationOf< Type, std::unique_ptr >, Traits::IsSpecializationOf< Type, std::shared_ptr >, Traits::IsSpecializationOf< Type, std::weak_ptr > > IsBuiltInType
Definition: reflector.h:83
void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
Pushes the specified reflectable to the specified value.
Definition: reflector.h:150
The JsonSerializable class provides the CRTP-base for (de)serializable objects.
Definition: reflector.h:31