refs #815 Throw CJsonException when required JSON objects are not found.

This commit is contained in:
Mathew Sutcliffe
2016-12-18 04:44:25 +00:00
parent 7c5c9d30e6
commit bbdbd26f82
10 changed files with 112 additions and 40 deletions

View File

@@ -122,13 +122,17 @@ namespace BlackMisc
void convertFromJson(const QJsonObject &json) void convertFromJson(const QJsonObject &json)
{ {
derived().clear(); derived().clear();
QJsonArray array = json.value("containerbase").toArray(); QJsonValue value = json.value("containerbase");
if (value.isUndefined()) { throw CJsonException("Missing 'containerbase'"); }
QJsonArray array = value.toArray();
int index = 0;
for (auto i = array.begin(); i != array.end(); ++i) for (auto i = array.begin(); i != array.end(); ++i)
{ {
CJsonScope scope("containerbase", index++);
QJsonValueRef ref = (*i); QJsonValueRef ref = (*i);
T value; T val;
ref >> value; ref >> val;
derived().insert(value); derived().insert(std::move(val));
} }
} }

View File

@@ -257,7 +257,10 @@ namespace BlackMisc
//! \copydoc BlackMisc::Mixin::JsonByMetaClass::convertFromJson //! \copydoc BlackMisc::Mixin::JsonByMetaClass::convertFromJson
void convertFromJson(const QJsonObject &json) void convertFromJson(const QJsonObject &json)
{ {
QJsonArray array = json.value("associativecontainerbase").toArray(); QJsonValue value = json.value("associativecontainerbase");
if (value.isUndefined()) { throw CJsonException("Missing 'associativecontainerbase'"); }
QJsonArray array = value.toArray();
int index = 0;
for (auto it = array.begin(); it != array.end(); ++it) for (auto it = array.begin(); it != array.end(); ++it)
{ {
QJsonValueRef jsonKey = (*it); QJsonValueRef jsonKey = (*it);
@@ -265,10 +268,16 @@ namespace BlackMisc
if (it == array.end()) { qWarning("Odd number of elements in CDictionary::convertFromJson"); return; } if (it == array.end()) { qWarning("Odd number of elements in CDictionary::convertFromJson"); return; }
QJsonValueRef jsonValue = (*it); QJsonValueRef jsonValue = (*it);
Key key; Key key;
Value value; Value val;
jsonKey >> key; {
jsonValue >> value; CJsonScope scope("associativecontainerbase", 2 * index);
m_impl.insert(key, value); jsonKey >> key;
}
{
CJsonScope scope("associativecontainerbase", 2 * index++ + 1);
jsonValue >> val;
}
m_impl.insert(std::move(key), std::move(val));
} }
} }

View File

@@ -16,6 +16,7 @@
#include "blackmisc/fileutils.h" #include "blackmisc/fileutils.h"
#include "blackmisc/inheritancetraits.h" #include "blackmisc/inheritancetraits.h"
#include "blackmisc/metaclass.h" #include "blackmisc/metaclass.h"
#include "blackmisc/jsonexception.h"
#include <QByteArray> #include <QByteArray>
#include <QJsonArray> #include <QJsonArray>
@@ -375,8 +376,17 @@ namespace BlackMisc
auto meta = introspect<Derived>().without(MetaFlags<DisabledForJson>()); auto meta = introspect<Derived>().without(MetaFlags<DisabledForJson>());
meta.forEachMemberName(*derived(), [ & ](auto & member, CExplicitLatin1String name) meta.forEachMemberName(*derived(), [ & ](auto & member, CExplicitLatin1String name)
{ {
auto it = json.find(name); const auto value = json.value(name);
if (it != json.end()) { it.value() >> member; } if (value.isUndefined())
{
constexpr bool required = false; // \todo add RequiredForJson flag in metaclass system
if (required) { throw CJsonException(QStringLiteral("Missing required member '%1'").arg(name.m_latin1)); }
}
else
{
CJsonScope scope(name.m_latin1);
value >> member;
}
}); });
} }

View File

@@ -194,8 +194,9 @@ namespace BlackMisc
void CUrl::convertFromJson(const QJsonObject &json) void CUrl::convertFromJson(const QJsonObject &json)
{ {
QString url(json.value("url").toString()); const QJsonValue value = json.value("url");
this->setFullUrl(url); if (value.isUndefined()) { throw CJsonException("Missing 'url'"); }
this->setFullUrl(value.toString());
} }
int CUrl::protocolToDefaultPort(const QString &protocol) int CUrl::protocolToDefaultPort(const QString &protocol)

View File

@@ -348,9 +348,13 @@ namespace BlackMisc
template <class MU, class PQ> template <class MU, class PQ>
void CPhysicalQuantity<MU, PQ>::convertFromJson(const QJsonObject &json) void CPhysicalQuantity<MU, PQ>::convertFromJson(const QJsonObject &json)
{ {
const QString unitSymbol = json.value("unit").toString(); const QJsonValue unit = json.value("unit");
this->setUnitBySymbol(unitSymbol); const QJsonValue value = json.value("value");
this->m_value = json.value("value").toDouble(); if (unit.isUndefined()) { throw CJsonException("Missing 'unit'"); }
if (value.isUndefined()) { throw CJsonException("Missing 'value'"); }
this->setUnitBySymbol(unit.toString());
this->m_value = value.toDouble();
} }
template <class MU, class PQ> template <class MU, class PQ>

View File

@@ -698,13 +698,34 @@ namespace BlackMisc
void CAircraftModelList::convertFromMemoizedJson(const QJsonObject &json) void CAircraftModelList::convertFromMemoizedJson(const QJsonObject &json)
{ {
clear(); clear();
QJsonArray array = json.value("containerbase").toArray(); QJsonValue value = json.value("containerbase");
if (value.isUndefined()) { throw CJsonException("Missing 'containerbase'"); }
QJsonArray array = value.toArray();
CAircraftModel::MemoHelper::CUnmemoizer helper; CAircraftModel::MemoHelper::CUnmemoizer helper;
helper.getTable<CAircraftIcaoCode>().convertFromJson(json.value("aircraftIcaos").toObject()); QJsonValue aircraftIcaos = json.value("aircraftIcaos");
helper.getTable<CLivery>().convertFromJson(json.value("liveries").toObject()); QJsonValue liveries = json.value("liveries");
helper.getTable<CDistributor>().convertFromJson(json.value("distributors").toObject()); QJsonValue distributors = json.value("distributors");
if (aircraftIcaos.isUndefined()) { throw CJsonException("Missing 'aircraftIcaos'"); }
if (liveries.isUndefined()) { throw CJsonException("Missing 'liveries'"); }
if (distributors.isUndefined()) { throw CJsonException("Missing 'distributors'"); }
{
CJsonScope scope("aircraftIcaos");
helper.getTable<CAircraftIcaoCode>().convertFromJson(aircraftIcaos.toObject());
}
{
CJsonScope scope("liveries");
helper.getTable<CLivery>().convertFromJson(liveries.toObject());
}
{
CJsonScope scope("distributors");
helper.getTable<CDistributor>().convertFromJson(distributors.toObject());
}
int index = 0;
for (auto i = array.begin(); i != array.end(); ++i) for (auto i = array.begin(); i != array.end(); ++i)
{ {
CJsonScope scope("containerbase", index++);
CAircraftModel value; CAircraftModel value;
value.convertFromMemoizedJson(i->toObject(), helper); value.convertFromMemoizedJson(i->toObject(), helper);
insert(value); insert(value);

View File

@@ -27,7 +27,10 @@ namespace BlackMisc
{ {
if (json.contains("IID")) // comes from the plugin if (json.contains("IID")) // comes from the plugin
{ {
if (! json.contains("MetaData")) { throw CJsonException("Missing 'MetaData'"); }
// json data is already validated by CPluginManagerSimulator // json data is already validated by CPluginManagerSimulator
CJsonScope scope("MetaData");
CValueObject::convertFromJson(json["MetaData"].toObject()); CValueObject::convertFromJson(json["MetaData"].toObject());
m_valid = true; m_valid = true;
} }

View File

@@ -156,38 +156,43 @@ namespace BlackMisc
{ {
// Remark: Names "type" and "value" are also used for drag and drop // Remark: Names "type" and "value" are also used for drag and drop
// Changing the names here requires the change for drag and drop too // Changing the names here requires the change for drag and drop too
QString typeName = json.value("type").toString(); QJsonValue typeValue = json.value("type");
if (typeValue.isUndefined()) { throw CJsonException("Missing 'type'"); }
QString typeName = typeValue.toString();
if (typeName.isEmpty()) { m_v.clear(); return; } if (typeName.isEmpty()) { m_v.clear(); return; }
int typeId = QMetaType::type(qPrintable(typeName)); int typeId = QMetaType::type(qPrintable(typeName));
QJsonValue value = json.value("value");
if (value.isUndefined() && typeId != QVariant::Invalid) { throw CJsonException("Missing 'value'"); }
switch (typeId) switch (typeId)
{ {
case QVariant::Invalid: CLogMessage(this).warning("Invalid type for fromJson: %1") << typeName; m_v.clear(); break; case QVariant::Invalid: CLogMessage(this).warning("Invalid type for fromJson: %1") << typeName; m_v.clear(); break;
case QVariant::Int: m_v.setValue(json.value("value").toInt()); break; case QVariant::Int: m_v.setValue(value.toInt()); break;
case QVariant::UInt: m_v.setValue<uint>(json.value("value").toInt()); break; case QVariant::UInt: m_v.setValue<uint>(value.toInt()); break;
case QVariant::Bool: m_v.setValue(json.value("value").toBool()); break; case QVariant::Bool: m_v.setValue(value.toBool()); break;
case QVariant::Double: m_v.setValue(json.value("value").toDouble()); break; case QVariant::Double: m_v.setValue(value.toDouble()); break;
case QVariant::LongLong: m_v.setValue<qlonglong>(json.value("value").toInt()); break; // QJsonValue has no toLongLong() method??? case QVariant::LongLong: m_v.setValue<qlonglong>(value.toInt()); break; // QJsonValue has no toLongLong() method???
case QVariant::ULongLong: m_v.setValue<qulonglong>(json.value("value").toInt()); break; case QVariant::ULongLong: m_v.setValue<qulonglong>(value.toInt()); break;
case QVariant::String: m_v.setValue(json.value("value").toString()); break; case QVariant::String: m_v.setValue(value.toString()); break;
case QVariant::Char: m_v.setValue(json.value("value").toString().size() > 0 ? json.value("value").toString().at(0) : '\0'); break; case QVariant::Char: m_v.setValue(value.toString().size() > 0 ? value.toString().at(0) : '\0'); break;
case QVariant::ByteArray: m_v.setValue(json.value("value").toString().toLatin1()); break; case QVariant::ByteArray: m_v.setValue(value.toString().toLatin1()); break;
case QVariant::DateTime: m_v.setValue(QDateTime::fromString(json.value("value").toString(), Qt::ISODate)); break; case QVariant::DateTime: m_v.setValue(QDateTime::fromString(value.toString(), Qt::ISODate)); break;
case QVariant::Date: m_v.setValue(QDate::fromString(json.value("value").toString(), Qt::ISODate)); break; case QVariant::Date: m_v.setValue(QDate::fromString(value.toString(), Qt::ISODate)); break;
case QVariant::Time: m_v.setValue(QTime::fromString(json.value("value").toString(), Qt::ISODate)); break; case QVariant::Time: m_v.setValue(QTime::fromString(value.toString(), Qt::ISODate)); break;
case QVariant::StringList: m_v.setValue(QVariant(json.value("value").toArray().toVariantList()).toStringList()); break; case QVariant::StringList: m_v.setValue(QVariant(value.toArray().toVariantList()).toStringList()); break;
default: default:
try try
{ {
auto *meta = Private::getValueObjectMetaInfo(typeId); auto *meta = Private::getValueObjectMetaInfo(typeId);
if (meta) if (meta)
{ {
CJsonScope scope("value");
m_v = QVariant(typeId, nullptr); m_v = QVariant(typeId, nullptr);
meta->convertFromJson(json.value("value").toObject(), data()); meta->convertFromJson(value.toObject(), data());
} }
else if (QMetaType::hasRegisteredConverterFunction(qMetaTypeId<QString>(), typeId)) else if (QMetaType::hasRegisteredConverterFunction(qMetaTypeId<QString>(), typeId))
{ {
m_v.setValue(json.value("value").toString()); m_v.setValue(value.toString());
if (! m_v.convert(typeId)) if (! m_v.convert(typeId))
{ {
CLogMessage(this).warning("Failed to convert from JSON string"); CLogMessage(this).warning("Failed to convert from JSON string");
@@ -231,15 +236,21 @@ namespace BlackMisc
void CVariant::convertFromMemoizedJson(const QJsonObject &json) void CVariant::convertFromMemoizedJson(const QJsonObject &json)
{ {
QString typeName = json.value("type").toString(); QJsonValue typeValue = json.value("type");
if (typeValue.isUndefined()) { throw CJsonException("Missing 'type'"); }
QString typeName = typeValue.toString();
if (typeName.isEmpty()) { m_v.clear(); return; } if (typeName.isEmpty()) { m_v.clear(); return; }
int typeId = QMetaType::type(qPrintable(typeName)); int typeId = QMetaType::type(qPrintable(typeName));
auto *meta = Private::getValueObjectMetaInfo(typeId); auto *meta = Private::getValueObjectMetaInfo(typeId);
if (meta) if (meta)
{ {
QJsonValue value = json.value("value");
if (value.isUndefined()) { throw CJsonException("Missing 'value'"); }
CJsonScope scope("value");
m_v = QVariant(typeId, nullptr); m_v = QVariant(typeId, nullptr);
meta->convertFromMemoizedJson(json.value("value").toObject(), data()); meta->convertFromMemoizedJson(value.toObject(), data());
} }
else else
{ {

View File

@@ -35,9 +35,11 @@ namespace BlackMisc
clear(); clear();
for (auto it = json.begin(); it != json.end(); ++it) for (auto it = json.begin(); it != json.end(); ++it)
{ {
const QString key = it.key();
CJsonScope scope(key);
CVariant value; CVariant value;
value.convertFromJson(it.value().toObject()); value.convertFromJson(it.value().toObject());
implementationOf(*this).insert(cend(), it.key(), value); implementationOf(*this).insert(cend(), key, value);
} }
} }
@@ -48,6 +50,7 @@ namespace BlackMisc
{ {
auto value = json.value(key); auto value = json.value(key);
if (value.isUndefined()) { continue; } if (value.isUndefined()) { continue; }
CJsonScope scope(key);
CVariant var; CVariant var;
var.convertFromJson(value.toObject()); var.convertFromJson(value.toObject());
insert(key, var); insert(key, var);
@@ -75,9 +78,11 @@ namespace BlackMisc
clear(); clear();
for (auto it = json.begin(); it != json.end(); ++it) for (auto it = json.begin(); it != json.end(); ++it)
{ {
const QString key = it.key();
CJsonScope scope(key);
CVariant value; CVariant value;
value.convertFromMemoizedJson(it.value().toObject()); value.convertFromMemoizedJson(it.value().toObject());
implementationOf(*this).insert(cend(), it.key(), value); implementationOf(*this).insert(cend(), key, value);
} }
} }
@@ -88,6 +93,7 @@ namespace BlackMisc
{ {
auto value = json.value(key); auto value = json.value(key);
if (value.isUndefined()) { continue; } if (value.isUndefined()) { continue; }
CJsonScope scope(key);
CVariant var; CVariant var;
var.convertFromMemoizedJson(value.toObject()); var.convertFromMemoizedJson(value.toObject());
insert(key, var); insert(key, var);

View File

@@ -26,7 +26,10 @@ namespace BlackMisc
{ {
if (json.contains("IID")) // comes from the plugin if (json.contains("IID")) // comes from the plugin
{ {
if (! json.contains("MetaData")) { throw CJsonException("Missing 'MetaData'"); }
// json data is already validated by CPluginManagerWeatherData // json data is already validated by CPluginManagerWeatherData
CJsonScope scope("MetaData");
CValueObject::convertFromJson(json["MetaData"].toObject()); CValueObject::convertFromJson(json["MetaData"].toObject());
m_valid = true; m_valid = true;
} }