Reflection for RapidJSON  0.0.7
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 "../traits.h"
11 
12 #include <c++utilities/conversion/types.h>
13 
14 #include <rapidjson/document.h>
15 #include <rapidjson/rapidjson.h>
16 #include <rapidjson/stringbuffer.h>
17 #include <rapidjson/writer.h>
18 
19 #include <limits>
20 #include <memory>
21 #include <string>
22 #include <tuple>
23 
24 #include "./errorhandling.h"
25 
26 namespace ReflectiveRapidJSON {
27 
28 template <typename Type> struct JsonSerializable;
29 
33 template <typename T> struct AdaptedJsonSerializable : public Traits::Bool<false> {
34  static constexpr const char *name = "AdaptedJsonSerializable";
35  static constexpr const char *qualifiedName = "ReflectiveRapidJSON::AdaptedJsonSerializable";
36 };
37 
41 namespace JsonReflector {
42 
46 constexpr RAPIDJSON_NAMESPACE::SizeType rapidJsonSize(std::size_t size)
47 {
48  return size > std::numeric_limits<RAPIDJSON_NAMESPACE::SizeType>::max() ? std::numeric_limits<RAPIDJSON_NAMESPACE::SizeType>::max()
49  : static_cast<RAPIDJSON_NAMESPACE::SizeType>(size);
50 }
51 
55 inline RAPIDJSON_NAMESPACE::StringBuffer serializeJsonDocToString(RAPIDJSON_NAMESPACE::Document &document)
56 {
57  RAPIDJSON_NAMESPACE::StringBuffer buffer;
58  RAPIDJSON_NAMESPACE::Writer<RAPIDJSON_NAMESPACE::StringBuffer> writer(buffer);
59  document.Accept(writer);
60  return buffer;
61 }
62 
66 inline RAPIDJSON_NAMESPACE::Document parseJsonDocFromString(const char *json, std::size_t jsonSize)
67 {
68  RAPIDJSON_NAMESPACE::Document document(RAPIDJSON_NAMESPACE::kObjectType);
69  const RAPIDJSON_NAMESPACE::ParseResult parseRes = document.Parse(json, jsonSize);
70  if (parseRes.IsError()) {
71  throw parseRes;
72  }
73  return document;
74 }
75 
76 // define traits to distinguish between "built-in" types like int, std::string, std::vector, ... and custom structs/classes
77 template <typename Type>
78 using IsBuiltInType = Traits::Any<std::is_integral<Type>, std::is_floating_point<Type>, std::is_pointer<Type>, std::is_enum<Type>,
79  Traits::IsSpecializationOf<Type, std::tuple>, Traits::IsIteratable<Type>, Traits::IsSpecializationOf<Type, std::unique_ptr>,
80  Traits::IsSpecializationOf<Type, std::shared_ptr>, Traits::IsSpecializationOf<Type, std::weak_ptr>>;
81 template <typename Type> using IsCustomType = Traits::Not<IsBuiltInType<Type>>;
82 
83 // define trait to check for custom structs/classes which are JSON serializable
84 // NOTE: the check for Traits::IsComplete is required because std::is_base_of fails for incomplete types when using GCC
85 template <typename Type>
87  = Traits::Any<Traits::Not<Traits::IsComplete<Type>>, std::is_base_of<JsonSerializable<Type>, Type>, AdaptedJsonSerializable<Type>>;
88 
89 // define functions to "push" values to a RapidJSON array or object
90 
94 template <typename Type, Traits::DisableIf<IsBuiltInType<Type>> * = nullptr>
95 void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator);
96 
100 template <typename Type, Traits::DisableIf<IsJsonSerializable<Type>> * = nullptr>
101 void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value::Array &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator);
102 
106 template <typename Type, Traits::EnableIf<IsJsonSerializable<Type>> * = nullptr>
107 void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value::Array &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator);
108 
112 template <typename Type, Traits::EnableIf<IsJsonSerializable<Type>> * = nullptr>
113 void push(
114  const Type &reflectable, const char *name, RAPIDJSON_NAMESPACE::Value::Object &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator);
115 
119 template <typename Type, Traits::DisableIf<IsJsonSerializable<Type>> * = nullptr>
120 void push(
121  const Type &reflectable, const char *name, RAPIDJSON_NAMESPACE::Value::Object &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator);
122 
127 template <typename Type, Traits::DisableIf<IsBuiltInType<Type>> * = nullptr>
128 void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value::Object &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator);
129 
133 template <typename Type, Traits::DisableIf<IsBuiltInType<Type>> *>
134 inline void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
135 {
136  value.SetObject();
137  RAPIDJSON_NAMESPACE::Value::Object obj(value.GetObject());
138  push(reflectable, obj, allocator);
139 }
140 
144 template <typename Type, Traits::EnableIfAny<std::is_integral<Type>, std::is_floating_point<Type>> * = nullptr>
145 inline void push(Type reflectable, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
146 {
147  value.Set(reflectable, allocator);
148 }
149 
153 template <typename Type, Traits::EnableIfAny<std::is_enum<Type>> * = nullptr>
154 inline void push(Type reflectable, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
155 {
156  value.Set(static_cast<Traits::Conditional<std::is_unsigned<typename std::underlying_type<Type>::type>, uint64, int64>>(reflectable), allocator);
157 }
158 
162 template <typename Type, Traits::EnableIf<std::is_same<Type, const char *>> * = nullptr>
163 inline void push(Type reflectable, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
164 {
165  value.SetString(RAPIDJSON_NAMESPACE::StringRef(reflectable), allocator);
166 }
167 
171 template <typename Type, Traits::EnableIf<std::is_same<Type, const char *const &>> * = nullptr>
172 inline void push(const char *const &reflectable, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
173 {
174  value.SetString(RAPIDJSON_NAMESPACE::StringRef(reflectable), allocator);
175 }
176 
180 template <typename Type, Traits::EnableIf<std::is_same<Type, std::string>> * = nullptr>
181 inline void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
182 {
183  value.SetString(RAPIDJSON_NAMESPACE::StringRef(reflectable.data(), reflectable.size()), allocator);
184 }
185 
189 template <typename Type, Traits::EnableIf<IsArrayOrSet<Type>, Traits::HasSize<Type>> * = nullptr>
190 void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
191 {
192  value.SetArray();
193  RAPIDJSON_NAMESPACE::Value::Array array(value.GetArray());
194  array.Reserve(reflectable.size(), allocator);
195  for (const auto &item : reflectable) {
196  push(item, array, allocator);
197  }
198 }
199 
203 template <typename Type, Traits::EnableIf<IsArrayOrSet<Type>, Traits::Not<Traits::HasSize<Type>>> * = nullptr>
204 void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
205 {
206  value.SetArray();
207  RAPIDJSON_NAMESPACE::Value::Array array(value.GetArray());
208  for (const auto &item : reflectable) {
209  push(item, array, allocator);
210  }
211 }
212 
217 template <typename Type, Traits::EnableIfAny<IsMapOrHash<Type>, IsMultiMapOrHash<Type>> * = nullptr>
218 void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
219 {
220  value.SetObject();
221  RAPIDJSON_NAMESPACE::Value::Object object(value.GetObject());
222  for (const auto &item : reflectable) {
223  push(item.second, item.first.data(), object, allocator);
224  }
225 }
226 
227 namespace Detail {
228 
232 template <class Tuple, std::size_t N> struct TuplePushHelper {
233  static void push(const Tuple &tuple, RAPIDJSON_NAMESPACE::Value::Array &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
234  {
235  TuplePushHelper<Tuple, N - 1>::push(tuple, value, allocator);
236  JsonReflector::push(std::get<N - 1>(tuple), value, allocator);
237  }
238 };
239 
240 template <class Tuple> struct TuplePushHelper<Tuple, 1> {
241  static void push(const Tuple &tuple, RAPIDJSON_NAMESPACE::Value::Array &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
242  {
243  JsonReflector::push(std::get<0>(tuple), value, allocator);
244  }
245 };
246 } // namespace Detail
247 
251 template <typename Type, Traits::EnableIf<Traits::IsSpecializationOf<Type, std::tuple>> * = nullptr>
252 void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
253 {
254  value.SetArray();
255  RAPIDJSON_NAMESPACE::Value::Array array(value.GetArray());
256  array.Reserve(std::tuple_size<Type>::value, allocator);
257  Detail::TuplePushHelper<Type, std::tuple_size<Type>::value>::push(reflectable, array, allocator);
258 }
259 
263 template <typename Type,
264  Traits::EnableIfAny<Traits::IsSpecializationOf<Type, std::unique_ptr>, Traits::IsSpecializationOf<Type, std::shared_ptr>,
265  Traits::IsSpecializationOf<Type, std::weak_ptr>> * = nullptr>
266 void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
267 {
268  if (!reflectable) {
269  value.SetNull();
270  return;
271  }
272  push(*reflectable, value, allocator);
273 }
274 
278 template <typename Type, Traits::EnableIf<IsJsonSerializable<Type>> *>
279 void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value::Array &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
280 {
281  RAPIDJSON_NAMESPACE::Value objectValue(RAPIDJSON_NAMESPACE::kObjectType);
282  RAPIDJSON_NAMESPACE::Value::Object object(objectValue.GetObject());
283  push(reflectable, object, allocator);
284  value.PushBack(objectValue, allocator);
285 }
286 
290 template <typename Type, Traits::DisableIf<IsJsonSerializable<Type>> *>
291 void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value::Array &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
292 {
293  RAPIDJSON_NAMESPACE::Value genericValue;
294  push(reflectable, genericValue, allocator);
295  value.PushBack(genericValue, allocator);
296 }
297 
301 template <typename Type, Traits::EnableIf<IsJsonSerializable<Type>> *>
302 void push(
303  const Type &reflectable, const char *name, RAPIDJSON_NAMESPACE::Value::Object &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
304 {
305  RAPIDJSON_NAMESPACE::Value objectValue(RAPIDJSON_NAMESPACE::kObjectType);
306  RAPIDJSON_NAMESPACE::Value::Object object(objectValue.GetObject());
307  push(reflectable, object, allocator);
308  value.AddMember(RAPIDJSON_NAMESPACE::StringRef(name), objectValue, allocator);
309 }
310 
314 template <typename Type, Traits::DisableIf<IsJsonSerializable<Type>> *>
315 void push(
316  const Type &reflectable, const char *name, RAPIDJSON_NAMESPACE::Value::Object &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
317 {
318  RAPIDJSON_NAMESPACE::Value genericValue;
319  push(reflectable, genericValue, allocator);
320  value.AddMember(RAPIDJSON_NAMESPACE::StringRef(name), genericValue, allocator);
321 }
322 
323 // define functions to "pull" values from a RapidJSON array or object
324 
329 template <typename Type, Traits::DisableIf<IsBuiltInType<Type>> * = nullptr>
330 void pull(Type &reflectable, const RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>>::ConstObject &value,
331  JsonDeserializationErrors *errors);
332 
336 template <typename Type, Traits::DisableIf<IsBuiltInType<Type>> * = nullptr>
337 void pull(Type &reflectable, const RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors);
338 
342 template <typename Type, Traits::EnableIf<IsArrayOrSet<Type>, Traits::Not<Traits::IsReservable<Type>>> * = nullptr>
343 void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors);
344 
348 template <typename Type, Traits::EnableIf<IsArrayOrSet<Type>, Traits::IsReservable<Type>> * = nullptr>
349 void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors);
350 
354 template <typename Type, Traits::EnableIf<IsArray<Type>> * = nullptr>
355 void pull(Type &reflectable, rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>>::ConstArray array, JsonDeserializationErrors *errors);
356 
360 template <typename Type, Traits::EnableIf<IsSet<Type>> * = nullptr>
361 void pull(Type &reflectable, rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>>::ConstArray array, JsonDeserializationErrors *errors);
362 
366 template <typename Type, Traits::EnableIf<IsMultiSet<Type>> * = nullptr>
367 void pull(Type &reflectable, rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>>::ConstArray array, JsonDeserializationErrors *errors);
368 
372 template <typename Type, Traits::EnableIf<IsMapOrHash<Type>> * = nullptr>
373 void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors);
374 
378 template <typename Type, Traits::EnableIf<IsMultiMapOrHash<Type>> * = nullptr>
379 void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors);
380 
384 template <typename Type, Traits::EnableIf<Traits::IsSpecializationOf<Type, std::tuple>> * = nullptr>
385 void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors);
386 
390 template <typename Type, Traits::EnableIf<Traits::IsSpecializationOf<Type, std::unique_ptr>> * = nullptr>
391 void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors);
392 
396 template <typename Type, Traits::EnableIf<Traits::IsSpecializationOf<Type, std::shared_ptr>> * = nullptr>
397 void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors);
398 
402 template <typename Type>
403 inline void pull(
404  Type &reflectable, rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>>::ValueIterator &value, JsonDeserializationErrors *errors);
405 
411 template <typename Type>
412 inline void pull(Type &reflectable, const char *name, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>>::ConstObject &value,
413  JsonDeserializationErrors *errors);
414 
418 template <typename Type, Traits::DisableIf<IsBuiltInType<Type>> *>
419 void pull(Type &reflectable, const RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors);
420 
424 template <typename Type,
425  Traits::EnableIf<Traits::Not<std::is_same<Type, bool>>, Traits::Any<std::is_integral<Type>, std::is_floating_point<Type>>> * = nullptr>
426 inline void pull(
427  Type &reflectable, const RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors)
428 {
429  if (!value.IsNumber()) {
430  if (errors) {
431  errors->reportTypeMismatch<Type>(value.GetType());
432  }
433  return;
434  }
435  reflectable = value.Is<Type>() ? value.Get<Type>() : static_cast<Type>(value.GetDouble());
436 }
437 
441 template <typename Type, Traits::EnableIf<std::is_same<Type, bool>> * = nullptr>
442 inline void pull(
443  Type &reflectable, const RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors)
444 {
445  if (!value.IsBool()) {
446  if (errors) {
447  errors->reportTypeMismatch<Type>(value.GetType());
448  }
449  return;
450  }
451  reflectable = value.GetBool();
452 }
453 
458 template <typename Type, Traits::EnableIfAny<std::is_enum<Type>> * = nullptr>
459 inline void pull(
460  Type &reflectable, const RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors)
461 {
462  using ExpectedType = Traits::Conditional<std::is_unsigned<typename std::underlying_type<Type>::type>, uint64, int64>;
463  if (!value.Is<ExpectedType>()) {
464  if (errors) {
465  errors->reportTypeMismatch<ExpectedType>(value.GetType());
466  }
467  return;
468  }
469  reflectable = static_cast<Type>(value.Get<ExpectedType>());
470 }
471 
475 template <typename Type, Traits::EnableIf<std::is_same<Type, std::string>> * = nullptr>
476 inline void pull(
477  Type &reflectable, const RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors)
478 {
479  if (!value.IsString()) {
480  if (errors) {
481  errors->reportTypeMismatch<std::string>(value.GetType());
482  }
483  return;
484  }
485  reflectable = value.GetString();
486 }
487 
492 template <typename Type, Traits::EnableIfAny<std::is_same<Type, const char *>, std::is_same<Type, const char *const &>> * = nullptr>
493 inline void pull(Type &, const RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors)
494 {
495  if (!value.IsString()) {
496  if (errors) {
497  errors->reportTypeMismatch<std::string>(value.GetType());
498  }
499  return;
500  }
501 }
502 
506 template <typename Type, Traits::EnableIf<IsArrayOrSet<Type>, Traits::Not<Traits::IsReservable<Type>>> *>
507 void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors)
508 {
509  if (!value.IsArray()) {
510  if (errors) {
511  errors->reportTypeMismatch<Type>(value.GetType());
512  }
513  return;
514  }
515  pull(reflectable, value.GetArray(), errors);
516 }
517 
521 template <typename Type, Traits::EnableIf<IsArrayOrSet<Type>, Traits::IsReservable<Type>> *>
522 void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors)
523 {
524  if (!value.IsArray()) {
525  if (errors) {
526  errors->reportTypeMismatch<Type>(value.GetType());
527  }
528  return;
529  }
530  auto array = value.GetArray();
531  reflectable.reserve(array.Size());
532  pull(reflectable, array, errors);
533 }
534 
538 template <typename Type, Traits::EnableIf<IsArray<Type>> *>
539 void pull(Type &reflectable, rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>>::ConstArray array, JsonDeserializationErrors *errors)
540 {
541  // clear previous contents of the array
542  reflectable.clear();
543 
544  // pull all array elements of the specified value
545  std::size_t index = 0;
546  for (const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &item : array) {
547  // set error context for current index
548  if (errors) {
549  errors->currentIndex = index;
550  }
551  ++index;
552  reflectable.emplace_back();
553  pull(reflectable.back(), item, errors);
554  }
555 
556  // clear error context
557  if (errors) {
559  }
560 }
561 
565 template <typename Type, Traits::EnableIf<IsMultiSet<Type>> *>
566 void pull(Type &reflectable, rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>>::ConstArray array, JsonDeserializationErrors *errors)
567 {
568  // clear previous contents of the array
569  reflectable.clear();
570 
571  // pull all array elements of the specified value
572  std::size_t index = 0;
573  for (const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &item : array) {
574  // set error context for current index
575  if (errors) {
576  errors->currentIndex = index;
577  }
578  ++index;
579  typename Type::value_type itemObj;
580  pull(itemObj, item, errors);
581  reflectable.emplace(move(itemObj));
582  }
583 
584  // clear error context
585  if (errors) {
587  }
588 }
589 
593 template <typename Type, Traits::EnableIf<IsSet<Type>> *>
594 void pull(Type &reflectable, rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>>::ConstArray array, JsonDeserializationErrors *errors)
595 {
596  // clear previous contents of the array
597  reflectable.clear();
598 
599  // pull all array elements of the specified value
600  std::size_t index = 0;
601  for (const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &item : array) {
602  // set error context for current index
603  if (errors) {
604  errors->currentIndex = index;
605  }
606  ++index;
607  typename Type::value_type itemObj;
608  pull(itemObj, item, errors);
609  if (!reflectable.emplace(move(itemObj)).second) {
610  errors->reportUnexpectedDuplicate(JsonType::Array);
611  }
612  }
613 
614  // clear error context
615  if (errors) {
616  errors->currentIndex = JsonDeserializationError::noIndex;
617  }
618 }
619 
623 template <typename Type, Traits::EnableIf<IsMapOrHash<Type>> *>
624 void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors)
625 {
626  if (!value.IsObject()) {
627  if (errors) {
628  errors->reportTypeMismatch<Type>(value.GetType());
629  }
630  return;
631  }
632  auto obj = value.GetObject();
633  for (auto i = obj.MemberBegin(), end = obj.MemberEnd(); i != end; ++i) {
634  pull(reflectable[i->name.GetString()], i->value, errors);
635  }
636 }
637 
641 template <typename Type, Traits::EnableIf<IsMultiMapOrHash<Type>> *>
642 void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors)
643 {
644  if (!value.IsObject()) {
645  if (errors) {
646  errors->reportTypeMismatch<Type>(value.GetType());
647  }
648  return;
649  }
650  auto obj = value.GetObject();
651  for (auto i = obj.MemberBegin(), end = obj.MemberEnd(); i != end; ++i) {
652  auto insertedIterator = reflectable.insert(typename Type::value_type(i->name.GetString(), typename Type::mapped_type()));
653  pull(insertedIterator->second, i->value, errors);
654  }
655 }
656 
657 namespace Detail {
658 
663 template <class Tuple, std::size_t N> struct TuplePullHelper {
664  static void pull(Tuple &tuple, const RAPIDJSON_NAMESPACE::Value::ConstArray value, JsonDeserializationErrors *errors)
665  {
666  TuplePullHelper<Tuple, N - 1>::pull(tuple, value, errors);
667  JsonReflector::pull<typename std::tuple_element<N - 1, Tuple>::type>(std::get<N - 1>(tuple), value[N - 1], errors);
668  }
669 };
670 
671 template <class Tuple> struct TuplePullHelper<Tuple, 1> {
672  static void pull(Tuple &tuple, const RAPIDJSON_NAMESPACE::Value::ConstArray value, JsonDeserializationErrors *errors)
673  {
674  JsonReflector::pull<typename std::tuple_element<0, Tuple>::type>(std::get<0>(tuple), value[0], errors);
675  }
676 };
677 } // namespace Detail
678 
682 template <typename Type, Traits::EnableIf<Traits::IsSpecializationOf<Type, std::tuple>> *>
683 void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors)
684 {
685  if (!value.IsArray()) {
686  if (errors) {
687  errors->reportTypeMismatch<Type>(value.GetType());
688  }
689  return;
690  }
691  auto array = value.GetArray();
692  if (array.Size() != std::tuple_size<Type>::value) {
693  if (errors) {
694  // FIXME: report expected and actual size
695  errors->reportArraySizeMismatch();
696  }
697  return;
698  }
699  Detail::TuplePullHelper<Type, std::tuple_size<Type>::value>::pull(reflectable, array, errors);
700 }
701 
705 template <typename Type, Traits::EnableIf<Traits::IsSpecializationOf<Type, std::unique_ptr>> *>
706 void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors)
707 {
708  if (value.IsNull()) {
709  reflectable.reset();
710  return;
711  }
712  reflectable = std::make_unique<typename Type::element_type>();
713  pull(*reflectable, value, errors);
714 }
715 
719 template <typename Type, Traits::EnableIf<Traits::IsSpecializationOf<Type, std::shared_ptr>> *>
720 void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors)
721 {
722  if (value.IsNull()) {
723  reflectable.reset();
724  return;
725  }
726  reflectable = std::make_shared<typename Type::element_type>();
727  pull(*reflectable, value, errors);
728 }
729 
733 template <typename Type>
734 inline void pull(Type &reflectable, rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>>::ValueIterator &value, JsonDeserializationErrors *errors)
735 {
736  pull<Type>(reflectable, *value, errors);
737  ++value;
738 }
739 
745 template <typename Type>
746 inline void pull(Type &reflectable, const char *name, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>>::ConstObject &value,
748 {
749  // find member
750  const auto member = value.FindMember(name);
751  if (member == value.MemberEnd()) {
752  return; // TODO: handle member missing
753  }
754 
755  // set error context for current member
756  const char *previousMember;
757  if (errors) {
758  previousMember = errors->currentMember;
759  errors->currentMember = name;
760  }
761 
762  // actually pull value for member
763  pull<Type>(reflectable, member->value, errors);
764 
765  // restore previous error context
766  if (errors) {
767  errors->currentMember = previousMember;
768  }
769 }
770 
774 template <typename Type, Traits::DisableIf<IsBuiltInType<Type>> *>
775 void pull(Type &reflectable, const RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors)
776 {
777  if (!value.IsObject()) {
778  if (errors) {
779  errors->reportTypeMismatch<Type>(value.GetType());
780  }
781  return;
782  }
783  pull(reflectable, value.GetObject(), errors);
784 }
785 
786 // define functions providing high-level JSON serialization
787 
791 template <typename Type, Traits::EnableIfAny<IsJsonSerializable<Type>, IsMapOrHash<Type>, IsMultiMapOrHash<Type>> * = nullptr>
792 RAPIDJSON_NAMESPACE::Document toJsonDocument(const Type &reflectable)
793 {
794  RAPIDJSON_NAMESPACE::Document document(RAPIDJSON_NAMESPACE::kObjectType);
795  RAPIDJSON_NAMESPACE::Document::Object object(document.GetObject());
796  push(reflectable, object, document.GetAllocator());
797  return document;
798 }
799 
803 template <typename Type, Traits::EnableIfAny<std::is_integral<Type>, std::is_floating_point<Type>> * = nullptr>
804 RAPIDJSON_NAMESPACE::Document toJsonDocument(Type reflectable)
805 {
806  RAPIDJSON_NAMESPACE::Document document(RAPIDJSON_NAMESPACE::kNumberType);
807  document.Set(reflectable, document.GetAllocator());
808  return document;
809 }
810 
814 template <typename Type, Traits::EnableIf<std::is_same<Type, std::string>> * = nullptr>
815 RAPIDJSON_NAMESPACE::Document toJsonDocument(const std::string &reflectable)
816 {
817  RAPIDJSON_NAMESPACE::Document document(RAPIDJSON_NAMESPACE::kStringType);
818  document.SetString(RAPIDJSON_NAMESPACE::StringRef(reflectable.data(), reflectable.size()), document.GetAllocator());
819  return document;
820 }
821 
825 template <typename Type, Traits::EnableIf<std::is_same<Type, const char *>> * = nullptr>
826 RAPIDJSON_NAMESPACE::Document toJsonDocument(const char *reflectable)
827 {
828  RAPIDJSON_NAMESPACE::Document document(RAPIDJSON_NAMESPACE::kStringType);
829  document.SetString(RAPIDJSON_NAMESPACE::StringRef(reflectable), document.GetAllocator());
830  return document;
831 }
832 
836 template <typename Type, Traits::EnableIf<IsArray<Type>> * = nullptr> RAPIDJSON_NAMESPACE::Document toJsonDocument(const Type &reflectable)
837 {
838  RAPIDJSON_NAMESPACE::Document document(RAPIDJSON_NAMESPACE::kArrayType);
839  push(reflectable, document, document.GetAllocator());
840  return document;
841 }
842 
846 template <typename Type,
847  Traits::EnableIfAny<IsJsonSerializable<Type>, IsMapOrHash<Type>, IsMultiMapOrHash<Type>, std::is_integral<Type>, std::is_floating_point<Type>,
848  Traits::IsString<Type>, IsArray<Type>> * = nullptr>
849 RAPIDJSON_NAMESPACE::StringBuffer toJson(const Type &reflectable)
850 {
851  auto document(toJsonDocument(reflectable));
852  return serializeJsonDocToString(document);
853 }
854 
855 // define functions providing high-level JSON deserialization
856 
860 template <typename Type, Traits::EnableIfAny<IsJsonSerializable<Type>, IsMapOrHash<Type>, IsMultiMapOrHash<Type>> * = nullptr>
861 Type fromJson(const char *json, std::size_t jsonSize, JsonDeserializationErrors *errors = nullptr)
862 {
863  RAPIDJSON_NAMESPACE::Document doc(parseJsonDocFromString(json, jsonSize));
864  if (!doc.IsObject()) {
865  if (errors) {
866  errors->reportTypeMismatch<Type>(doc.GetType());
867  }
868  return Type();
869  }
870 
871  Type res;
872  pull<Type>(res, doc.GetObject(), errors);
873  return res;
874 }
875 
879 template <typename Type, Traits::EnableIfAny<std::is_integral<Type>, std::is_floating_point<Type>> * = nullptr>
880 Type fromJson(const char *json, std::size_t jsonSize, JsonDeserializationErrors *errors = nullptr)
881 {
882  RAPIDJSON_NAMESPACE::Document doc(parseJsonDocFromString(json, jsonSize));
883  if (!doc.Is<Type>()) {
884  if (errors) {
885  errors->reportTypeMismatch<Type>(doc.GetType());
886  }
887  return Type();
888  }
889 
890  return doc.Get<Type>();
891 }
892 
896 template <typename Type, Traits::EnableIf<std::is_same<Type, std::string>> * = nullptr>
897 Type fromJson(const char *json, std::size_t jsonSize, JsonDeserializationErrors *errors = nullptr)
898 {
899  RAPIDJSON_NAMESPACE::Document doc(parseJsonDocFromString(json, jsonSize));
900  if (!doc.IsString()) {
901  if (errors) {
902  errors->reportTypeMismatch<Type>(doc.GetType());
903  }
904  return Type();
905  }
906 
907  return doc.GetString();
908 }
909 
913 template <typename Type, Traits::EnableIf<IsArray<Type>> * = nullptr>
914 Type fromJson(const char *json, std::size_t jsonSize, JsonDeserializationErrors *errors = nullptr)
915 {
916  RAPIDJSON_NAMESPACE::Document doc(parseJsonDocFromString(json, jsonSize));
917  if (!doc.IsArray()) {
918  if (errors) {
919  errors->reportTypeMismatch<Type>(doc.GetType());
920  }
921  return Type();
922  }
923 
924  Type res;
925  pull<Type>(res, doc.GetArray(), errors);
926  return res;
927 }
928 
932 template <typename Type> Type fromJson(const char *json, JsonDeserializationErrors *errors = nullptr)
933 {
934  return fromJson<Type>(json, std::strlen(json), errors);
935 }
936 
940 template <typename Type> Type fromJson(const std::string &json, JsonDeserializationErrors *errors = nullptr)
941 {
942  return fromJson<Type>(json.data(), json.size(), errors);
943 }
944 
945 } // namespace JsonReflector
946 } // namespace ReflectiveRapidJSON
947 
948 #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:55
static void pull(Tuple &tuple, const RAPIDJSON_NAMESPACE::Value::ConstArray value, JsonDeserializationErrors *errors)
Definition: reflector.h:672
static void push(const Tuple &tuple, RAPIDJSON_NAMESPACE::Value::Array &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
Definition: reflector.h:241
RAPIDJSON_NAMESPACE::Document parseJsonDocFromString(const char *json, std::size_t jsonSize)
Parses the specified JSON string.
Definition: reflector.h:66
The AdaptedJsonSerializable class allows considering 3rd party classes as serializable.
Definition: reflector.h:33
Traits::Any< Traits::Not< Traits::IsComplete< Type > >, std::is_base_of< JsonSerializable< Type >, Type >, AdaptedJsonSerializable< Type > > IsJsonSerializable
Definition: reflector.h:87
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:46
static constexpr const char * qualifiedName
Definition: reflector.h:35
static void push(const Tuple &tuple, RAPIDJSON_NAMESPACE::Value::Array &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
Definition: reflector.h:233
RAPIDJSON_NAMESPACE::StringBuffer toJson(const Type &reflectable)
Serializes the specified reflectable.
Definition: reflector.h:849
static constexpr const char * name
Definition: reflector.h:34
std::size_t currentIndex
The index in the array which is currently processed.
Traits::Not< IsBuiltInType< Type > > IsCustomType
Definition: reflector.h:81
static void pull(Tuple &tuple, const RAPIDJSON_NAMESPACE::Value::ConstArray value, JsonDeserializationErrors *errors)
Definition: reflector.h:664
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:663
The TuplePushHelper class helps serializing tuples to JSON arrays.
Definition: reflector.h:232
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:861
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:80
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:134
The JsonSerializable class provides the CRTP-base for (de)serializable objects.
Definition: reflector.h:28
RAPIDJSON_NAMESPACE::Document toJsonDocument(const Type &reflectable)
Serializes the specified reflectable which has a custom type or can be mapped to and object.
Definition: reflector.h:792