Skip to content

Commit 18519ce

Browse files
committed
Allow format choice in, and add additional serializeJson overloads
1 parent aa74341 commit 18519ce

File tree

2 files changed

+99
-17
lines changed

2 files changed

+99
-17
lines changed

lib/core/include/qx/core/qx-json.h

Lines changed: 53 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,14 @@ class QX_CORE_EXPORT File
9696
QString string() const;
9797
};
9898

99+
class QX_CORE_EXPORT Data
100+
{
101+
public:
102+
Data();
103+
104+
QString string() const;
105+
};
106+
99107
class QX_CORE_EXPORT Document
100108
{
101109
private:
@@ -145,7 +153,7 @@ class QX_CORE_EXPORT ArrayElement
145153
QString string() const;
146154
};
147155

148-
using ContextNode = std::variant<File, Document, Object, ObjectKey, Array, ArrayElement>;
156+
using ContextNode = std::variant<File, Data, Document, Object, ObjectKey, Array, ArrayElement>;
149157

150158
} // namespace QxJson
151159

@@ -163,6 +171,7 @@ class QX_CORE_EXPORT JsonError final : public AbstractError<"Qx::JsonError", 5>
163171
TypeMismatch,
164172
EmptyDoc,
165173
InvalidValue,
174+
InvalidData,
166175
MissingFile,
167176
InaccessibleFile,
168177
FileReadError,
@@ -177,6 +186,7 @@ class QX_CORE_EXPORT JsonError final : public AbstractError<"Qx::JsonError", 5>
177186
{TypeMismatch, u"Value type mismatch."_s},
178187
{EmptyDoc, u"The document is empty."_s},
179188
{InvalidValue, u"Invalid value for type."_s},
189+
{InvalidData, u"Data parse error."_s},
180190
{MissingFile, u"File does not exist."_s},
181191
{InaccessibleFile, u"Cannot open the file."_s},
182192
{FileReadError, u"File read error."_s},
@@ -289,6 +299,7 @@ static inline const QString ERR_CONV_TYPE = u"JSON Error: Converting value to %1
289299
static inline const QString ERR_NO_KEY = u"JSON Error: Could not retrieve key '%1'."_s;
290300
static inline const QString ERR_PARSE_DOC = u"JSON Error: Could not parse JSON document."_s;
291301
static inline const QString ERR_READ_FILE = u"JSON Error: Could not read JSON file."_s;
302+
static inline const QString ERR_READ_DATA = u"JSON Error: Could not read JSON data."_s;
292303
static inline const QString ERR_WRITE_FILE = u"JSON Error: Could not write JSON file."_s;
293304

294305
//-Structs---------------------------------------------------------------
@@ -788,10 +799,45 @@ void serializeJson(QJsonDocument& serialized, const T& root)
788799
serialized = QJsonDocument(QxJson::Converter<T>::toJson(root));
789800
}
790801

802+
template<typename T>
803+
requires json_root<T>
804+
JsonError parseJson(T& parsed, const QByteArray& data)
805+
{
806+
// Check for no data
807+
if(data.isEmpty())
808+
return JsonError(QxJsonPrivate::ERR_READ_DATA, JsonError::EmptyDoc).withContext(QxJson::Data());
809+
810+
// Basic parse
811+
QJsonParseError jpe;
812+
QJsonDocument jd = QJsonDocument::fromJson(data, &jpe);
813+
814+
if(jpe.error != jpe.NoError)
815+
return JsonError(QxJsonPrivate::ERR_READ_DATA, JsonError::InvalidData).withContext(QxJson::Data());
816+
817+
// True parse
818+
return parseJson(parsed, jd).withContext(QxJson::Data());
819+
}
820+
821+
template<typename T>
822+
requires json_root<T>
823+
void serializeJson(QByteArray& serialized, const T& root, QJsonDocument::JsonFormat fmt = QJsonDocument::Indented)
824+
{
825+
// Ensure buffer is clear
826+
serialized.clear();
827+
828+
// Create document
829+
QJsonDocument jd;
830+
serializeJson(jd, root);
831+
832+
// Write data
833+
serialized = jd.toJson(fmt);
834+
}
835+
791836
template<typename T>
792837
requires json_root<T>
793838
JsonError parseJson(T& parsed, QFile& file)
794839
{
840+
// NOTE: Don't utilize the QByteArray "data" overload here as we would lose the better error info
795841
if(!file.exists())
796842
return JsonError(QxJsonPrivate::ERR_READ_FILE, JsonError::MissingFile).withContext(QxJson::File(file.fileName()));
797843

@@ -828,7 +874,7 @@ JsonError parseJson(T& parsed, QFile& file)
828874

829875
template<typename T>
830876
requires json_root<T>
831-
JsonError serializeJson(QFile& serialized, const T& root)
877+
JsonError serializeJson(QFile& serialized, const T& root, QJsonDocument::JsonFormat fmt = QJsonDocument::Indented)
832878
{
833879
// Close and re-open file, if open, to ensure correct mode and start of file
834880
if(serialized.isOpen())
@@ -840,15 +886,9 @@ JsonError serializeJson(QFile& serialized, const T& root)
840886
// Close file when finished
841887
QScopeGuard fileGuard([&serialized]{ serialized.close(); });
842888

843-
// Create document
844-
QJsonDocument jd;
845-
serializeJson(jd, root);
846-
847-
// Write data
848-
QByteArray jsonData = jd.toJson();
849-
if(jsonData.isEmpty())
850-
return JsonError(); // No-op
851-
889+
// Serialize
890+
QByteArray jsonData;
891+
serializeJson(jsonData, root, fmt);
852892
if(serialized.write(jsonData) != jsonData.size())
853893
return JsonError(QxJsonPrivate::ERR_WRITE_FILE, JsonError::FileWriteError).withContext(QxJson::File(serialized.fileName(), serialized.errorString()));
854894

@@ -866,11 +906,11 @@ JsonError parseJson(T& parsed, const QString& filePath)
866906

867907
template<typename T>
868908
requires json_root<T>
869-
JsonError serializeJson(const QString& serializedPath, const T& root)
909+
JsonError serializeJson(const QString& serializedPath, const T& root, QJsonDocument::JsonFormat fmt = QJsonDocument::Indented)
870910
{
871911
QFile file(serializedPath);
872912

873-
return serializeJson(file, root);
913+
return serializeJson(file, root, fmt);
874914
}
875915

876916
QX_CORE_EXPORT QList<QJsonValue> findAllValues(const QJsonValue& rootValue, QStringView key);

lib/core/src/qx-json.cpp

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,28 @@ QString QJsonParseErrorAdapter::deriveSecondary() const { return OFFSET_STR.arg(
324324
* @a T must satisfy the Qx::json_root concept.
325325
*/
326326

327+
/*!
328+
* @fn JsonError parseJson(T& parsed, const QByteArray& data)
329+
*
330+
* @overload
331+
*
332+
* Parses @a data as a JSON document and stores the result in @a parsed.
333+
* @a T must satisfy the Qx::json_root concept.
334+
*/
335+
336+
/*!
337+
* @fn JsonError serializeJson(QByteArray& serialized, const T& root, QJsonDocument::JsonFormat fmt)
338+
*
339+
* @overload
340+
*
341+
* Serializes the entire JSON root structure @a root and writes the result to @a serialized in format @a fmt.
342+
*
343+
* @a T must satisfy the Qx::json_root concept.
344+
*
345+
* If serialization fails, a valid JsonError is returned that describes the cause; otherwise, an invalid
346+
* error is returned.
347+
*/
348+
327349
/*!
328350
* @fn JsonError parseJson(T& parsed, QFile& file)
329351
*
@@ -334,11 +356,11 @@ QString QJsonParseErrorAdapter::deriveSecondary() const { return OFFSET_STR.arg(
334356
*/
335357

336358
/*!
337-
* @fn JsonError serializeJson(QFile& serialized, const T& root)
359+
* @fn JsonError serializeJson(QFile& serialized, const T& root, QJsonDocument::JsonFormat fmt)
338360
*
339361
* @overload
340362
*
341-
* Serializes the entire JSON root structure @a root and writes the result to @a serialized in indented format,
363+
* Serializes the entire JSON root structure @a root and writes the result to @a serialized in format @a fmt,
342364
* replacing existing contents, if any.
343365
*
344366
* @a T must satisfy the Qx::json_root concept.
@@ -357,12 +379,12 @@ QString QJsonParseErrorAdapter::deriveSecondary() const { return OFFSET_STR.arg(
357379
*/
358380

359381
/*!
360-
* @fn JsonError serializeJson(const QString& filePath, const T& root)
382+
* @fn JsonError serializeJson(const QString& filePath, const T& root, QJsonDocument::JsonFormat fmt)
361383
*
362384
* @overload
363385
*
364386
* Serializes the entire JSON root structure @a root and writes the result to the file at path @a
365-
* filePath in indented format, replacing existing contents, if any.
387+
* filePath in format @a fmt, replacing existing contents, if any.
366388
*
367389
* @a T must satisfy the Qx::json_root concept.
368390
*
@@ -476,6 +498,26 @@ QString File::string() const
476498
return str;
477499
}
478500

501+
/*!
502+
* @class Data
503+
* @brief The document class represents a JSON data node for use in error contexts.
504+
*
505+
* @note This class is irrelevant in user code except for some instances of complex
506+
* custom JSON parsing
507+
*
508+
* @sa Qx::JsonError::withContext().
509+
*/
510+
511+
/*!
512+
* Constructs a data element node.
513+
*/
514+
Data::Data() {}
515+
516+
/*!
517+
* Returns the string representation of the node.
518+
*/
519+
QString Data::string() const { return u"Data"_s; }
520+
479521
/*!
480522
* @class Document
481523
* @brief The document class represents a JSON document node for use in error contexts.

0 commit comments

Comments
 (0)