Comments (6)
I just realized that QVariant actually lets me convert back and forth without any issues however I must be missing a step for QtJsonSerializer. Code snippet below to provide an example.
foo.hpp
class Foobar
{
Q_GADGET
Q_PROPERTY(QString Name MEMBER Name)
public:
QString Name;
};
Q_DECLARE_METATYPE(Foobar)
class FoobarList : public QList<Foobar>
{
Q_GADGET
public:
static void registerMetaType()
{
QtJsonSerializer::JsonSerializer::registerListConverters<Foobar>();
}
FoobarList(const QList<Foobar> &a = QList<Foobar>())
: QList(a)
{}
};
Q_DECLARE_METATYPE(FoobarList)
foo.cpp
namespace
{
void registerMetaType()
{
FoobarList::registerMetaType();
}
} // namespace
Q_COREAPP_STARTUP_FUNCTION(registerMetaType)
main.cpp
#define JSON_PRINT(x) QJsonDocument(x).toJson().constData()
QtJsonSerializer::JsonSerializer s;
FoobarList a;
// populating
for (int i = 0; i < 3; ++i)
{
a.append(Foobar{
.Name = QString("Foo%1").arg(i, 4, 10, QLatin1Char('0')),
});
}
auto printDebug = [&s](const FoobarList &o, const QString &typeName) {
qDebug() << typeName << o.length() << JSON_PRINT(s.serialize(o));
for (int i = 0; i < o.length(); ++i)
qDebug() << QString("%1: %2").arg(i).arg(o.at(i).Name);
};
{ // QVariant
QVariant v;
v.setValue(a);
FoobarList o = v.value<FoobarList>();
printDebug(o, "QVariant"); // success
}
{ // QtJsonSerializer
FoobarList o = s.deserialize<FoobarList>(s.serialize(a));
printDebug(o, "QtJsonSerializer"); // failure
}
Output
"QVariant" 3 {
}
"0: Foo0000"
"1: Foo0001"
"2: Foo0002"
"QtJsonSerializer" 0 {
}
from qtjsonserializer.
QtJsonSerializer detects that your Foobar
is a Q_GADGET
and thus makes a property based serialization. The list is then just detected as such - a generic list of something, in this case the Foobar
, which gets serialized as object.
To archive your goal of having a simple list, you have 2 options:
- Create a custom type converter for
Foobar
, that serializes it to a string instead of a json object - Create a custom type converter for
FoobarList
, that creates a string list.
Creating a custom type converter is not that hard, simply implement the QtJsonSerializer::TypeConverter
class and register it via QtJsonSerializer::JsonSerializer::addTypeConverter
. Check the Documentation for more details.
from qtjsonserializer.
Hello,
I've been working on adding the converted as suggested, it seems to work somewhat but... I can't figure out if some of this stuff is intended or not. Code below.
class FoobarListConverter : public QtJsonSerializer::TypeConverter
{
Q_GADGET
public:
QByteArray name() const override
{
return staticMetaObject.className();
}
QCborTag tag() const
{
static QCborTag r(QCborValue::fromVariant(QVariant::fromValue(FoobarList())).tag());
return r;
}
bool canConvert(int metaTypeId) const override
{
return metaTypeId == qMetaTypeId<FoobarList>();
}
QList<QCborValue::Type> allowedCborTypes(int metaTypeId, QCborTag tag) const override
{
Q_UNUSED(metaTypeId)
Q_UNUSED(tag)
return {QCborValue::Array};
}
QCborValue serialize(int propertyType, const QVariant &value) const override
{
QCborArray r;
for (const auto &v : value.value<FoobarList>())
{
// we know Foobar is properly serialized, so let's make use of that
r.append(helper()->serializeSubtype(qMetaTypeId<Foobar>(), QVariant::fromValue(v)));
}
// add extra for the sake of it
r.append(helper()->serializeSubtype(qMetaTypeId<Foobar>(), QVariant::fromValue(Foobar{
.Name = "FoobarListConverter's Visit Card",
.Text = "It reads: \"FoobarListConverter was here.\"",
})));
return QCborValue(r);
}
QVariant deserializeCbor(int propertyType, const QCborValue &value, QObject *parent) const override
{
Q_UNUSED(propertyType)
Q_UNUSED(parent)
qDebug() << "deserializeCbor" << value.type() << value;
FoobarList r;
for (const auto &v : value.toArray())
{
r.append(helper()->deserializeSubtype(qMetaTypeId<Foobar>(), v, nullptr).value<Foobar>());
}
return QVariant::fromValue(r);
}
};
The serialization does work, but in a strange way for the return value. In main.cpp, if you use serialize, like below:
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QtJsonSerializer::JsonSerializer s;
/**
* I have to keep in mind addJsonTypeConverter
* that is NOT a global register.
*
* Might need a global instance of the serializer
* for this.
*/
s.addJsonTypeConverter<FoobarListConverter>();
FoobarList a;
a.append(Foobar{
.Name = "My Name!",
});
/**
* The method QtJsonSerializer::JsonSerializer::serialize
* always seems to return a QJsonObject for some reason
* despite the documentation stating otherwise and returning
* a QJsonValue, not a QJsonObject. Is the QJsonValue wrapped
* the QJsonObject itself? It seemed empty.
*
* To add to the issue, QtJsonSerializer::JsonSerializer::deserialize
* also only accepts QObjects which is very odd considering that once
* again, the document tell us that it accept a QJsonValue.
*
* Doc: https://skycoder42.github.io/QtJsonSerializer/class_qt_json_serializer_1_1_json_serializer.html#adde044d01cf8e1705ee672562495ad6f
*/
auto i = s.serialize(a); // ALWAYS recover a QJsonObject no matter what I do
qDebug() << "Is the object empty?" << i.isEmpty();
/**
* This method work.
*/
auto j = s.serializeGeneric(QVariant::fromValue(a)); // recover QJsonValue which contains QJsonArray
qDebug() << "QJsonArray" << JSON_PRINT(std::get<QJsonValue>(j).toArray());
auto b = s.deserialize(std::get<QJsonValue>(j).toArray(), qMetaTypeId<FoobarList>()).value<FoobarList>(); // HELP
for (int i = 0; i < b.length(); ++i)
{
const auto &v = b.at(i);
qDebug() << i << v.Name << v.Text << v.Bool;
}
return 0;
}
Console:
Is the object empty? true
QJsonArray [
{
"bool": false,
"name": "My Name!",
"text": ""
},
{
"bool": false,
"name": "FoobarListConverter's Visit Card",
"text": "It reads: \"FoobarListConverter was here.\""
}
]
Are serialize and deserialize intended to only use QJsonObject? This seems unintended as provided by the documentation.
from qtjsonserializer.
Hiya,
I understand my issue. But it seems like a very odd behaviour for serialize and deserialize, the document tell us that it takes/return a Json, not a Json object.
In any case, for the sake of completion, working conversion:
// QJsonArray i = s.serialize(a).toArray(); // doesn't work, always return a QJsonObject
QJsonValue i = s.serialize(QVariant::fromValue(a)); // works, recover QJsonArray as QJsonValue rather than a QJsonObject that has an immediate conversion to QJsonValue
qDebug() << JSON_PRINT(i.toArray());
// FoobarList k = s.deserialize<FoobarList>(i); // can't take QJsonValue or QJsonArray as parameters; only QJsonObject
FoobarList k = s.deserialize(i, qMetaTypeId<FoobarList>()).value<FoobarList>(); // works, obviously
for (int i = 0; i < k.length(); ++i)
{
const auto &v = k.at(i);
qDebug() << i << v.Name << v.Text << v.Bool;
}
Thanks a lot!
from qtjsonserializer.
About those points:
FoobarListConverter::tag
is not really needed, you can simply returnstatic_cast<QCborTag>(-1)
from that method- You can actually register the converter globally. Use
JsonSerializer::addJsonTypeConverterFactory
for this. - The return value stuff is because your
FoobarList
is aQ_GADGET
. The serializer uses some generic stuff to dynamically detect what kind of json certain data would be. Normally, list classes are detected as such and are matched to aQJsonArray
. But since your list is a gadget, that one is detected instead and an object is expected/returned, as that is the "default" for gadgets. You have already figured out the solution: use the QVariant based methods instead, and you're good... I know this is sligthly inconvenient, but this design seemed like a good idea at the time...
from qtjsonserializer.
Thanks a lot, I didn't realize that Q_GADGET would force a map/array to be considered as an object. Thank you again!
from qtjsonserializer.
Related Issues (20)
- QHash<int, QString> workaround HOT 2
- It can't convert QSharedPointer successfully.
- How to deserialize derived classes that use none-default constructors HOT 2
- Mac build "make" step giving .reggen errors. Any advice? HOT 2
- Add module fail HOT 1
- Using multiple instances in Qt subdir HOT 3
- Q_GADGET and QVariantList HOT 1
- Deserialization QPair within QVariant
- Cannot find missing dependency "qt.qt5.5130.android_arm64_v8a" ...
- Runtime exception occurred in sample.
- Sample: SerializationException (Unable to determine typeid of meta enum SampleObject::SuperFlags) HOT 1
- Converting QtJsonSerializer from QMake to CMake HOT 1
- Add entries in the repository for Qt 5.15.* and 6
- CopperSpice support HOT 2
- head of line cannot run sample application HOT 1
- Can not serialize enum properties HOT 3
- Poor performance for array of PODs with simple properties
- registerSetConverters results in build time error no matching function to call qHash(...
- Deserialize into existing object
- Create references to existing object , not duplicates HOT 3
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from qtjsonserializer.