QJson: Move writing from QJsonDocument to QJsonValue

JSON values are now written directly by QJsonValue instead of
QJsonDocument. Only objects and arrays are currently supported to be
written.

Change-Id: I413db14c69e8d6e9f06431051c8d716d1fb9d4eb
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
Johannes Grunenberg 2024-11-13 17:18:27 +01:00
parent c20c7814f4
commit 8fabcb642f
3 changed files with 116 additions and 38 deletions

View File

@ -15,6 +15,7 @@
#include <qdebug.h> #include <qdebug.h>
#include "qdatastream.h" #include "qdatastream.h"
#include "qjsonparser_p.h" #include "qjsonparser_p.h"
#include "qjsonwriter_p.h"
#include <private/qnumeric_p.h> #include <private/qnumeric_p.h>
#include <private/qcborvalue_p.h> #include <private/qcborvalue_p.h>
@ -606,7 +607,7 @@ QVariant QJsonValue::toVariant() const
Currently, only objects/maps and arrays/lists can be parsed. Currently, only objects/maps and arrays/lists can be parsed.
\sa QJsonParseError, isUndefined() \sa QJsonParseError, isUndefined(), toJson()
*/ */
QJsonValue QJsonValue::fromJson(QByteArrayView json, QJsonParseError *error) QJsonValue QJsonValue::fromJson(QByteArrayView json, QJsonParseError *error)
{ {
@ -616,6 +617,43 @@ QJsonValue QJsonValue::fromJson(QByteArrayView json, QJsonParseError *error)
return result; return result;
} }
/*!
\enum QJsonValue::JsonFormat
\since 6.9
This value defines the format of the JSON byte array produced
when converting to a QJsonValue using toJson().
\value Indented Defines human readable output as follows:
\snippet code/src_corelib_serialization_qjsondocument.cpp 0
\value Compact Defines a compact output as follows:
\snippet code/src_corelib_serialization_qjsondocument.cpp 1
*/
/*!
\since 6.9
Converts the QJsonValue to a UTF-8 encoded JSON value in the provided \a format.
Currently, only objects/maps and arrays/lists can be encoded.
\sa fromJson(), JsonFormat
*/
#if !defined(QT_JSON_READONLY) || defined(Q_QDOC)
QByteArray QJsonValue::toJson(JsonFormat format) const
{
QByteArray json;
const QCborContainerPrivate *container = QJsonPrivate::Value::container(value);
if (isArray())
QJsonPrivate::Writer::arrayToJson(container, json, 0, (format == Compact));
else
QJsonPrivate::Writer::objectToJson(container, json, 0, (format == Compact));
return json;
}
#endif
/*! /*!
Returns the type of the value. Returns the type of the value.

View File

@ -35,6 +35,11 @@ public:
Undefined = 0x80 Undefined = 0x80
}; };
enum JsonFormat {
Indented,
Compact,
};
QJsonValue(Type = Null); QJsonValue(Type = Null);
QJsonValue(bool b); QJsonValue(bool b);
QJsonValue(double n); QJsonValue(double n);
@ -71,6 +76,10 @@ public:
static QJsonValue fromJson(QByteArrayView json, QJsonParseError *error = nullptr); static QJsonValue fromJson(QByteArrayView json, QJsonParseError *error = nullptr);
#if !defined(QT_JSON_READONLY) || defined(Q_QDOC)
QByteArray toJson(JsonFormat format = JsonFormat::Indented) const;
#endif
Type type() const; Type type() const;
inline bool isNull() const { return type() == Null; } inline bool isNull() const { return type() == Null; }
inline bool isBool() const { return type() == Bool; } inline bool isBool() const { return type() == Bool; }

View File

@ -267,7 +267,8 @@ void tst_QtJson::testNumbers()
for (int i = 0; i < n; ++i) for (int i = 0; i < n; ++i)
array.append(numbers[i]); array.append(numbers[i]);
QByteArray serialized = QJsonDocument(array).toJson(); QByteArray serialized = QJsonValue(array).toJson();
QCOMPARE(QJsonDocument(array).toJson(), serialized);
QJsonValue json = QJsonValue::fromJson(serialized); QJsonValue json = QJsonValue::fromJson(serialized);
QJsonArray array2 = json.toArray(); QJsonArray array2 = json.toArray();
@ -314,7 +315,8 @@ void tst_QtJson::testNumbers()
for (int i = 0; i < n; ++i) for (int i = 0; i < n; ++i)
array.append(QJsonValue(numbers[i])); array.append(QJsonValue(numbers[i]));
QByteArray serialized = QJsonDocument(array).toJson(); QByteArray serialized = QJsonValue(array).toJson();
QCOMPARE(QJsonDocument(array).toJson(), serialized);
QJsonValue json = QJsonValue::fromJson(serialized); QJsonValue json = QJsonValue::fromJson(serialized);
QJsonArray array2 = json.toArray(); QJsonArray array2 = json.toArray();
@ -359,7 +361,8 @@ void tst_QtJson::testNumbers()
for (int i = 0; i < n; ++i) for (int i = 0; i < n; ++i)
array.append(numbers[i]); array.append(numbers[i]);
QByteArray serialized = QJsonDocument(array).toJson(); QByteArray serialized = QJsonValue(array).toJson();
QCOMPARE(QJsonDocument(array).toJson(), serialized);
QJsonValue json = QJsonValue::fromJson(serialized); QJsonValue json = QJsonValue::fromJson(serialized);
QJsonArray array2 = json.toArray(); QJsonArray array2 = json.toArray();
@ -393,7 +396,8 @@ void tst_QtJson::testNumbers_2()
QJsonValue jValue1(jObject); QJsonValue jValue1(jObject);
QJsonDocument jDocument1(jObject); QJsonDocument jDocument1(jObject);
QByteArray ba(jDocument1.toJson()); QByteArray ba(jValue1.toJson());
QCOMPARE(jDocument1.toJson(), ba);
QJsonValue jValue2(QJsonValue::fromJson(ba)); QJsonValue jValue2(QJsonValue::fromJson(ba));
QJsonDocument jDocument2(QJsonDocument::fromJson(ba)); QJsonDocument jDocument2(QJsonDocument::fromJson(ba));
@ -434,7 +438,8 @@ void tst_QtJson::testNumbers_3()
jObject.insert("d2", QJsonValue(d2)); jObject.insert("d2", QJsonValue(d2));
QJsonDocument jDocument1(jObject); QJsonDocument jDocument1(jObject);
QJsonValue jValue1(jObject); QJsonValue jValue1(jObject);
QByteArray ba(jDocument1.toJson()); QByteArray ba(jValue1.toJson());
QCOMPARE(jDocument1.toJson(), ba);
QJsonDocument jDocument2(QJsonDocument::fromJson(ba)); QJsonDocument jDocument2(QJsonDocument::fromJson(ba));
QJsonValue jValue2(QJsonValue::fromJson(ba)); QJsonValue jValue2(QJsonValue::fromJson(ba));
@ -462,7 +467,7 @@ void tst_QtJson::testNumbers_4()
array << QJsonValue(-9223372036854775808.0); array << QJsonValue(-9223372036854775808.0);
array << QJsonValue(+18446744073709551616.0); array << QJsonValue(+18446744073709551616.0);
array << QJsonValue(-18446744073709551616.0); array << QJsonValue(-18446744073709551616.0);
QJsonDocument doc1 = QJsonDocument(array); QJsonValue doc1 = QJsonValue(array);
const QByteArray json(doc1.toJson()); const QByteArray json(doc1.toJson());
const QByteArray expected = const QByteArray expected =
"[\n" "[\n"
@ -484,7 +489,7 @@ void tst_QtJson::testNumbers_4()
array2 << QJsonValue(Q_INT64_C(-9007199254740992)); array2 << QJsonValue(Q_INT64_C(-9007199254740992));
array2 << QJsonValue(Q_INT64_C(+9223372036854775807)); array2 << QJsonValue(Q_INT64_C(+9223372036854775807));
array2 << QJsonValue(Q_INT64_C(-9223372036854775807)); array2 << QJsonValue(Q_INT64_C(-9223372036854775807));
QJsonDocument doc2 = QJsonDocument(array2); QJsonValue doc2 = QJsonValue(array2);
const QByteArray json2(doc2.toJson()); const QByteArray json2(doc2.toJson());
const QByteArray expected2 = const QByteArray expected2 =
"[\n" "[\n"
@ -1916,7 +1921,7 @@ void tst_QtJson::toVariantList()
void tst_QtJson::toJson() void tst_QtJson::toJson()
{ {
// Test QJsonDocument::Indented format // Test QJson{Document,Value}::Indented format
{ {
QJsonObject object; QJsonObject object;
object.insert("\\Key\n", QString("Value")); object.insert("\\Key\n", QString("Value"));
@ -1929,7 +1934,7 @@ void tst_QtJson::toJson()
array.append(QLatin1String("\\\a\n\r\b\tabcABC\"")); array.append(QLatin1String("\\\a\n\r\b\tabcABC\""));
object.insert("Array", array); object.insert("Array", array);
QByteArray json = QJsonDocument(object).toJson(); QByteArray json = QJsonValue(object).toJson();
QByteArray expected = QByteArray expected =
"{\n" "{\n"
@ -1949,6 +1954,7 @@ void tst_QtJson::toJson()
doc.setObject(object); doc.setObject(object);
json = doc.toJson(); json = doc.toJson();
QCOMPARE(json, expected); QCOMPARE(json, expected);
QCOMPARE(QJsonDocument(object).toJson(), expected);
doc.setArray(array); doc.setArray(array);
json = doc.toJson(); json = doc.toJson();
@ -1961,9 +1967,10 @@ void tst_QtJson::toJson()
" \"\\\\\\u0007\\n\\r\\b\\tabcABC\\\"\"\n" " \"\\\\\\u0007\\n\\r\\b\\tabcABC\\\"\"\n"
"]\n"; "]\n";
QCOMPARE(json, expected); QCOMPARE(json, expected);
QCOMPARE(QJsonValue(array).toJson(), expected);
} }
// Test QJsonDocument::Compact format // Test QJson{Document,Value}::Compact format
{ {
QJsonObject object; QJsonObject object;
object.insert("\\Key\n", QString("Value")); object.insert("\\Key\n", QString("Value"));
@ -1976,7 +1983,7 @@ void tst_QtJson::toJson()
array.append(QLatin1String("\\\a\n\r\b\tabcABC\"")); array.append(QLatin1String("\\\a\n\r\b\tabcABC\""));
object.insert("Array", array); object.insert("Array", array);
QByteArray json = QJsonDocument(object).toJson(QJsonDocument::Compact); QByteArray json = QJsonValue(object).toJson(QJsonValue::Compact);
QByteArray expected = QByteArray expected =
"{\"Array\":[true,999,\"string\",null,\"\\\\\\u0007\\n\\r\\b\\tabcABC\\\"\"],\"\\\\Key\\n\":\"Value\",\"null\":null}"; "{\"Array\":[true,999,\"string\",null,\"\\\\\\u0007\\n\\r\\b\\tabcABC\\\"\"],\"\\\\Key\\n\":\"Value\",\"null\":null}";
QCOMPARE(json, expected); QCOMPARE(json, expected);
@ -1985,11 +1992,13 @@ void tst_QtJson::toJson()
doc.setObject(object); doc.setObject(object);
json = doc.toJson(QJsonDocument::Compact); json = doc.toJson(QJsonDocument::Compact);
QCOMPARE(json, expected); QCOMPARE(json, expected);
QCOMPARE(QJsonDocument(object).toJson(QJsonDocument::Compact), expected);
doc.setArray(array); doc.setArray(array);
json = doc.toJson(QJsonDocument::Compact); json = doc.toJson(QJsonDocument::Compact);
expected = "[true,999,\"string\",null,\"\\\\\\u0007\\n\\r\\b\\tabcABC\\\"\"]"; expected = "[true,999,\"string\",null,\"\\\\\\u0007\\n\\r\\b\\tabcABC\\\"\"]";
QCOMPARE(json, expected); QCOMPARE(json, expected);
QCOMPARE(QJsonValue(array).toJson(QJsonValue::Compact), expected);
} }
} }
@ -2002,7 +2011,7 @@ void tst_QtJson::toJsonSillyNumericValues()
array.append(QJsonValue(std::numeric_limits<double>::quiet_NaN())); // encode to: null array.append(QJsonValue(std::numeric_limits<double>::quiet_NaN())); // encode to: null
object.insert("Array", array); object.insert("Array", array);
QByteArray json = QJsonDocument(object).toJson(); QByteArray json = QJsonValue(object).toJson();
QByteArray expected = QByteArray expected =
"{\n" "{\n"
@ -2039,7 +2048,7 @@ void tst_QtJson::toJsonLargeNumericValues()
array.append(QJsonValue(-9007199254740992LL)); // JS Number min integer array.append(QJsonValue(-9007199254740992LL)); // JS Number min integer
object.insert("Array", array); object.insert("Array", array);
QByteArray json = QJsonDocument(object).toJson(); QByteArray json = QJsonValue(object).toJson();
QByteArray expected = QByteArray expected =
"{\n" "{\n"
@ -2088,7 +2097,7 @@ void tst_QtJson::toJsonDenormalValues()
array.append(QJsonValue(-std::numeric_limits<double>::denorm_min())); array.append(QJsonValue(-std::numeric_limits<double>::denorm_min()));
object.insert("Array", array); object.insert("Array", array);
QByteArray json = QJsonDocument(object).toJson(); QByteArray json = QJsonValue(object).toJson();
QByteArray expected = QByteArray expected =
"{\n" "{\n"
" \"Array\": [\n" " \"Array\": [\n"
@ -2105,6 +2114,8 @@ void tst_QtJson::toJsonDenormalValues()
"}\n"; "}\n";
QCOMPARE(json, expected); QCOMPARE(json, expected);
QCOMPARE(QJsonDocument(object).toJson(), expected);
QJsonDocument doc; QJsonDocument doc;
doc.setObject(object); doc.setObject(object);
json = doc.toJson(); json = doc.toJson();
@ -2118,15 +2129,22 @@ void tst_QtJson::fromJson()
{ {
{ {
QByteArray json = "[\n true\n]\n"; QByteArray json = "[\n true\n]\n";
QJsonDocument doc = QJsonDocument::fromJson(json); QJsonDocument doc = QJsonDocument::fromJson(json);
QVERIFY(!doc.isEmpty()); QVERIFY(!doc.isEmpty());
QCOMPARE(doc.isArray(), true); QCOMPARE(doc.isArray(), true);
QCOMPARE(doc.isObject(), false); QCOMPARE(doc.isObject(), false);
QJsonArray array = doc.array(); QJsonValue root = QJsonValue::fromJson(json);
QVERIFY(root.isArray());
QCOMPARE(doc.array(), root.toArray());
QJsonArray array = root.toArray();
QCOMPARE(array.size(), 1); QCOMPARE(array.size(), 1);
QCOMPARE(array.at(0).type(), QJsonValue::Bool); QCOMPARE(array.at(0).type(), QJsonValue::Bool);
QCOMPARE(array.at(0).toBool(), true); QCOMPARE(array.at(0).toBool(), true);
QCOMPARE(doc.toJson(), json); QCOMPARE(doc.toJson(), json);
QCOMPARE(root.toJson(), json);
} }
{ {
//regression test: test if unicode_control_characters are correctly decoded //regression test: test if unicode_control_characters are correctly decoded
@ -2135,11 +2153,17 @@ void tst_QtJson::fromJson()
QVERIFY(!doc.isEmpty()); QVERIFY(!doc.isEmpty());
QCOMPARE(doc.isArray(), true); QCOMPARE(doc.isArray(), true);
QCOMPARE(doc.isObject(), false); QCOMPARE(doc.isObject(), false);
QJsonArray array = doc.array(); QJsonValue root = QJsonValue::fromJson(json);
QVERIFY(root.isArray());
QCOMPARE(doc.array(), root.toArray());
QJsonArray array = root.toArray();
QCOMPARE(array.size(), 1); QCOMPARE(array.size(), 1);
QCOMPARE(array.at(0).type(), QJsonValue::String); QCOMPARE(array.at(0).type(), QJsonValue::String);
QCOMPARE(array.at(0).toString(), QString::fromUtf8(UNICODE_NON_CHARACTER)); QCOMPARE(array.at(0).toString(), QString::fromUtf8(UNICODE_NON_CHARACTER));
QCOMPARE(doc.toJson(), json); QCOMPARE(doc.toJson(), json);
QCOMPARE(root.toJson(), json);
} }
{ {
QByteArray json = "[]"; QByteArray json = "[]";
@ -2149,6 +2173,10 @@ void tst_QtJson::fromJson()
QCOMPARE(doc.isObject(), false); QCOMPARE(doc.isObject(), false);
QJsonArray array = doc.array(); QJsonArray array = doc.array();
QCOMPARE(array.size(), 0); QCOMPARE(array.size(), 0);
QJsonValue root = QJsonValue::fromJson(json);
QVERIFY(root.isArray());
QCOMPARE(doc.array(), root.toArray());
} }
{ {
QByteArray json = "{}"; QByteArray json = "{}";
@ -2165,10 +2193,16 @@ void tst_QtJson::fromJson()
QVERIFY(!doc.isEmpty()); QVERIFY(!doc.isEmpty());
QCOMPARE(doc.isArray(), false); QCOMPARE(doc.isArray(), false);
QCOMPARE(doc.isObject(), true); QCOMPARE(doc.isObject(), true);
QJsonObject object = doc.object(); QJsonValue root = QJsonValue::fromJson(json);
QVERIFY(root.isObject());
QCOMPARE(doc.object(), root.toObject());
QJsonObject object = root.toObject();
QCOMPARE(object.size(), 1); QCOMPARE(object.size(), 1);
QCOMPARE(object.value("Key"), QJsonValue(true)); QCOMPARE(object.value("Key"), QJsonValue(true));
QCOMPARE(doc.toJson(), json); QCOMPARE(doc.toJson(), json);
QCOMPARE(root.toJson(), json);
} }
{ {
QByteArray json = "[ null, true, false, \"Foo\", 1, [], {} ]"; QByteArray json = "[ null, true, false, \"Foo\", 1, [], {} ]";
@ -2535,9 +2569,7 @@ void tst_QtJson::parseStrings()
QJsonValue val = array.at(0); QJsonValue val = array.at(0);
QCOMPARE(val.type(), QJsonValue::String); QCOMPARE(val.type(), QJsonValue::String);
// TODO: QJsonValue::toJson QCOMPARE(root.toJson(), json);
QJsonDocument doc(array);
QCOMPARE(doc.toJson(), json);
} }
struct Pairs { struct Pairs {
@ -2568,9 +2600,7 @@ void tst_QtJson::parseStrings()
QJsonValue val = array.at(0); QJsonValue val = array.at(0);
QCOMPARE(val.type(), QJsonValue::String); QCOMPARE(val.type(), QJsonValue::String);
// TODO: QJsonValue::toJson QCOMPARE(root.toJson(), out);
QJsonDocument doc(array);
QCOMPARE(doc.toJson(), out);
} }
} }
@ -2867,7 +2897,8 @@ void tst_QtJson::makeEscapes()
QFETCH(QByteArray, result); QFETCH(QByteArray, result);
QJsonArray array = { input }; QJsonArray array = { input };
QByteArray json = QJsonDocument(array).toJson(QJsonDocument::Compact); QByteArray json = QJsonValue(array).toJson(QJsonValue::Compact);
QCOMPARE(QJsonDocument(array).toJson(QJsonDocument::Compact), json);
QVERIFY(json.startsWith("[\"")); QVERIFY(json.startsWith("[\""));
result.prepend("[\""); result.prepend("[\"");
@ -3279,14 +3310,14 @@ void tst_QtJson::longStrings()
QMap <QString, QVariant> map; QMap <QString, QVariant> map;
map["key"] = s; map["key"] = s;
/* Create a QJsonDocument from the QMap ... */ /* Create a QJsonValue from the QMap ... */
QJsonDocument d1 = QJsonDocument::fromVariant(QVariant(map)); QJsonValue d1 = QJsonValue::fromVariant(QVariant(map));
/* ... and a QByteArray from the QJsonDocument */ /* ... and a QByteArray from the QJsonDocument */
QByteArray a1 = d1.toJson(); QByteArray a1 = d1.toJson();
/* Create a QJsonDocument from the QByteArray ... */ /* Create a QJsonDocument from the QByteArray ... */
QJsonDocument d2 = QJsonDocument::fromJson(a1); QJsonValue d2 = QJsonValue::fromJson(a1);
/* ... and a QByteArray from the QJsonDocument */ /* ... and a QByteArray from the QJsonValue */
QByteArray a2 = d2.toJson(); QByteArray a2 = d2.toJson();
QCOMPARE(a1, a2); QCOMPARE(a1, a2);
@ -3294,8 +3325,8 @@ void tst_QtJson::longStrings()
QJsonObject o1, o2; QJsonObject o1, o2;
o1[s] = 42; o1[s] = 42;
o2[QLatin1String(ba.data(), i + 1)] = 42; o2[QLatin1String(ba.data(), i + 1)] = 42;
d1.setObject(o1); d1 = o1;
d2.setObject(o2); d2 = o2;
a1 = d1.toJson(); a1 = d1.toJson();
a2 = d2.toJson(); a2 = d2.toJson();
QCOMPARE(a1, a2); QCOMPARE(a1, a2);
@ -3310,13 +3341,13 @@ void tst_QtJson::longStrings()
QMap <QString, QVariant> map; QMap <QString, QVariant> map;
map["key"] = s; map["key"] = s;
/* Create a QJsonDocument from the QMap ... */ /* Create a QJsonValue from the QMap ... */
QJsonDocument d1 = QJsonDocument::fromVariant(QVariant(map)); QJsonValue d1 = QJsonValue::fromVariant(QVariant(map));
/* ... and a QByteArray from the QJsonDocument */ /* ... and a QByteArray from the QJsonValue */
QByteArray a1 = d1.toJson(); QByteArray a1 = d1.toJson();
/* Create a QJsonDocument from the QByteArray ... */ /* Create a QJsonDocument from the QByteArray ... */
QJsonDocument d2 = QJsonDocument::fromJson(a1); QJsonValue d2 = QJsonValue::fromJson(a1);
/* ... and a QByteArray from the QJsonDocument */ /* ... and a QByteArray from the QJsonDocument */
QByteArray a2 = d2.toJson(); QByteArray a2 = d2.toJson();
QCOMPARE(a1, a2); QCOMPARE(a1, a2);
@ -3325,8 +3356,8 @@ void tst_QtJson::longStrings()
QJsonObject o1, o2; QJsonObject o1, o2;
o1[s] = 42; o1[s] = 42;
o2[QLatin1String(ba.data(), i + 1)] = 42; o2[QLatin1String(ba.data(), i + 1)] = 42;
d1.setObject(o1); d1 = o1;
d2.setObject(o2); d2 = o2;
a1 = d1.toJson(); a1 = d1.toJson();
a2 = d2.toJson(); a2 = d2.toJson();
QCOMPARE(a1, a2); QCOMPARE(a1, a2);
@ -3489,7 +3520,7 @@ void tst_QtJson::removeNonLatinKey()
sourceObject.insert(nonLatinKeyName, 1); sourceObject.insert(nonLatinKeyName, 1);
const QByteArray json = QJsonDocument(sourceObject).toJson(); const QByteArray json = QJsonValue(sourceObject).toJson();
const QJsonObject restoredObject = QJsonValue::fromJson(json).toObject(); const QJsonObject restoredObject = QJsonValue::fromJson(json).toObject();
QCOMPARE(sourceObject.keys(), restoredObject.keys()); QCOMPARE(sourceObject.keys(), restoredObject.keys());