PDA

View Full Version : Serializing nested objects



jiveaxe
12th December 2013, 18:17
Hi, I need your help :P Scenario:

* I created objectA containing a bunch of Q_PROPERTY() and stream operators to serialize it. The code is ok, objectA's properties are saved correctly
* I created objectB containing a bunch of Q_PROPERTY() and objectA is in one of them. When I try to serialize objectB I got the following message in console:


QVariant::save: unable to save type 322.

The resulting file contains all objectB properties except objectA (I can see only the object name, something like MyApp::ObjectA).

Any idea where I'm wrong?

Very thanks.

ChrisW67
12th December 2013, 22:26
Any idea where I'm wrong?
Based on the information you have provided you are doing something wrong with a QVariant.

jiveaxe
12th December 2013, 23:14
Well, I don't think this is the problem. Trying to be more clear:

When I use stream operator on an indipendent objectA (not as data member of objectB) I got a correct result, this should tell me that the stream operator in objecta.h/cpp is ok, right? objectB has its own stream operator, and has objectA as data member. Calling the stream operator of objectB gives the error in first post. If in objectB I comment out the Q_PROPERTY() line regarding objectA (so it is not saved during stream operation) then it works. Probably I'm doing a wrong assumption: I presume that calling operator<< of objectB triggers operator<< of objectA when this one must be saved; am I wrong? (I know, a bit intricate). A very limited example:

objecta.h


class ObjectA : public QObject
{
Q_OBJECT
Q_PROPERTY( QString name READ name WRITE setName )
...
};

QDataStream& operator<<( QDataStream& dataStream, const ObjectA & objectA );


objectb.h


class ObjectB : public QObject
{
Q_OBJECT
Q_PROPERTY( ObjectA objectA READ objectA WRITE setObjectA )
Q_PROPERTY( QString path READ path WRITE setPath )
...
};

QDataStream& operator<<( QDataStream& dataStream, const ObjectB & objectB );


main.cpp


ObjectA objectA;
out << objectA; // works

ObjectB objectB;
objectB.setObjectA(objectA)
out << objectB; // NOT works: QVariant::save: unable to save type 322.

ChrisW67
13th December 2013, 00:38
You have implemented operator<<() for class ObjectB. We cannot see this code.

I can only assume from the involvement of QVariant in the error and the implied connection between a Q_PROPERTY macro and serialisation that you are accessing the property values through QMetaObject and QMetaProperty::read(). Have you declared ObjectA* and its stream operators qRegisterMetaType<T>() and qRegisterMetaTypeStreamOperators<T>()? (You cannot declare for ObjectA because it lacks the requisite copy constructor)

jiveaxe
13th December 2013, 11:18
Sorry, here the missing code:


QDataStream& operator<<( QDataStream& dataStream, const ObjectA & objectA )
{
for(int i=0; i< objectA.metaObject()->propertyCount(); ++i) {
if(objectA.metaObject()->property(i).isStored(&objectA)) {
dataStream << objectA.metaObject()->property(i).read(&objectA);
}
}
return dataStream;
}

(stream operator for ObjectB is the same, just replaced ObjectA with ObjectB)


Have you declared ObjectA* and its stream operators qRegisterMetaType<T>() and qRegisterMetaTypeStreamOperators<T>()?

Nope. Where those line should be added?

I tried adding:



qRegisterMetaType<ObjectA>("ObjectA");
qRegisterMetaTypeStreamOperators<ObjectA>("ObjectA");


in objecta.h but make returns the following error:

objecta.h:28: error: specializing member '::qRegisterMetaType<ObjectA>' requires 'template<>' syntax
qRegisterMetaType<ObjectA>("ObjectA");

Thanks for your help.

jiveaxe
13th December 2013, 17:29
Ok, solved; I added:



qRegisterMetaType<ObjectA>("ObjectA");
qRegisterMetaTypeStreamOperators<ObjectA>("ObjectA");


in constructor of ObjectB and now serialization with QDataStream works fine.