Reflection for RapidJSON  0.0.2
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 <string>
22 #include <tuple>
23 #include <unordered_map>
24 
25 #include "./errorhandling.h"
26 
28 
29 template <typename Type> struct JsonSerializable;
30 
34 template <typename T> struct AdaptedJsonSerializable : public Traits::Bool<false> {
35  static constexpr const char *name = "AdaptedJsonSerializable";
36  static constexpr const char *qualifiedName = "ReflectiveRapidJSON::AdaptedJsonSerializable";
37 };
38 
42 namespace JsonReflector {
43 
47 constexpr RAPIDJSON_NAMESPACE::SizeType rapidJsonSize(std::size_t size)
48 {
49  return size > std::numeric_limits<RAPIDJSON_NAMESPACE::SizeType>::max() ? std::numeric_limits<RAPIDJSON_NAMESPACE::SizeType>::max()
50  : static_cast<RAPIDJSON_NAMESPACE::SizeType>(size);
51 }
52 
56 inline RAPIDJSON_NAMESPACE::StringBuffer serializeJsonDocToString(RAPIDJSON_NAMESPACE::Document &document)
57 {
58  RAPIDJSON_NAMESPACE::StringBuffer buffer;
59  RAPIDJSON_NAMESPACE::Writer<RAPIDJSON_NAMESPACE::StringBuffer> writer(buffer);
60  document.Accept(writer);
61  return buffer;
62 }
63 
67 inline RAPIDJSON_NAMESPACE::Document parseJsonDocFromString(const char *json, std::size_t jsonSize)
68 {
69  RAPIDJSON_NAMESPACE::Document document(RAPIDJSON_NAMESPACE::kObjectType);
70  const RAPIDJSON_NAMESPACE::ParseResult parseRes = document.Parse(json, jsonSize);
71  if (parseRes.IsError()) {
72  throw parseRes;
73  }
74  return document;
75 }
76 
77 // define traits to distinguish between "built-in" types like int, std::string, std::vector, ... and custom structs/classes
78 template <typename Type>
79 using IsBuiltInType = Traits::Any<std::is_integral<Type>, std::is_floating_point<Type>, std::is_pointer<Type>, std::is_enum<Type>,
80  Traits::IsSpecializationOf<Type, std::tuple>, Traits::IsIteratable<Type>, Traits::IsSpecializationOf<Type, std::unique_ptr>,
81  Traits::IsSpecializationOf<Type, std::shared_ptr>, Traits::IsSpecializationOf<Type, std::weak_ptr>>;
82 template <typename Type> using IsCustomType = Traits::Not<IsBuiltInType<Type>>;
83 
84 // define trait to check for custom structs/classes which are JSON serializable
85 // NOTE: the check for Traits::IsComplete is required because std::is_base_of fails for incomplete types when using GCC
86 template <typename Type>
88  = Traits::Any<Traits::Not<Traits::IsComplete<Type>>, std::is_base_of<JsonSerializable<Type>, Type>, AdaptedJsonSerializable<Type>>;
89 
90 // define trait to check for map or hash
91 template <typename Type>
92 using IsMapOrHash = Traits::Any<Traits::IsSpecializationOf<Type, std::map>, Traits::IsSpecializationOf<Type, std::unordered_map>>;
93 template <typename Type>
94 using IsArray
95  = Traits::All<Traits::IsIteratable<Type>, Traits::Not<Traits::IsSpecializationOf<Type, std::basic_string>>, Traits::Not<IsMapOrHash<Type>>>;
96 
97 // define functions to "push" values to a RapidJSON array or object
98 
102 template <typename Type, Traits::DisableIf<IsBuiltInType<Type>>...>
103 void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator);
104 
108 template <typename Type, Traits::DisableIf<IsJsonSerializable<Type>>...>
109 void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value::Array &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator);
110 
114 template <typename Type, Traits::EnableIf<IsJsonSerializable<Type>>...>
115 void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value::Array &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator);
116 
120 template <typename Type, Traits::EnableIf<IsJsonSerializable<Type>>...>
121 void push(
122  const Type &reflectable, const char *name, RAPIDJSON_NAMESPACE::Value::Object &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator);
123 
127 template <typename Type, Traits::DisableIf<IsJsonSerializable<Type>>...>
128 void push(
129  const Type &reflectable, const char *name, RAPIDJSON_NAMESPACE::Value::Object &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator);
130 
135 template <typename Type, Traits::DisableIf<IsBuiltInType<Type>>...>
136 void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value::Object &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator);
137 
141 template <typename Type, Traits::DisableIf<IsBuiltInType<Type>>...>
142 inline void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
143 {
144  value.SetObject();
145  RAPIDJSON_NAMESPACE::Value::Object obj(value.GetObject());
146  push(reflectable, obj, allocator);
147 }
148 
152 template <typename Type, Traits::EnableIfAny<std::is_integral<Type>, std::is_floating_point<Type>>...>
153 inline void push(Type reflectable, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
154 {
155  value.Set(reflectable, allocator);
156 }
157 
161 template <typename Type, Traits::EnableIfAny<std::is_enum<Type>>...>
162 inline void push(Type reflectable, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
163 {
164  value.Set(static_cast<Traits::Conditional<std::is_unsigned<typename std::underlying_type<Type>::type>, uint64, int64>>(reflectable), allocator);
165 }
166 
170 template <typename Type, Traits::EnableIf<std::is_same<Type, const char *>>...>
171 inline void push(Type 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, const char *const &>>...>
180 inline void push(const char *const &reflectable, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
181 {
182  value.SetString(RAPIDJSON_NAMESPACE::StringRef(reflectable), allocator);
183 }
184 
188 template <typename Type, Traits::EnableIf<std::is_same<Type, std::string>>...>
189 inline void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
190 {
191  value.SetString(RAPIDJSON_NAMESPACE::StringRef(reflectable.data(), reflectable.size()), allocator);
192 }
193 
197 template <typename Type, Traits::EnableIf<IsArray<Type>, Traits::HasSize<Type>>...>
198 void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
199 {
200  value.SetArray();
201  RAPIDJSON_NAMESPACE::Value::Array array(value.GetArray());
202  array.Reserve(reflectable.size(), allocator);
203  for (const auto &item : reflectable) {
204  push(item, array, allocator);
205  }
206 }
207 
211 template <typename Type, Traits::EnableIf<IsArray<Type>, Traits::Not<Traits::HasSize<Type>>>...>
212 void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
213 {
214  value.SetArray();
215  RAPIDJSON_NAMESPACE::Value::Array array(value.GetArray());
216  for (const auto &item : reflectable) {
217  push(item, array, allocator);
218  }
219 }
220 
224 template <typename Type, Traits::EnableIf<IsMapOrHash<Type>>...>
225 void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
226 {
227  value.SetObject();
228  RAPIDJSON_NAMESPACE::Value::Object object(value.GetObject());
229  for (const auto &item : reflectable) {
230  push(item.second, item.first.data(), object, allocator);
231  }
232 }
233 
234 namespace Detail {
235 
239 template <class Tuple, std::size_t N> struct TuplePushHelper {
240  static void push(const Tuple &tuple, RAPIDJSON_NAMESPACE::Value::Array &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
241  {
242  TuplePushHelper<Tuple, N - 1>::push(tuple, value, allocator);
243  JsonReflector::push(std::get<N - 1>(tuple), value, allocator);
244  }
245 };
246 
247 template <class Tuple> struct TuplePushHelper<Tuple, 1> {
248  static void push(const Tuple &tuple, RAPIDJSON_NAMESPACE::Value::Array &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
249  {
250  JsonReflector::push(std::get<0>(tuple), value, allocator);
251  }
252 };
253 } // namespace Detail
254 
258 template <typename Type, Traits::EnableIf<Traits::IsSpecializationOf<Type, std::tuple>>...>
259 void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
260 {
261  value.SetArray();
262  RAPIDJSON_NAMESPACE::Value::Array array(value.GetArray());
263  array.Reserve(std::tuple_size<Type>::value, allocator);
264  Detail::TuplePushHelper<Type, std::tuple_size<Type>::value>::push(reflectable, array, allocator);
265 }
266 
270 template <typename Type,
271  Traits::EnableIfAny<Traits::IsSpecializationOf<Type, std::unique_ptr>, Traits::IsSpecializationOf<Type, std::shared_ptr>,
272  Traits::IsSpecializationOf<Type, std::weak_ptr>>...>
273 void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
274 {
275  if (!reflectable) {
276  value.SetNull();
277  return;
278  }
279  push(*reflectable, value, allocator);
280 }
281 
285 template <typename Type, Traits::EnableIf<IsJsonSerializable<Type>>...>
286 void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value::Array &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
287 {
288  RAPIDJSON_NAMESPACE::Value objectValue(RAPIDJSON_NAMESPACE::kObjectType);
289  RAPIDJSON_NAMESPACE::Value::Object object(objectValue.GetObject());
290  push(reflectable, object, allocator);
291  value.PushBack(objectValue, allocator);
292 }
293 
297 template <typename Type, Traits::DisableIf<IsJsonSerializable<Type>>...>
298 void push(const Type &reflectable, RAPIDJSON_NAMESPACE::Value::Array &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
299 {
300  RAPIDJSON_NAMESPACE::Value genericValue;
301  push(reflectable, genericValue, allocator);
302  value.PushBack(genericValue, allocator);
303 }
304 
308 template <typename Type, Traits::EnableIf<IsJsonSerializable<Type>>...>
309 void push(
310  const Type &reflectable, const char *name, RAPIDJSON_NAMESPACE::Value::Object &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
311 {
312  RAPIDJSON_NAMESPACE::Value objectValue(RAPIDJSON_NAMESPACE::kObjectType);
313  RAPIDJSON_NAMESPACE::Value::Object object(objectValue.GetObject());
314  push(reflectable, object, allocator);
315  value.AddMember(RAPIDJSON_NAMESPACE::StringRef(name), objectValue, allocator);
316 }
317 
321 template <typename Type, Traits::DisableIf<IsJsonSerializable<Type>>...>
322 void push(
323  const Type &reflectable, const char *name, RAPIDJSON_NAMESPACE::Value::Object &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
324 {
325  RAPIDJSON_NAMESPACE::Value genericValue;
326  push(reflectable, genericValue, allocator);
327  value.AddMember(RAPIDJSON_NAMESPACE::StringRef(name), genericValue, allocator);
328 }
329 
330 // define functions to "pull" values from a RapidJSON array or object
331 
336 template <typename Type, Traits::DisableIf<IsBuiltInType<Type>>...>
337 void pull(Type &reflectable, const RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>>::ConstObject &value,
338  JsonDeserializationErrors *errors);
339 
343 template <typename Type, Traits::DisableIf<IsBuiltInType<Type>>...>
344 void pull(Type &reflectable, const RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors);
345 
349 template <typename Type, Traits::EnableIf<IsArray<Type>, Traits::Not<Traits::IsReservable<Type>>>...>
350 void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors);
351 
355 template <typename Type, Traits::EnableIf<IsArray<Type>, Traits::IsReservable<Type>>...>
356 void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors);
357 
361 template <typename Type, Traits::EnableIf<IsArray<Type>>...>
362 void pull(Type &reflectable, rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>>::ConstArray array, JsonDeserializationErrors *errors);
363 
367 template <typename Type, Traits::EnableIf<IsMapOrHash<Type>>...>
368 void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors);
369 
373 template <typename Type, Traits::EnableIf<Traits::IsSpecializationOf<Type, std::tuple>>...>
374 void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors);
375 
379 template <typename Type, Traits::EnableIf<Traits::IsSpecializationOf<Type, std::unique_ptr>>...>
380 void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors);
381 
385 template <typename Type, Traits::EnableIf<Traits::IsSpecializationOf<Type, std::shared_ptr>>...>
386 void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors);
387 
391 template <typename Type>
392 inline void pull(
393  Type &reflectable, rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>>::ValueIterator &value, JsonDeserializationErrors *errors);
394 
400 template <typename Type>
401 inline void pull(Type &reflectable, const char *name, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>>::ConstObject &value,
402  JsonDeserializationErrors *errors);
403 
407 template <typename Type, Traits::DisableIf<IsBuiltInType<Type>>...>
408 void pull(Type &reflectable, const RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors);
409 
413 template <typename Type,
414  Traits::EnableIf<Traits::Not<std::is_same<Type, bool>>, Traits::Any<std::is_integral<Type>, std::is_floating_point<Type>>>...>
415 inline void pull(
416  Type &reflectable, const RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors)
417 {
418  if (!value.IsNumber()) {
419  if (errors) {
420  errors->reportTypeMismatch<Type>(value.GetType());
421  }
422  return;
423  }
424  reflectable = value.Is<Type>() ? value.Get<Type>() : static_cast<Type>(value.GetDouble());
425 }
426 
430 template <typename Type, Traits::EnableIf<std::is_same<Type, bool>>...>
431 inline void pull(
432  Type &reflectable, const RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors)
433 {
434  if (!value.IsBool()) {
435  if (errors) {
436  errors->reportTypeMismatch<Type>(value.GetType());
437  }
438  return;
439  }
440  reflectable = value.GetBool();
441 }
442 
447 template <typename Type, Traits::EnableIfAny<std::is_enum<Type>>...>
448 inline void pull(
449  Type &reflectable, const RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors)
450 {
451  using ExpectedType = Traits::Conditional<std::is_unsigned<typename std::underlying_type<Type>::type>, uint64, int64>;
452  if (!value.Is<ExpectedType>()) {
453  if (errors) {
454  errors->reportTypeMismatch<ExpectedType>(value.GetType());
455  }
456  return;
457  }
458  reflectable = static_cast<Type>(value.Get<ExpectedType>());
459 }
460 
464 template <typename Type, Traits::EnableIf<std::is_same<Type, std::string>>...>
465 inline void pull(
466  Type &reflectable, const RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors)
467 {
468  if (!value.IsString()) {
469  if (errors) {
470  errors->reportTypeMismatch<std::string>(value.GetType());
471  }
472  return;
473  }
474  reflectable = value.GetString();
475 }
476 
481 template <typename Type, Traits::EnableIfAny<std::is_same<Type, const char *>, std::is_same<Type, const char *const &>>...>
482 inline void pull(Type &, const RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors)
483 {
484  if (!value.IsString()) {
485  if (errors) {
486  errors->reportTypeMismatch<std::string>(value.GetType());
487  }
488  return;
489  }
490 }
491 
495 template <typename Type, Traits::EnableIf<IsArray<Type>, Traits::Not<Traits::IsReservable<Type>>>...>
496 void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors)
497 {
498  if (!value.IsArray()) {
499  if (errors) {
500  errors->reportTypeMismatch<Type>(value.GetType());
501  }
502  return;
503  }
504  pull(reflectable, value.GetArray(), errors);
505 }
506 
510 template <typename Type, Traits::EnableIf<IsArray<Type>, Traits::IsReservable<Type>>...>
511 void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors)
512 {
513  if (!value.IsArray()) {
514  if (errors) {
515  errors->reportTypeMismatch<Type>(value.GetType());
516  }
517  return;
518  }
519  auto array = value.GetArray();
520  reflectable.reserve(array.Size());
521  pull(reflectable, array, errors);
522 }
523 
527 template <typename Type, Traits::EnableIf<IsArray<Type>>...>
528 void pull(Type &reflectable, rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>>::ConstArray array, JsonDeserializationErrors *errors)
529 {
530  // clear previous contents of the array
531  reflectable.clear();
532 
533  // pull all array elements of the specified value
534  std::size_t index = 0;
535  for (const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &item : array) {
536  // set error context for current index
537  if (errors) {
538  errors->currentIndex = index;
539  }
540  reflectable.emplace_back();
541  pull(reflectable.back(), item, errors);
542  ++index;
543  }
544 
545  // clear error context
546  if (errors) {
548  }
549 }
550 
554 template <typename Type, Traits::EnableIf<IsMapOrHash<Type>>...>
555 void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors)
556 {
557  if (!value.IsObject()) {
558  if (errors) {
559  errors->reportTypeMismatch<Type>(value.GetType());
560  }
561  return;
562  }
563  auto obj = value.GetObject();
564  for (auto i = obj.MemberBegin(), end = obj.MemberEnd(); i != end; ++i) {
565  pull(reflectable[i->name.GetString()], i->value, errors);
566  }
567 }
568 
569 namespace Detail {
570 
575 template <class Tuple, std::size_t N> struct TuplePullHelper {
576  static void pull(Tuple &tuple, const RAPIDJSON_NAMESPACE::Value::ConstArray value, JsonDeserializationErrors *errors)
577  {
578  TuplePullHelper<Tuple, N - 1>::pull(tuple, value, errors);
579  JsonReflector::pull<typename std::tuple_element<N - 1, Tuple>::type>(std::get<N - 1>(tuple), value[N - 1], errors);
580  }
581 };
582 
583 template <class Tuple> struct TuplePullHelper<Tuple, 1> {
584  static void pull(Tuple &tuple, const RAPIDJSON_NAMESPACE::Value::ConstArray value, JsonDeserializationErrors *errors)
585  {
586  JsonReflector::pull<typename std::tuple_element<0, Tuple>::type>(std::get<0>(tuple), value[0], errors);
587  }
588 };
589 } // namespace Detail
590 
594 template <typename Type, Traits::EnableIf<Traits::IsSpecializationOf<Type, std::tuple>>...>
595 void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors)
596 {
597  if (!value.IsArray()) {
598  if (errors) {
599  errors->reportTypeMismatch<Type>(value.GetType());
600  }
601  return;
602  }
603  auto array = value.GetArray();
604  if (array.Size() != std::tuple_size<Type>::value) {
605  if (errors) {
606  // FIXME: report expected and actual size
607  errors->reportArraySizeMismatch();
608  }
609  return;
610  }
611  Detail::TuplePullHelper<Type, std::tuple_size<Type>::value>::pull(reflectable, array, errors);
612 }
613 
617 template <typename Type, Traits::EnableIf<Traits::IsSpecializationOf<Type, std::unique_ptr>>...>
618 void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors)
619 {
620  if (value.IsNull()) {
621  reflectable.reset();
622  return;
623  }
624  reflectable = std::make_unique<typename Type::element_type>();
625  pull(*reflectable, value, errors);
626 }
627 
631 template <typename Type, Traits::EnableIf<Traits::IsSpecializationOf<Type, std::shared_ptr>>...>
632 void pull(Type &reflectable, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors)
633 {
634  if (value.IsNull()) {
635  reflectable.reset();
636  return;
637  }
638  reflectable = std::make_shared<typename Type::element_type>();
639  pull(*reflectable, value, errors);
640 }
641 
645 template <typename Type>
646 inline void pull(Type &reflectable, rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>>::ValueIterator &value, JsonDeserializationErrors *errors)
647 {
648  pull<Type>(reflectable, *value, errors);
649  ++value;
650 }
651 
657 template <typename Type>
658 inline void pull(Type &reflectable, const char *name, const rapidjson::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>>::ConstObject &value,
660 {
661  // find member
662  const auto member = value.FindMember(name);
663  if (member == value.MemberEnd()) {
664  return; // TODO: handle member missing
665  }
666 
667  // set error context for current member
668  const char *previousMember;
669  if (errors) {
670  previousMember = errors->currentMember;
671  errors->currentMember = name;
672  }
673 
674  // actually pull value for member
675  pull<Type>(reflectable, member->value, errors);
676 
677  // restore previous error context
678  if (errors) {
679  errors->currentMember = previousMember;
680  }
681 }
682 
686 template <typename Type, Traits::DisableIf<IsBuiltInType<Type>>...>
687 void pull(Type &reflectable, const RAPIDJSON_NAMESPACE::GenericValue<RAPIDJSON_NAMESPACE::UTF8<char>> &value, JsonDeserializationErrors *errors)
688 {
689  if (!value.IsObject()) {
690  if (errors) {
691  errors->reportTypeMismatch<Type>(value.GetType());
692  }
693  return;
694  }
695  pull(reflectable, value.GetObject(), errors);
696 }
697 
698 // define functions providing high-level JSON serialization
699 
703 template <typename Type, Traits::EnableIfAny<IsJsonSerializable<Type>, IsMapOrHash<Type>>...>
704 RAPIDJSON_NAMESPACE::StringBuffer toJson(const Type &reflectable)
705 {
706  RAPIDJSON_NAMESPACE::Document document(RAPIDJSON_NAMESPACE::kObjectType);
707  RAPIDJSON_NAMESPACE::Document::Object object(document.GetObject());
708  push(reflectable, object, document.GetAllocator());
709  return serializeJsonDocToString(document);
710 }
711 
715 template <typename Type, Traits::EnableIfAny<std::is_integral<Type>, std::is_floating_point<Type>>...>
716 RAPIDJSON_NAMESPACE::StringBuffer toJson(Type reflectable)
717 {
718  RAPIDJSON_NAMESPACE::Document document(RAPIDJSON_NAMESPACE::kNumberType);
719  document.Set(reflectable, document.GetAllocator());
720  return serializeJsonDocToString(document);
721 }
722 
726 template <typename Type, Traits::EnableIf<std::is_same<Type, std::string>>...>
727 RAPIDJSON_NAMESPACE::StringBuffer toJson(const std::string &reflectable)
728 {
729  RAPIDJSON_NAMESPACE::Document document(RAPIDJSON_NAMESPACE::kStringType);
730  document.SetString(RAPIDJSON_NAMESPACE::StringRef(reflectable.data(), reflectable.size()), document.GetAllocator());
731  return serializeJsonDocToString(document);
732 }
733 
737 template <typename Type, Traits::EnableIf<std::is_same<Type, const char *>>...> RAPIDJSON_NAMESPACE::StringBuffer toJson(const char *reflectable)
738 {
739  RAPIDJSON_NAMESPACE::Document document(RAPIDJSON_NAMESPACE::kStringType);
740  document.SetString(RAPIDJSON_NAMESPACE::StringRef(reflectable), document.GetAllocator());
741  return serializeJsonDocToString(document);
742 }
743 
747 template <typename Type, Traits::EnableIf<IsArray<Type>>...> RAPIDJSON_NAMESPACE::StringBuffer toJson(const Type &reflectable)
748 {
749  RAPIDJSON_NAMESPACE::Document document(RAPIDJSON_NAMESPACE::kArrayType);
750  push(reflectable, document, document.GetAllocator());
751  return serializeJsonDocToString(document);
752 }
753 
754 // define functions providing high-level JSON deserialization
755 
759 template <typename Type, Traits::EnableIfAny<IsJsonSerializable<Type>, IsMapOrHash<Type>>...>
760 Type fromJson(const char *json, std::size_t jsonSize, JsonDeserializationErrors *errors = nullptr)
761 {
762  RAPIDJSON_NAMESPACE::Document doc(parseJsonDocFromString(json, jsonSize));
763  if (!doc.IsObject()) {
764  if (errors) {
765  errors->reportTypeMismatch<Type>(doc.GetType());
766  }
767  return Type();
768  }
769 
770  Type res;
771  pull<Type>(res, doc.GetObject(), errors);
772  return res;
773 }
774 
778 template <typename Type, Traits::EnableIfAny<std::is_integral<Type>, std::is_floating_point<Type>>...>
779 Type fromJson(const char *json, std::size_t jsonSize, JsonDeserializationErrors *errors = nullptr)
780 {
781  RAPIDJSON_NAMESPACE::Document doc(parseJsonDocFromString(json, jsonSize));
782  if (!doc.Is<Type>()) {
783  if (errors) {
784  errors->reportTypeMismatch<Type>(doc.GetType());
785  }
786  return Type();
787  }
788 
789  return doc.Get<Type>();
790 }
791 
795 template <typename Type, Traits::EnableIf<std::is_same<Type, std::string>>...>
796 Type fromJson(const char *json, std::size_t jsonSize, JsonDeserializationErrors *errors = nullptr)
797 {
798  RAPIDJSON_NAMESPACE::Document doc(parseJsonDocFromString(json, jsonSize));
799  if (!doc.IsString()) {
800  if (errors) {
801  errors->reportTypeMismatch<Type>(doc.GetType());
802  }
803  return Type();
804  }
805 
806  return doc.GetString();
807 }
808 
812 template <typename Type, Traits::EnableIf<IsArray<Type>>...>
813 Type fromJson(const char *json, std::size_t jsonSize, JsonDeserializationErrors *errors = nullptr)
814 {
815  RAPIDJSON_NAMESPACE::Document doc(parseJsonDocFromString(json, jsonSize));
816  if (!doc.IsArray()) {
817  if (errors) {
818  errors->reportTypeMismatch<Type>(doc.GetType());
819  }
820  return Type();
821  }
822 
823  Type res;
824  pull<Type>(res, doc.GetArray(), errors);
825  return res;
826 }
827 
831 template <typename Type> Type fromJson(const char *json, JsonDeserializationErrors *errors = nullptr)
832 {
833  return fromJson<Type>(json, std::strlen(json), errors);
834 }
835 
839 template <typename Type> Type fromJson(const std::string &json, JsonDeserializationErrors *errors = nullptr)
840 {
841  return fromJson<Type>(json.data(), json.size(), errors);
842 }
843 
844 } // namespace JsonReflector
845 } // namespace ReflectiveRapidJSON
846 
847 #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:56
static void pull(Tuple &tuple, const RAPIDJSON_NAMESPACE::Value::ConstArray value, JsonDeserializationErrors *errors)
Definition: reflector.h:584
static void push(const Tuple &tuple, RAPIDJSON_NAMESPACE::Value::Array &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
Definition: reflector.h:248
Traits::All< Traits::IsIteratable< Type >, Traits::Not< Traits::IsSpecializationOf< Type, std::basic_string > >, Traits::Not< IsMapOrHash< Type > >> IsArray
Definition: reflector.h:95
RAPIDJSON_NAMESPACE::Document parseJsonDocFromString(const char *json, std::size_t jsonSize)
Parses the specified JSON string.
Definition: reflector.h:67
The AdaptedJsonSerializable class allows considering 3rd party classes as serializable.
Definition: reflector.h:34
Traits::Any< Traits::Not< Traits::IsComplete< Type > >, std::is_base_of< JsonSerializable< Type >, Type >, AdaptedJsonSerializable< Type > > IsJsonSerializable
Definition: reflector.h:88
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:47
static constexpr const char * qualifiedName
Definition: reflector.h:36
static void push(const Tuple &tuple, RAPIDJSON_NAMESPACE::Value::Array &value, RAPIDJSON_NAMESPACE::Document::AllocatorType &allocator)
Definition: reflector.h:240
Traits::Any< Traits::IsSpecializationOf< Type, std::map >, Traits::IsSpecializationOf< Type, std::unordered_map > > IsMapOrHash
Definition: reflector.h:92
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:704
static constexpr const char * name
Definition: reflector.h:35
std::size_t currentIndex
The index in the array which is currently processed.
Traits::Not< IsBuiltInType< Type > > IsCustomType
Definition: reflector.h:82
static void pull(Tuple &tuple, const RAPIDJSON_NAMESPACE::Value::ConstArray value, JsonDeserializationErrors *errors)
Definition: reflector.h:576
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:575
The TuplePushHelper class helps serializing tuples to JSON arrays.
Definition: reflector.h:239
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:760
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:81
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:142
The JsonSerializable class provides the CRTP-base for (de)serializable objects.
Definition: reflector.h:29