QtJsonSerializer
QtJsonSerializer copied to clipboard
How to deserialize derived classes that use none-default constructors
Hello there,
I was trying to deserialize some polymorphic classes which use none-default constructors by creating my own QJsonTypeConverter with the help of discussion about it in issue #22.
let's say we have class Base
and class Derived
.
I faced a problem with the canConvert()
function.
when I want to deserialize the Derived class canConvert()
is called with the metaTypeId
of Base *
instead of Derived *
.
Am I doing something wrong?
How can I solve that problem?
First, make sure to read the documentation about this library treats polymorphism: https://skycoder42.github.io/QtJsonSerializer/class_qt_json_serializer_1_1_serializer_base.html#a18d5fc879178e3d3ab9094de4f3277e2
As stated there, the serializer should add a special "@class" property that holds the actual type. This property is written and read/interpreted by the object serializer itself - this means if you have a custom serializer, you have to duplicate that behaviour.
Getting the can convert for the base class is correct, as from C++, you request the deserialization of a Base
object. Your serializer should be able to detect that it is actually a Derived
and do the serialization, as generally there is no guarantee that the object being deserialized is actually of the Derived
type. If you know that beforehand, you could just deserialize it as Derived
directly and don't need polymorphism.
I hope this helps you with your problem. If not, maybe post the code of your custom converter here, and I can take a look at it and give you some ideas on how to proceed.
I'm using version: 3.3.1-3
The serializer works fine with most of my polymorphic classes except the one I mentioned above.
I've used the Q_CLASSINFO("polymorphic", "true")
in the Base
class declaration.
Let's say we have the following code snippet.
Note: "..." means that the code in the QJsonObjectConverter is used without any changes.
class Base : public QObject
{
Q_OBJECT
Q_CLASSINFO("polymorphic", "true")
public:
Base(QObject *parent = nullptr) {}
}
class Derived : public Base
{
Q_OBJECT
public:
Q_INVOKABLE Derived(int a, QObject *parent = nullptr) : Base(parent) {}
}
class Derived2 : public Base
{
Q_OBJECT
public:
Q_INVOKABLE Derived2(int a, int b, QObject *parent = nullptr) : Base(parent) {}
}
First I need to do something to override the default object instantiation by adding a type converter. right? so I created two new type converter with the following codes:
class Q_JSONSERIALIZER_EXPORT QJsonCustomConverter : public QJsonTypeConverter
{
int m_number;
public:
QJsonCustomConverter(int n) : m_number(n) {}
bool canConvert(int metaTypeId) const override;
...
...
...
}
definition:
bool QJsonCustomConverter::canConvert(int metaTypeId) const
{
if (metaTypeId != QMetaType::type("Derived*"))
return false;
auto flags = QMetaType::typeFlags(metaTypeId);
return (flags.testFlag(QMetaType::PointerToQObject) ||
flags.testFlag(QMetaType::SharedPointerToQObject) ||//weak ptr cannot be constructed
flags.testFlag(QMetaType::TrackingPointerToQObject));
}
...
...
QVariant QJsonCustomConverter::deserialize(int propertyType, const QJsonValue &value, QObject *parent, const QJsonTypeConverter::SerializationHelper *helper) const
{
...
...
auto object = metaObject->newInstance(Q_ARG(int, m_number), Q_ARG(QObject*, parent));
if(!object) {
throw QJsonDeserializationException(QByteArray("Failed to construct object")
}
...
...
}
and for the second class:
class Q_JSONSERIALIZER_EXPORT QJsonCustomConverter2 : public QJsonTypeConverter
{
int m_number;
int m_number2;
public:
QJsonCustomConverter2(int n, int n2) : m_number(n), m_number2(n2) {}
bool canConvert(int metaTypeId) const override;
...
...
...
}
definition:
bool QJsonCustomConverter::canConvert(int metaTypeId) const
{
if (metaTypeId != QMetaType::type("Derived2*"))
return false;
auto flags = QMetaType::typeFlags(metaTypeId);
return (flags.testFlag(QMetaType::PointerToQObject) ||
flags.testFlag(QMetaType::SharedPointerToQObject) ||//weak ptr cannot be constructed
flags.testFlag(QMetaType::TrackingPointerToQObject));
}
...
...
QVariant QJsonCustomConverter::deserialize(int propertyType, const QJsonValue &value, QObject *parent, const QJsonTypeConverter::SerializationHelper *helper) const
{
...
...
auto object = metaObject->newInstance(Q_ARG(int, m_number), Q_ARG(int, m_number2), Q_ARG(QObject*, parent));
if(!object) {
throw QJsonDeserializationException(QByteArray("Failed to construct object")
}
...
...
}
I added those converters and faced the problem mentioned in the previous post in deserialization and none of the converters is used because the canConvert
function returns false.