Some days ago I introduced the possibility to serialize a QObject instance to JSON. Today I’m going to show you the opposite operation: initializing a QObject using a JSON object.
I refactored a bit my latest changes: I created a new class called QObjectHelper that provides the methods required to convert a QObject instance to a QVariantMap and vice-versa.
This class can be used in conjunction with the Serializer and Parser classes to serialize and deserialize QObject instances to and from JSON.
Let me show a quick example, suppose the declaration of Person class looks like this:
class Person : public QObject
{
Q_OBJECT
Q_PROPERTY(QString name READ name WRITE setName)
Q_PROPERTY(int phoneNumber READ phoneNumber WRITE setPhoneNumber)
Q_PROPERTY(Gender gender READ gender WRITE setGender)
Q_PROPERTY(QDate dob READ dob WRITE setDob)
Q_ENUMS(Gender)
public:
Person(QObject* parent = 0);
~Person();
QString name() const;
void setName(const QString& name);
int phoneNumber() const;
void setPhoneNumber(const int phoneNumber);
enum Gender {Male, Female};
void setGender(Gender gender);
Gender gender() const;
QDate dob() const;
void setDob(const QDate& dob);
private:
QString m_name;
int m_phoneNumber;
Gender m_gender;
QDate m_dob;
};
From QObject to JSON
The following code will serialize an instance of Person to JSON :
Person person;
person.setName("Flavio");
person.setPhoneNumber(123456);
person.setGender(Person::Male);
person.setDob(QDate(1982, 7, 12));
QVariantMap variant = QObjectHelper::qobject2qvariant(&person);
Serializer serializer;
qDebug() << serializer.serialize( variant);
The generated output will be:
{ "dob" : "1982-07-12", "gender" : 0, "name" : "Flavio", "phoneNumber" : 123456 }
From JSON to QObject
Suppose you have the following JSON data stored into a QString:
{ "dob" : "1982-07-12", "gender" : 0, "name" : "Flavio", "phoneNumber" : 123456 }
The following code will initialize an already allocated instance of Person using the JSON values:
Parser parser; QVariant variant = parser.parse(json); Person person; QObjectHelper::qvariant2qobject(variant.toMap(), &person);
A new release
These changes have been included inside the new release of QJson: 0.7.0.
Packages for openSUSE are building right now.
Tags: KDE, qjson, Qt














Entries (RSS)
What about nested types?
I’m going to provide some examples showing serializing operations with nested types.
Cool! I’m not sure what you have in mind, but from looking at this code:
QVariant value = object->property(name);
result[QLatin1String(name)] = value;
, it looks like the user will have to manually convert those map values that are still qobjects into more qvariantmaps. Isn’t there a recursive way to do this automatically? The question is, what types of qobjects warrant this type of property treatment, and which do not?
But it looks like you’ve already answered that question:
Line 144: //TODO: catch other values like QImage, QRect, …
Maybe the recursive logic aught to be included here (or included in a overloaded seralize() for qobjects). That is to say, all qobjects that cannot be converted like the other qvariants get converted recursively using the qt property system.
This way you could call seralize on any qobject and have it resolve the properties or JSON equivalants recursively and automatically.
Or am I confused about something?
And parsing would use a similar recursive method.
Please remember not to use classes under Q + Capital letter in the global namespace. Those are reserved by Qt itself. Imagine what would happen if QJson were to be included in Qt.
You are right! I’m going to drop the initial Q. Let me know if you have a better name
namespace QJson {
…isn’t it already in the QJson namespace, and not the global one?
Yes, but who knows what can happen in the future…
Have you got a plan to create JSON member names that are not valid c++ symbols, for example “date-of-birth” or “delete”? The c++ compiler will choke on this when it is used as a property name. Is this a real problem?
I read rfc4627 and there are no restrictions on member names to make them compiler-friendly.
I encountered this problem when making Qt bindings for the NetworkManager DBUS interface – since they were using manually created variant maps to represent settings with no real object backing it, the designers had no reason not to use ‘-’ liberally in member names. I had to create a mapping system to turn legal c++ symbols back into what the server expects on the bus.
Perhaps you could optionally supply a mapping to the Serializer and Parser classes allowing them to perform this?
Thanks for pointing out this issue, I didn’t think about it. Providing a mapping to theSerializer and Parser classes sounds good.
Very great, I will try that out soon.
Do you have any timeframe on the name change? (Could be a bit nasty to convert a big project later)
I think I’ll perform the name change today. Do you have any hint?
As we discussed, I’ve implemented the serializer side of things for the recursive/nested implementation. What remains is the parser side of things. Also some duplicate code needs to be taken care of. The logic for the qobject serialization has been taken out of qobjecthelper and put directly in the serializer class. Eventually the same would be done for the parser, and qobjecthelper would no longer be necessary. Here’s the patch:
http://data.zx2c4.com/recursiveqjsonserializer.diff
If you like it, let me know, and I’ll commit it myself.
Hello,
It’s probably already discussed but I’m looking at the code and it seems that the serialization is done recursively. It may be a problem in case of a huge depth, like serializing a tree, right?
Well, the serialization would just require more time…
API question: Why do you have to create a “Parser parser” or “Serializer serializer” object first?
Can’t the API look like this?
QVariant variant = QtJson::decode( jsonString );
QString json = QtJson::encode( qvariant )
e.g. using static methods.
This isn’t possible because of certain error handling code.
void setPhoneNumber(const int phoneNumber);
isn’t the const needless? I mean it’s a simple integer which gets copied, not a reference.
You are right, it’s pretty useless but at least it guarantees phoneNumber value won’t be accidentally altered