From 0aec6119b0033aa0a67ad80c6c2658bc3f4e3285 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Mon, 29 Aug 2016 19:32:09 +0100 Subject: Add support for [de]serializing a dictionary as a json object --- slicer/json/serializer.cpp | 63 ++++++++++++++++++++++++++++---- slicer/json/serializer.h | 1 + slicer/test/initial/objectmap.json | 5 +++ slicer/test/initial/objectmapMember.json | 8 ++++ slicer/test/preprocessor.cpp | 2 +- slicer/test/serializers.cpp | 26 +++++++++++++ slicer/test/types.ice | 9 +++++ 7 files changed, 105 insertions(+), 9 deletions(-) create mode 100644 slicer/test/initial/objectmap.json create mode 100644 slicer/test/initial/objectmapMember.json diff --git a/slicer/json/serializer.cpp b/slicer/json/serializer.cpp index e50dd32..e6ddf81 100644 --- a/slicer/json/serializer.cpp +++ b/slicer/json/serializer.cpp @@ -1,4 +1,5 @@ #include "serializer.h" +#include #include #include #include @@ -16,6 +17,10 @@ NAMEDFACTORY("application/json", Slicer::JsonStreamSerializer, Slicer::StreamSer NAMEDFACTORY("application/json", Slicer::JsonStreamDeserializer, Slicer::StreamDeserializerFactory); namespace Slicer { + const std::string md_object = "json:object"; + const std::string keyName = "key"; + const std::string valueName = "value"; + class JsonValueSource : public ValueSource { public: JsonValueSource(const json::Value & s) : @@ -144,15 +149,30 @@ namespace Slicer { } } modelPart->Create(); - for (const auto & element : o) { - auto emp = modelPart->GetChild(element.first); - if (emp) { + if (metaDataFlagSet(modelPart->GetMetadata(), md_object)) { + for (const auto & element : o) { + auto emp = modelPart->GetAnonChild(); emp->Create(); - boost::apply_visitor(DocumentTreeIterate(emp), *element.second); + auto key = emp->GetChild(keyName); + auto value = emp->GetChild(valueName); + key->Create(); + key->SetValue(new JsonValueSource(element.first)); + key->Complete(); + boost::apply_visitor(DocumentTreeIterate(value), *element.second); emp->Complete(); } } - modelPart->Complete(); + else { + for (const auto & element : o) { + auto emp = modelPart->GetChild(element.first); + if (emp) { + emp->Create(); + boost::apply_visitor(DocumentTreeIterate(emp), *element.second); + emp->Complete(); + } + } + modelPart->Complete(); + } } void operator()(const json::Array & a) const { @@ -179,6 +199,20 @@ namespace Slicer { ModelTreeIterateRoot(arr->back().get(), mp); } + void + JsonSerializer::ModelTreeIterateDictObj(json::Value * n, ModelPartPtr mp) + { + auto obj = boost::get(n); + json::Object::key_type k; + auto v = json::ValuePtr(new json::Value()); + json::Value kv; + mp->GetChild(keyName)->GetValue(new JsonValueTarget(kv)); + JsonValueSource s(kv); + s.set(k); + ModelTreeIterateRoot(v.get(), mp->GetChild(valueName)); + obj->insert({ k, v }); + } + void JsonSerializer::ModelTreeIterate(json::Value * n, const std::string & name, ModelPartPtr mp) { @@ -206,9 +240,16 @@ namespace Slicer { break; } case mpt_Sequence: - case mpt_Dictionary: mp->OnEachChild(boost::bind(&JsonSerializer::ModelTreeIterateSeq, boost::get(*n).insert({name, json::ValuePtr(new json::Value(json::Array()))}).first->second.get(), _2)); break; + case mpt_Dictionary: + if (metaDataFlagSet(mp->GetMetadata(), md_object)) { + mp->OnEachChild(boost::bind(&JsonSerializer::ModelTreeIterateDictObj, boost::get(*n).insert({name, json::ValuePtr(new json::Value(json::Object()))}).first->second.get(), _2)); + } + else { + mp->OnEachChild(boost::bind(&JsonSerializer::ModelTreeIterateSeq, boost::get(*n).insert({name, json::ValuePtr(new json::Value(json::Array()))}).first->second.get(), _2)); + } + break; } } } @@ -239,8 +280,14 @@ namespace Slicer { mp->OnEachChild(boost::bind(&JsonSerializer::ModelTreeIterateSeq, n, _2)); break; case mpt_Dictionary: - *n = json::Array(); - mp->OnEachChild(boost::bind(&JsonSerializer::ModelTreeIterate, n, _1, _2)); + if (metaDataFlagSet(mp->GetMetadata(), md_object)) { + *n = json::Object(); + mp->OnEachChild(boost::bind(&JsonSerializer::ModelTreeIterateDictObj, n, _2)); + } + else { + *n = json::Array(); + mp->OnEachChild(boost::bind(&JsonSerializer::ModelTreeIterate, n, _1, _2)); + } break; } } diff --git a/slicer/json/serializer.h b/slicer/json/serializer.h index c7e0fc3..cb83d16 100644 --- a/slicer/json/serializer.h +++ b/slicer/json/serializer.h @@ -9,6 +9,7 @@ namespace Slicer { class JsonSerializer : public Serializer { protected: static void ModelTreeIterate(json::Value *, const std::string &, ModelPartPtr mp); + static void ModelTreeIterateDictObj(json::Value *, ModelPartPtr mp); static void ModelTreeIterateSeq(json::Value *, ModelPartPtr mp); static void ModelTreeIterateRoot(json::Value *, ModelPartPtr mp); }; diff --git a/slicer/test/initial/objectmap.json b/slicer/test/initial/objectmap.json new file mode 100644 index 0000000..c7e43ac --- /dev/null +++ b/slicer/test/initial/objectmap.json @@ -0,0 +1,5 @@ +{ + "one": 1, + "three hundred": 300, + "twenty": 20 +} diff --git a/slicer/test/initial/objectmapMember.json b/slicer/test/initial/objectmapMember.json new file mode 100644 index 0000000..c523899 --- /dev/null +++ b/slicer/test/initial/objectmapMember.json @@ -0,0 +1,8 @@ +{ + "name": "foo", + "props": { + "one": 1, + "three hundred": 300, + "twenty": 20 + } +} diff --git a/slicer/test/preprocessor.cpp b/slicer/test/preprocessor.cpp index 18fad39..cc67d64 100644 --- a/slicer/test/preprocessor.cpp +++ b/slicer/test/preprocessor.cpp @@ -13,7 +13,7 @@ namespace fs = boost::filesystem; -const unsigned int COMPONENTS_IN_TEST_ICE = 37; +const unsigned int COMPONENTS_IN_TEST_ICE = 39; BOOST_FIXTURE_TEST_SUITE ( preprocessor, FileStructure ); diff --git a/slicer/test/serializers.cpp b/slicer/test/serializers.cpp index d23bd2f..95e8e87 100644 --- a/slicer/test/serializers.cpp +++ b/slicer/test/serializers.cpp @@ -249,6 +249,22 @@ checkSomeNumbers(const TestModule::SomeNumbers & sn) BOOST_REQUIRE_EQUAL(sn, TestModule::FiftyFive); } +void +checkObjectMap(const TestJson::Properties & p) +{ + BOOST_REQUIRE_EQUAL(3, p.size()); + BOOST_REQUIRE_EQUAL(1, p.find("one")->second); + BOOST_REQUIRE_EQUAL(20, p.find("twenty")->second); + BOOST_REQUIRE_EQUAL(300, p.find("three hundred")->second); +} + +void +checkObjectMapMember(const TestJson::HasProperitiesPtr & p) +{ + BOOST_REQUIRE_EQUAL(p->name, "foo"); + checkObjectMap(p->props); +} + xmlpp::Document * readXml(const fs::path & path) { @@ -422,6 +438,16 @@ BOOST_AUTO_TEST_CASE( json_rootEnums_json ) verifyByFile("enum2.json", checkSomeNumbers); } +BOOST_AUTO_TEST_CASE( json_objectmap ) +{ + verifyByFile("objectmap.json", checkObjectMap); +} + +BOOST_AUTO_TEST_CASE( json_objectmapMember ) +{ + verifyByFile("objectmapMember.json", checkObjectMapMember); +} + BOOST_AUTO_TEST_CASE( json_streams ) { const auto tmpf = tmp / "byStream"; diff --git a/slicer/test/types.ice b/slicer/test/types.ice index b119df0..c2ac8f3 100644 --- a/slicer/test/types.ice +++ b/slicer/test/types.ice @@ -125,6 +125,15 @@ module TestModule { }; }; +module TestJson { + [ "slicer:json:object" ] + dictionary Properties; + class HasProperities { + string name; + Properties props; + }; +}; + module TestModule2 { class CrossModule extends TestModule::ClassType { int anything; -- cgit v1.2.3