swift
mixinjson.h
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: Copyright (C) 2014 swift Project Community / Contributors
2 // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1
3 
5 
6 #ifndef SWIFT_MISC_MIXIN_MIXINJSON_H
7 #define SWIFT_MISC_MIXIN_MIXINJSON_H
8 
9 #include <utility>
10 
11 #include <QJsonArray>
12 #include <QJsonDocument>
13 #include <QJsonObject>
14 #include <QJsonValue>
15 #include <QJsonValueRef>
16 #include <QtGlobal>
17 
18 #include "misc/inheritancetraits.h"
19 #include "misc/json.h"
20 #include "misc/jsonexception.h"
21 
22 namespace swift::misc
23 {
24  class CEmpty;
25 
26  namespace mixin
27  {
35  template <class Derived>
37  {
38  public:
40  friend const QJsonObject &operator>>(const QJsonObject &json, Derived &obj)
41  {
42  obj.convertFromJson(json);
43  return json;
44  }
45 
47  friend const QJsonValue &operator>>(const QJsonValue &json, Derived &obj)
48  {
49  obj.convertFromJson(json.toObject());
50  return json;
51  }
52 
54  friend QJsonValueRef operator>>(QJsonValueRef json, Derived &obj)
55  {
56  obj.convertFromJson(json.toObject());
57  return json;
58  }
59 
61  friend QJsonArray &operator<<(QJsonArray &json, const Derived &obj)
62  {
63  json.append(obj.toJson());
64  return json;
65  }
66 
68  friend QJsonObject &operator<<(QJsonObject &json, const std::pair<QString, const Derived &> &value)
69  {
70  json.insert(value.first, QJsonValue(value.second.toJson()));
71  return json;
72  }
73 
75  friend QJsonObject &operator<<(QJsonObject &json,
76  const std::pair<CExplicitLatin1String, const Derived &> &value)
77  {
78  json[value.first] = QJsonValue(value.second.toJson());
79  return json;
80  }
81  };
82 
88  template <class Derived>
89  class JsonByMetaClass : public JsonOperators<Derived>
90  {
91  public:
93  QJsonObject toJson() const;
94 
96  QString toJsonString(QJsonDocument::JsonFormat format = QJsonDocument::Indented) const;
97 
99  void convertFromJson(const QJsonObject &json);
100 
102  void convertFromJson(const QString &jsonString, bool acceptCacheFormat = false);
103 
105  template <class DerivedObj = Derived>
106  static DerivedObj fromJson(const QJsonObject &json);
107 
109  template <class DerivedObj = Derived>
110  static DerivedObj fromJson(const QString &jsonString, bool acceptCacheJson = false);
111 
113  template <class DerivedObj = Derived>
114  static DerivedObj fromJsonNoThrow(const QString &jsonString, bool acceptCacheJson, bool &success,
115  QString &errMsg);
116 
117  private:
118  const Derived *derived() const;
119  Derived *derived();
120 
121  template <typename T>
122  static QJsonObject baseToJson(const T *base);
123  template <typename T>
124  static void baseConvertFromJson(T *base, const QJsonObject &json);
125  static QJsonObject baseToJson(const void *);
126  static void baseConvertFromJson(void *, const QJsonObject &);
127  static QJsonObject baseToJson(const CEmpty *);
128  static void baseConvertFromJson(CEmpty *, const QJsonObject &);
129  };
130 
131  template <class Derived>
133  {
134  QJsonObject json;
135  introspect<Derived>().forEachMember([&, this](auto member) {
136  if constexpr (!decltype(member)::has(MetaFlags<DisabledForJson>()))
137  {
138  json << std::make_pair(CExplicitLatin1String(member.latin1Name()),
139  std::cref(member.in(*this->derived())));
140  }
141  });
142  return json::appendJsonObject(json, baseToJson(static_cast<const TBaseOfT<Derived> *>(derived())));
143  }
144 
145  template <class Derived>
146  QString JsonByMetaClass<Derived>::toJsonString(QJsonDocument::JsonFormat format) const
147  {
148  QJsonDocument jsonDoc(toJson());
149  return jsonDoc.toJson(format);
150  }
151 
152  template <class Derived>
153  void JsonByMetaClass<Derived>::convertFromJson(const QJsonObject &json)
154  {
155  baseConvertFromJson(static_cast<TBaseOfT<Derived> *>(derived()), json);
156  introspect<Derived>().forEachMember([&, this](auto member) {
157  if constexpr (!decltype(member)::has(MetaFlags<DisabledForJson>()))
158  {
159  const auto value = json.value(CExplicitLatin1String(member.latin1Name()));
160  if (value.isUndefined())
161  {
162  constexpr bool required = decltype(member)::has(MetaFlags<RequiredForJson>());
163  // QLatin1String used instead of QStringLiteral below since the latter causes an internal
164  // compiler bug in GCC 8 and higher
165  if (required)
166  {
167  throw CJsonException(
168  QLatin1String("Missing required member '%1'").arg(member.latin1Name()));
169  } // cppcheck-suppress knownConditionTrueFalse
170  }
171  else
172  {
173  CJsonScope scope(member.latin1Name());
174  Q_UNUSED(scope);
175  value >> member.in(*this->derived());
176  }
177  }
178  });
179  }
180 
181  template <class Derived>
182  void JsonByMetaClass<Derived>::convertFromJson(const QString &jsonString, bool acceptCacheFormat)
183  {
184  const QJsonObject jsonObject = swift::misc::json::jsonObjectFromString(jsonString, acceptCacheFormat);
185  convertFromJson(jsonObject);
186  }
187 
188  template <class Derived>
189  template <class DerivedObj>
190  DerivedObj JsonByMetaClass<Derived>::fromJson(const QJsonObject &json)
191  {
192  DerivedObj obj;
193  obj.convertFromJson(json);
194  return obj;
195  }
196 
197  template <class Derived>
198  template <class DerivedObj>
199  DerivedObj JsonByMetaClass<Derived>::fromJson(const QString &jsonString, bool acceptCacheJson)
200  {
201  DerivedObj obj;
202  if (jsonString.isEmpty()) { return obj; }
203  const QJsonObject jsonObj =
204  acceptCacheJson ? json::swiftDataObjectValue(jsonString) : json::jsonObjectFromString(jsonString);
205  obj.convertFromJson(jsonObj);
206  return obj;
207  }
208 
209  template <class Derived>
210  template <class DerivedObj>
211  DerivedObj JsonByMetaClass<Derived>::fromJsonNoThrow(const QString &jsonString, bool acceptCacheJson,
212  bool &success, QString &errMsg)
213  {
214  success = false;
215  DerivedObj obj;
216  try
217  {
218  if (jsonString.isEmpty()) { return obj; }
219  const QJsonObject jsonObj =
220  acceptCacheJson ? json::swiftDataObjectValue(jsonString) : json::jsonObjectFromString(jsonString);
221  obj.convertFromJson(jsonObj);
222  success = true;
223  }
224  catch (const CJsonException &ex)
225  {
226  errMsg = ex.toString("JSON conversion");
227  }
228  return obj;
229  }
230 
231  template <class Derived>
232  const Derived *JsonByMetaClass<Derived>::derived() const
233  {
234  return static_cast<const Derived *>(this);
235  }
236 
237  template <class Derived>
238  Derived *JsonByMetaClass<Derived>::derived()
239  {
240  return static_cast<Derived *>(this);
241  }
242 
243  template <class Derived>
244  template <typename T>
245  QJsonObject JsonByMetaClass<Derived>::baseToJson(const T *base)
246  {
247  return base->toJson();
248  }
249 
250  template <class Derived>
251  template <typename T>
252  void JsonByMetaClass<Derived>::baseConvertFromJson(T *base, const QJsonObject &json)
253  {
254  base->convertFromJson(json);
255  }
256 
257  template <class Derived>
258  QJsonObject JsonByMetaClass<Derived>::baseToJson(const void *)
259  {
260  return {};
261  }
262 
263  template <class Derived>
264  void JsonByMetaClass<Derived>::baseConvertFromJson(void *, const QJsonObject &)
265  {}
266 
267  template <class Derived>
268  QJsonObject JsonByMetaClass<Derived>::baseToJson(const CEmpty *)
269  {
270  return {};
271  }
272 
273  template <class Derived>
274  void JsonByMetaClass<Derived>::baseConvertFromJson(CEmpty *, const QJsonObject &)
275  {}
276 
281 #define SWIFT_MISC_DECLARE_USING_MIXIN_JSON(DERIVED) \
282  using ::swift::misc::mixin::JsonByMetaClass<DERIVED>::toJson; \
283  using ::swift::misc::mixin::JsonByMetaClass<DERIVED>::convertFromJson;
284  } // namespace mixin
285 } // namespace swift::misc
286 
287 #endif // SWIFT_MISC_MIXIN_MIXINJSON_H
Default base class for CValueObject.
Definition: valueobject.h:76
Thrown when a convertFromJson method encounters an unrecoverable error in JSON data.
Definition: jsonexception.h:24
QString toString(const QString &prefix) const
As string info.
Pseudo-RAII pattern that tracks the current JSON value being converted.
Definition: jsonexception.h:50
CRTP class template from which a derived class can inherit common methods dealing with JSON by metatu...
Definition: mixinjson.h:90
static DerivedObj fromJson(const QJsonObject &json)
Get object from QJsonObject.
Definition: mixinjson.h:190
static DerivedObj fromJson(const QString &jsonString, bool acceptCacheJson=false)
Get object from JSON string.
Definition: mixinjson.h:199
static DerivedObj fromJsonNoThrow(const QString &jsonString, bool acceptCacheJson, bool &success, QString &errMsg)
Get object from JSON string.
Definition: mixinjson.h:211
void convertFromJson(const QJsonObject &json)
Assign from JSON object.
Definition: mixinjson.h:153
void convertFromJson(const QString &jsonString, bool acceptCacheFormat=false)
Assign from JSON object string.
Definition: mixinjson.h:182
QString toJsonString(QJsonDocument::JsonFormat format=QJsonDocument::Indented) const
Convenience function JSON as string.
Definition: mixinjson.h:146
QJsonObject toJson() const
Cast to JSON object.
Definition: mixinjson.h:132
CRTP class template which will generate marshalling operators for a derived class with its own marsha...
Definition: mixinjson.h:37
friend QJsonArray & operator<<(QJsonArray &json, const Derived &obj)
operator << for JSON
Definition: mixinjson.h:61
friend const QJsonValue & operator>>(const QJsonValue &json, Derived &obj)
operator >> for JSON
Definition: mixinjson.h:47
friend QJsonObject & operator<<(QJsonObject &json, const std::pair< CExplicitLatin1String, const Derived & > &value)
operator << for JSON
Definition: mixinjson.h:75
friend QJsonObject & operator<<(QJsonObject &json, const std::pair< QString, const Derived & > &value)
operator << for JSON
Definition: mixinjson.h:68
friend QJsonValueRef operator>>(QJsonValueRef json, Derived &obj)
operator >> for JSON
Definition: mixinjson.h:54
friend const QJsonObject & operator>>(const QJsonObject &json, Derived &obj)
operator >> for JSON
Definition: mixinjson.h:40
QJsonObject & appendJsonObject(QJsonObject &target, const QJsonObject &toBeAppended)
Append to first JSON object (concatenate)
Definition: json.cpp:438
QJsonObject jsonObjectFromString(const QString &json, bool acceptCacheFormat)
JSON Object from string.
Definition: json.cpp:413
Free functions in swift::misc.
typename TBaseOf< T >::type TBaseOfT
Alias for typename TBaseOf<T>::type.
Simple literal type containing a single QLatin1String.
Definition: metaclass.h:102
Type wrapper for passing MetaFlag to CMetaMember::has.
Definition: metaclass.h:119