mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-09 13:12:40 +02:00
Tests working for reading JSON.
This commit is contained in:
parent
77b6a209ab
commit
37c977af02
4 changed files with 260 additions and 41 deletions
|
@ -1178,7 +1178,9 @@ Bitstream& Bitstream::operator>(ObjectStreamerPointer& streamer) {
|
|||
}
|
||||
for (int i = 0; i < localProperties.size(); i++) {
|
||||
const StreamerPropertyPair& property = properties.at(i);
|
||||
if (localProperties.at(i).first != property.first || property.second.propertyIndex() != i) {
|
||||
const StreamerPropertyPair& localProperty = localProperties.at(i);
|
||||
if (property.first != localProperty.first ||
|
||||
property.second.propertyIndex() != localProperty.second.propertyIndex()) {
|
||||
streamer = ObjectStreamerPointer(new MappedObjectStreamer(metaObject, properties));
|
||||
return *this;
|
||||
}
|
||||
|
@ -1866,7 +1868,6 @@ void JSONWriter::addSharedObject(const SharedObjectPointer& object) {
|
|||
|
||||
QJsonObject sharedObject;
|
||||
sharedObject.insert("id", object->getID());
|
||||
sharedObject.insert("originID", object->getOriginID());
|
||||
sharedObject.insert("data", getData(static_cast<const QObject*>(object.data())));
|
||||
_sharedObjects.replace(index, sharedObject);
|
||||
}
|
||||
|
@ -1887,17 +1888,121 @@ JSONReader::JSONReader(const QJsonDocument& document, Bitstream::GenericsMode ge
|
|||
for (int i = types.size() - 1; i >= 0; i--) {
|
||||
QJsonObject type = types.at(i).toObject();
|
||||
QString name = type.value("name").toString();
|
||||
QByteArray latinName = name.toLatin1();
|
||||
const TypeStreamer* baseStreamer = Bitstream::getTypeStreamers().value(QMetaType::type(latinName));
|
||||
if (!baseStreamer) {
|
||||
baseStreamer = Bitstream::getEnumStreamersByName().value(latinName);
|
||||
}
|
||||
if (!baseStreamer && genericsMode == Bitstream::NO_GENERICS) {
|
||||
continue;
|
||||
}
|
||||
QString category = type.value("category").toString();
|
||||
if (!baseStreamer || genericsMode == Bitstream::ALL_GENERICS) {
|
||||
TypeStreamerPointer streamer;
|
||||
if (category == "ENUM") {
|
||||
QVector<NameIntPair> values;
|
||||
int highestValue = 0;
|
||||
foreach (const QJsonValue& value, type.value("values").toArray()) {
|
||||
QJsonObject object = value.toObject();
|
||||
int value = object.value("value").toInt();
|
||||
highestValue = qMax(value, highestValue);
|
||||
values.append(NameIntPair(object.value("key").toString().toLatin1(), value));
|
||||
}
|
||||
streamer = TypeStreamerPointer(new GenericEnumTypeStreamer(latinName,
|
||||
values, getBitsForHighestValue(highestValue), QByteArray()));
|
||||
|
||||
} else if (category == "STREAMABLE") {
|
||||
QVector<StreamerNamePair> fields;
|
||||
foreach (const QJsonValue& field, type.value("fields").toArray()) {
|
||||
QJsonObject object = field.toObject();
|
||||
fields.append(StreamerNamePair(getTypeStreamer(object.value("type").toString()),
|
||||
object.value("name").toString().toLatin1()));
|
||||
}
|
||||
streamer = TypeStreamerPointer(new GenericStreamableTypeStreamer(latinName,
|
||||
fields, QByteArray()));
|
||||
|
||||
} else if (category == "LIST") {
|
||||
streamer = TypeStreamerPointer(new GenericListTypeStreamer(latinName,
|
||||
getTypeStreamer(type.value("valueType").toString())));
|
||||
|
||||
} else if (category == "SET") {
|
||||
streamer = TypeStreamerPointer(new GenericSetTypeStreamer(latinName,
|
||||
getTypeStreamer(type.value("valueType").toString())));
|
||||
|
||||
} else if (category == "MAP") {
|
||||
streamer = TypeStreamerPointer(new GenericMapTypeStreamer(latinName,
|
||||
getTypeStreamer(type.value("keyType").toString()),
|
||||
getTypeStreamer(type.value("valueType").toString())));
|
||||
}
|
||||
_typeStreamers.insert(name, streamer);
|
||||
static_cast<GenericTypeStreamer*>(streamer.data())->_weakSelf = streamer;
|
||||
continue;
|
||||
}
|
||||
if (category == "ENUM") {
|
||||
|
||||
QHash<int, int> mappings;
|
||||
int highestValue = 0;
|
||||
QMetaEnum metaEnum = baseStreamer->getMetaEnum();
|
||||
QJsonArray array = type.value("values").toArray();
|
||||
bool matches = (array.size() == metaEnum.keyCount());
|
||||
foreach (const QJsonValue& value, array) {
|
||||
QJsonObject object = value.toObject();
|
||||
int value = object.value("value").toInt();
|
||||
highestValue = qMax(value, highestValue);
|
||||
int mapping = metaEnum.keyToValue(object.value("key").toString().toLatin1());
|
||||
if (mapping != -1) {
|
||||
mappings.insert(value, mapping);
|
||||
}
|
||||
matches &= (value == mapping);
|
||||
}
|
||||
if (matches) {
|
||||
_typeStreamers.insert(name, baseStreamer->getSelf());
|
||||
} else {
|
||||
_typeStreamers.insert(name, TypeStreamerPointer(new MappedEnumTypeStreamer(baseStreamer,
|
||||
getBitsForHighestValue(highestValue), mappings)));
|
||||
}
|
||||
} else if (category == "STREAMABLE") {
|
||||
|
||||
QVector<StreamerIndexPair> fields;
|
||||
QJsonArray array = type.value("fields").toArray();
|
||||
const QVector<MetaField>& metaFields = baseStreamer->getMetaFields();
|
||||
bool matches = (array.size() == metaFields.size());
|
||||
for (int j = 0; j < array.size(); j++) {
|
||||
QJsonObject object = array.at(j).toObject();
|
||||
TypeStreamerPointer streamer = getTypeStreamer(object.value("type").toString());
|
||||
int index = baseStreamer->getFieldIndex(object.value("name").toString().toLatin1());
|
||||
fields.append(StreamerIndexPair(streamer, index));
|
||||
matches &= (index == j && streamer == metaFields.at(j).getStreamer());
|
||||
}
|
||||
if (matches) {
|
||||
_typeStreamers.insert(name, baseStreamer->getSelf());
|
||||
} else {
|
||||
_typeStreamers.insert(name, TypeStreamerPointer(new MappedStreamableTypeStreamer(baseStreamer, fields)));
|
||||
}
|
||||
} else if (category == "LIST") {
|
||||
|
||||
TypeStreamerPointer valueStreamer = getTypeStreamer(type.value("valueType").toString());
|
||||
if (valueStreamer == baseStreamer->getValueStreamer()) {
|
||||
_typeStreamers.insert(name, baseStreamer->getSelf());
|
||||
|
||||
} else {
|
||||
_typeStreamers.insert(name, TypeStreamerPointer(new MappedListTypeStreamer(baseStreamer, valueStreamer)));
|
||||
}
|
||||
} else if (category == "SET") {
|
||||
|
||||
TypeStreamerPointer valueStreamer = getTypeStreamer(type.value("valueType").toString());
|
||||
if (valueStreamer == baseStreamer->getValueStreamer()) {
|
||||
_typeStreamers.insert(name, baseStreamer->getSelf());
|
||||
|
||||
} else {
|
||||
_typeStreamers.insert(name, TypeStreamerPointer(new MappedSetTypeStreamer(baseStreamer, valueStreamer)));
|
||||
}
|
||||
} else if (category == "MAP") {
|
||||
|
||||
TypeStreamerPointer keyStreamer = getTypeStreamer(type.value("keyType").toString());
|
||||
TypeStreamerPointer valueStreamer = getTypeStreamer(type.value("valueType").toString());
|
||||
if (keyStreamer == baseStreamer->getKeyStreamer() && valueStreamer == baseStreamer->getValueStreamer()) {
|
||||
_typeStreamers.insert(name, baseStreamer->getSelf());
|
||||
|
||||
} else {
|
||||
_typeStreamers.insert(name, TypeStreamerPointer(new MappedMapTypeStreamer(
|
||||
baseStreamer, keyStreamer, valueStreamer)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1905,11 +2010,45 @@ JSONReader::JSONReader(const QJsonDocument& document, Bitstream::GenericsMode ge
|
|||
for (int i = classes.size() - 1; i >= 0; i--) {
|
||||
QJsonObject clazz = classes.at(i).toObject();
|
||||
QString name = clazz.value("name").toString();
|
||||
QJsonArray properties = clazz.value("properties").toArray();
|
||||
foreach (const QJsonValue& property, properties) {
|
||||
QJsonObject object = property.toObject();
|
||||
object.value("type");
|
||||
object.value("name");
|
||||
QByteArray latinName = name.toLatin1();
|
||||
const ObjectStreamer* baseStreamer = Bitstream::getObjectStreamers().value(
|
||||
Bitstream::getMetaObjects().value(latinName));
|
||||
if (!baseStreamer && genericsMode == Bitstream::NO_GENERICS) {
|
||||
continue;
|
||||
}
|
||||
if (!baseStreamer || genericsMode == Bitstream::ALL_GENERICS) {
|
||||
QVector<StreamerNamePair> properties;
|
||||
foreach (const QJsonValue& property, clazz.value("properties").toArray()) {
|
||||
QJsonObject object = property.toObject();
|
||||
properties.append(StreamerNamePair(getTypeStreamer(object.value("type").toString()),
|
||||
object.value("name").toString().toLatin1()));
|
||||
}
|
||||
ObjectStreamerPointer streamer = ObjectStreamerPointer(new GenericObjectStreamer(
|
||||
latinName, properties, QByteArray()));
|
||||
_objectStreamers.insert(name, streamer);
|
||||
static_cast<GenericObjectStreamer*>(streamer.data())->_weakSelf = streamer;
|
||||
continue;
|
||||
}
|
||||
const QMetaObject* metaObject = baseStreamer->getMetaObject();
|
||||
const QVector<StreamerPropertyPair>& baseProperties = baseStreamer->getProperties();
|
||||
QVector<StreamerPropertyPair> properties;
|
||||
QJsonArray propertyArray = clazz.value("properties").toArray();
|
||||
bool matches = (baseProperties.size() == propertyArray.size());
|
||||
for (int j = 0; j < propertyArray.size(); j++) {
|
||||
QJsonObject object = propertyArray.at(j).toObject();
|
||||
TypeStreamerPointer typeStreamer = getTypeStreamer(object.value("type").toString());
|
||||
QMetaProperty metaProperty = metaObject->property(metaObject->indexOfProperty(
|
||||
object.value("name").toString().toLatin1()));
|
||||
properties.append(StreamerPropertyPair(typeStreamer, metaProperty));
|
||||
|
||||
const StreamerPropertyPair& baseProperty = baseProperties.at(i);
|
||||
matches &= (typeStreamer == baseProperty.first &&
|
||||
metaProperty.propertyIndex() == baseProperty.second.propertyIndex());
|
||||
}
|
||||
if (matches) {
|
||||
_objectStreamers.insert(name, baseStreamer->getSelf());
|
||||
} else {
|
||||
_objectStreamers.insert(name, ObjectStreamerPointer(new MappedObjectStreamer(metaObject, properties)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1917,9 +2056,11 @@ JSONReader::JSONReader(const QJsonDocument& document, Bitstream::GenericsMode ge
|
|||
for (int i = objects.size() - 1; i >= 0; i--) {
|
||||
QJsonObject object = objects.at(i).toObject();
|
||||
int id = object.value("id").toInt();
|
||||
int originID = object.value("originID").toInt();
|
||||
QJsonObject data = object.value("data").toObject();
|
||||
|
||||
QObject* qObject;
|
||||
putData(object.value("data"), qObject);
|
||||
if (qObject) {
|
||||
_sharedObjects.insert(id, static_cast<SharedObject*>(qObject));
|
||||
}
|
||||
}
|
||||
|
||||
_contents = top.value("contents").toArray();
|
||||
|
@ -2051,16 +2192,12 @@ void JSONReader::putData(const QJsonValue& data, const QMetaObject*& value) {
|
|||
void JSONReader::putData(const QJsonValue& data, QVariant& value) {
|
||||
QJsonObject object = data.toObject();
|
||||
QString type = object.value("type").toString();
|
||||
const TypeStreamer* streamer = _typeStreamers.value(type).data();
|
||||
if (!streamer) {
|
||||
streamer = Bitstream::getTypeStreamers().value(QMetaType::type(type.toLatin1()));
|
||||
if (!streamer) {
|
||||
qWarning() << "Unknown type:" << type;
|
||||
value = QVariant();
|
||||
return;
|
||||
}
|
||||
TypeStreamerPointer streamer = getTypeStreamer(type);
|
||||
if (streamer) {
|
||||
streamer->putJSONVariantData(*this, object.value("value"), value);
|
||||
} else {
|
||||
value = QVariant();
|
||||
}
|
||||
streamer->putJSONData(*this, object.value("value"), value);
|
||||
}
|
||||
|
||||
void JSONReader::putData(const QJsonValue& data, SharedObjectPointer& value) {
|
||||
|
@ -2073,6 +2210,19 @@ void JSONReader::putData(const QJsonValue& data, QObject*& value) {
|
|||
value = streamer ? streamer->putJSONData(*this, object) : NULL;
|
||||
}
|
||||
|
||||
TypeStreamerPointer JSONReader::getTypeStreamer(const QString& name) const {
|
||||
TypeStreamerPointer streamer = _typeStreamers.value(name);
|
||||
if (!streamer) {
|
||||
const TypeStreamer* defaultStreamer = Bitstream::getTypeStreamers().value(QMetaType::type(name.toLatin1()));
|
||||
if (defaultStreamer) {
|
||||
streamer = defaultStreamer->getSelf();
|
||||
} else {
|
||||
qWarning() << "Unknown type:" << name;
|
||||
}
|
||||
}
|
||||
return streamer;
|
||||
}
|
||||
|
||||
ObjectStreamer::ObjectStreamer(const QMetaObject* metaObject) :
|
||||
_metaObject(metaObject) {
|
||||
}
|
||||
|
@ -2438,6 +2588,10 @@ void TypeStreamer::putJSONData(JSONReader& reader, const QJsonValue& data, QVari
|
|||
value = QVariant();
|
||||
}
|
||||
|
||||
void TypeStreamer::putJSONVariantData(JSONReader& reader, const QJsonValue& data, QVariant& value) const {
|
||||
putJSONData(reader, data, value);
|
||||
}
|
||||
|
||||
bool TypeStreamer::equal(const QVariant& first, const QVariant& second) const {
|
||||
return first == second;
|
||||
}
|
||||
|
@ -2750,6 +2904,12 @@ const char* GenericTypeStreamer::getName() const {
|
|||
return _name.constData();
|
||||
}
|
||||
|
||||
void GenericTypeStreamer::putJSONVariantData(JSONReader& reader, const QJsonValue& data, QVariant& value) const {
|
||||
QVariant containedValue;
|
||||
putJSONData(reader, data, containedValue);
|
||||
value = QVariant::fromValue(GenericValue(_weakSelf, containedValue));
|
||||
}
|
||||
|
||||
QVariant GenericTypeStreamer::readVariant(Bitstream& in) const {
|
||||
return QVariant::fromValue(GenericValue(_weakSelf, read(in)));
|
||||
}
|
||||
|
|
|
@ -893,7 +893,7 @@ public:
|
|||
|
||||
template<class T> JSONReader& operator>>(T& value) { putData(*_contentsIterator++, value); return *this; }
|
||||
|
||||
TypeStreamerPointer getTypeStreamer(const QString& name) const { return _typeStreamers.value(name); }
|
||||
TypeStreamerPointer getTypeStreamer(const QString& name) const;
|
||||
ObjectStreamerPointer getObjectStreamer(const QString& name) const { return _objectStreamers.value(name); }
|
||||
SharedObjectPointer getSharedObject(int id) const { return _sharedObjects.value(id); }
|
||||
|
||||
|
@ -1020,6 +1020,7 @@ public:
|
|||
private:
|
||||
|
||||
friend class Bitstream;
|
||||
friend class JSONReader;
|
||||
|
||||
QByteArray _name;
|
||||
WeakObjectStreamerPointer _weakSelf;
|
||||
|
@ -1107,6 +1108,7 @@ public:
|
|||
virtual QJsonValue getJSONData(JSONWriter& writer, const QVariant& value) const;
|
||||
virtual QJsonValue getJSONVariantData(JSONWriter& writer, const QVariant& value) const;
|
||||
virtual void putJSONData(JSONReader& reader, const QJsonValue& data, QVariant& value) const;
|
||||
virtual void putJSONVariantData(JSONReader& reader, const QJsonValue& data, QVariant& value) const;
|
||||
|
||||
virtual bool equal(const QVariant& first, const QVariant& second) const;
|
||||
|
||||
|
@ -1237,11 +1239,13 @@ public:
|
|||
GenericTypeStreamer(const QByteArray& name);
|
||||
|
||||
virtual const char* getName() const;
|
||||
virtual void putJSONVariantData(JSONReader& reader, const QJsonValue& data, QVariant& value) const;
|
||||
virtual QVariant readVariant(Bitstream& in) const;
|
||||
|
||||
protected:
|
||||
|
||||
friend class Bitstream;
|
||||
friend class JSONReader;
|
||||
|
||||
QByteArray _name;
|
||||
WeakTypeStreamerPointer _weakSelf;
|
||||
|
|
|
@ -252,8 +252,64 @@ static bool testSerialization(Bitstream::MetadataType metadataType) {
|
|||
jsonWriter << testObjectReadA;
|
||||
jsonWriter << testObjectReadB;
|
||||
jsonWriter << messageRead;
|
||||
qDebug() << jsonWriter.getDocument().toJson();
|
||||
qDebug();
|
||||
jsonWriter << endRead;
|
||||
QByteArray encodedJson = jsonWriter.getDocument().toJson();
|
||||
|
||||
// and read from JSON
|
||||
JSONReader jsonReader(QJsonDocument::fromJson(encodedJson), Bitstream::ALL_GENERICS);
|
||||
jsonReader >> testObjectReadA;
|
||||
jsonReader >> testObjectReadB;
|
||||
jsonReader >> messageRead;
|
||||
jsonReader >> endRead;
|
||||
|
||||
// reassign the ids
|
||||
testObjectReadA->setID(testObjectWrittenA->getID());
|
||||
testObjectReadA->setOriginID(testObjectWrittenA->getOriginID());
|
||||
testObjectReadB->setID(testObjectWrittenB->getID());
|
||||
testObjectReadB->setOriginID(testObjectWrittenB->getOriginID());
|
||||
|
||||
// and back to binary
|
||||
QByteArray secondCompareArray;
|
||||
QDataStream secondCompareOutStream(&secondCompareArray, QIODevice::WriteOnly);
|
||||
Bitstream secondCompareOut(secondCompareOutStream, Bitstream::FULL_METADATA);
|
||||
secondCompareOut << testObjectReadA;
|
||||
secondCompareOut << testObjectReadB;
|
||||
secondCompareOut << messageRead;
|
||||
secondCompareOut << endRead;
|
||||
secondCompareOut.flush();
|
||||
|
||||
if (compareArray != secondCompareArray) {
|
||||
qDebug() << "Mismatch between written/JSON streams (generics).";
|
||||
return true;
|
||||
}
|
||||
|
||||
// once more, with mapping!
|
||||
JSONReader secondJSONReader(QJsonDocument::fromJson(encodedJson));
|
||||
secondJSONReader >> testObjectReadA;
|
||||
secondJSONReader >> testObjectReadB;
|
||||
secondJSONReader >> messageRead;
|
||||
secondJSONReader >> endRead;
|
||||
|
||||
// reassign the ids
|
||||
testObjectReadA->setID(testObjectWrittenA->getID());
|
||||
testObjectReadA->setOriginID(testObjectWrittenA->getOriginID());
|
||||
testObjectReadB->setID(testObjectWrittenB->getID());
|
||||
testObjectReadB->setOriginID(testObjectWrittenB->getOriginID());
|
||||
|
||||
// and back to binary
|
||||
QByteArray thirdCompareArray;
|
||||
QDataStream thirdCompareOutStream(&thirdCompareArray, QIODevice::WriteOnly);
|
||||
Bitstream thirdCompareOut(thirdCompareOutStream, Bitstream::FULL_METADATA);
|
||||
thirdCompareOut << testObjectReadA;
|
||||
thirdCompareOut << testObjectReadB;
|
||||
thirdCompareOut << messageRead;
|
||||
thirdCompareOut << endRead;
|
||||
thirdCompareOut.flush();
|
||||
|
||||
if (compareArray != thirdCompareArray) {
|
||||
qDebug() << "Mismatch between written/JSON streams (mapped).";
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -123,11 +123,6 @@ void generateOutput (QTextStream& out, const QList<Streamable>& streamables) {
|
|||
out << "QHash<QByteArray, int> " << name << "::createFieldIndices() {\n";
|
||||
out << " QHash<QByteArray, int> indices;\n";
|
||||
out << " int index = 1;\n";
|
||||
foreach (const QString& base, str.clazz.bases) {
|
||||
out << " foreach (const MetaField& field, " << base << "::getMetaFields()) {\n";
|
||||
out << " indices.insert(field.getName(), index++);\n";
|
||||
out << " }\n";
|
||||
}
|
||||
out << " foreach (const MetaField& field, getMetaFields()) {\n";
|
||||
out << " indices.insert(field.getName(), index++);\n";
|
||||
out << " }\n";
|
||||
|
@ -231,15 +226,19 @@ void generateOutput (QTextStream& out, const QList<Streamable>& streamables) {
|
|||
out << "}\n";
|
||||
|
||||
out << "template<> void JSONReader::putData(const QJsonValue& data, " << name << "& value) {\n";
|
||||
out << " QJsonArray array = data.toArray();\n";
|
||||
out << " QJsonArray::const_iterator it = array.constBegin();\n";
|
||||
/* foreach (const QString& base, str.clazz.bases) {
|
||||
out << " foreach (const QJsonValue& element, getData(static_cast<const " << base << "&>(value)).toArray()) {\n";
|
||||
out << " array.append(element);\n";
|
||||
out << " }\n";
|
||||
} */
|
||||
foreach (const Field& field, str.fields) {
|
||||
out << " putData(*it++, value." << field.name << ");\n";
|
||||
if (!(str.clazz.bases.isEmpty() && str.fields.isEmpty())) {
|
||||
out << " QJsonArray array = data.toArray(), subarray;\n";
|
||||
out << " QJsonArray::const_iterator it = array.constBegin();\n";
|
||||
foreach (const QString& base, str.clazz.bases) {
|
||||
out << " subarray = QJsonArray();\n";
|
||||
out << " for (int i = 0; i < " << base << "::getMetaFields().size(); i++) {\n";
|
||||
out << " subarray.append(*it++);\n";
|
||||
out << " }\n";
|
||||
out << " putData(subarray, static_cast<" << base << "&>(value));\n";
|
||||
}
|
||||
foreach (const Field& field, str.fields) {
|
||||
out << " putData(*it++, value." << field.name << ");\n";
|
||||
}
|
||||
}
|
||||
out << "}\n";
|
||||
|
||||
|
|
Loading…
Reference in a new issue