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