From 336b1f9ca5cbb96027c768c3109c6aacafa6e1af Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Tue, 19 Jan 2016 22:19:23 +0000 Subject: Add support for json/xml stream serializers and support for serializer factories based on mime types and file extensions --- slicer/json/Jamfile.jam | 20 +++++++++++++++++++- slicer/json/serializer.cpp | 35 +++++++++++++++++++++++++++++++++++ slicer/json/serializer.h | 20 ++++++++++++++++++++ slicer/json/testSpecifics.cpp | 18 ++++++++++++++++++ slicer/slicer/serializer.cpp | 10 ++++++++++ slicer/slicer/serializer.h | 11 +++++++++-- slicer/slicer/slicer.h | 28 ++++++++++++++++++++++++---- slicer/test/serializers.cpp | 38 ++++++++++++++++++++++++++++++++++++++ slicer/xml/serializer.cpp | 32 ++++++++++++++++++++++++++++++++ slicer/xml/serializer.h | 20 ++++++++++++++++++++ slicer/xml/testSpecifics.cpp | 10 +++++++++- 11 files changed, 234 insertions(+), 8 deletions(-) create mode 100644 slicer/json/testSpecifics.cpp create mode 100644 slicer/slicer/serializer.cpp diff --git a/slicer/json/Jamfile.jam b/slicer/json/Jamfile.jam index 29c40c0..f99e4ab 100644 --- a/slicer/json/Jamfile.jam +++ b/slicer/json/Jamfile.jam @@ -1,14 +1,17 @@ +import testing ; + lib jsonpp : : : : ../..//glibmm ; lib boost_system ; lib boost_filesystem ; +lib boost_utf : : boost_unit_test_framework ; lib IceUtil ; lib adhocutil : : : : /usr/include/adhocutil ; lib slicer-json : - [ glob *.cpp ] + [ glob *.cpp : test*.cpp ] : .. boost_system @@ -22,3 +25,18 @@ lib slicer-json : : : jsonpp ; + +run testSpecifics.cpp + : : : + BOOST_TEST_DYN_LINK + slicer-json + boost_utf + ../test//slicer-test + ../test//common + ../slicer//slicer + .. + ../test//compilation + : + testSpecifics + ; + diff --git a/slicer/json/serializer.cpp b/slicer/json/serializer.cpp index 7476a0d..5e6bf01 100644 --- a/slicer/json/serializer.cpp +++ b/slicer/json/serializer.cpp @@ -6,6 +6,15 @@ #include #include +NAMEDFACTORY(".js", Slicer::JsonFileSerializer, Slicer::FileSerializerFactory); +NAMEDFACTORY(".js", Slicer::JsonFileDeserializer, Slicer::FileDeserializerFactory); +NAMEDFACTORY(".json", Slicer::JsonFileSerializer, Slicer::FileSerializerFactory); +NAMEDFACTORY(".json", Slicer::JsonFileDeserializer, Slicer::FileDeserializerFactory); +NAMEDFACTORY("application/javascript", Slicer::JsonStreamSerializer, Slicer::StreamSerializerFactory); +NAMEDFACTORY("application/javascript", Slicer::JsonStreamDeserializer, Slicer::StreamDeserializerFactory); +NAMEDFACTORY("application/json", Slicer::JsonStreamSerializer, Slicer::StreamSerializerFactory); +NAMEDFACTORY("application/json", Slicer::JsonStreamDeserializer, Slicer::StreamDeserializerFactory); + namespace Slicer { class JsonValueSource : public ValueSource { public: @@ -237,6 +246,32 @@ namespace Slicer { } } + JsonStreamSerializer::JsonStreamSerializer(std::ostream & s) : + strm(s) + { + } + + JsonStreamDeserializer::JsonStreamDeserializer(std::istream & s) : + strm(s) + { + } + + void + JsonStreamDeserializer::Deserialize(ModelPartPtr modelRoot) + { + json::Value obj = json::parseValue(strm); + auto mp = modelRoot->GetAnonChild(); + boost::apply_visitor(DocumentTreeIterate(mp), obj); + } + + void + JsonStreamSerializer::Serialize(ModelPartPtr modelRoot) + { + json::Value doc; + modelRoot->OnEachChild(boost::bind(&JsonSerializer::ModelTreeIterateRoot, &doc, _2)); + json::serializeValue(doc, strm, "utf-8"); + } + JsonFileSerializer::JsonFileSerializer(const boost::filesystem::path & p) : path(p) { diff --git a/slicer/json/serializer.h b/slicer/json/serializer.h index 55c48d3..64f591b 100644 --- a/slicer/json/serializer.h +++ b/slicer/json/serializer.h @@ -13,6 +13,16 @@ namespace Slicer { static void ModelTreeIterateRoot(json::Value *, ModelPartPtr mp); }; + class JsonStreamSerializer : public JsonSerializer { + public: + DLL_PUBLIC JsonStreamSerializer(std::ostream &); + + virtual void Serialize(ModelPartPtr) override; + + private: + std::ostream & strm; + }; + class JsonFileSerializer : public JsonSerializer { public: DLL_PUBLIC JsonFileSerializer(const boost::filesystem::path &); @@ -33,6 +43,16 @@ namespace Slicer { json::Value & value; }; + class JsonStreamDeserializer : public Deserializer { + public: + DLL_PUBLIC JsonStreamDeserializer(std::istream &); + + virtual void Deserialize(ModelPartPtr) override; + + private: + std::istream & strm; + }; + class JsonFileDeserializer : public Deserializer { public: DLL_PUBLIC JsonFileDeserializer(const boost::filesystem::path &); diff --git a/slicer/json/testSpecifics.cpp b/slicer/json/testSpecifics.cpp new file mode 100644 index 0000000..c0a54d4 --- /dev/null +++ b/slicer/json/testSpecifics.cpp @@ -0,0 +1,18 @@ +#define BOOST_TEST_MODULE json_specifics +#include +#include +#include "serializer.h" +#include + +BOOST_AUTO_TEST_CASE( factories ) +{ + BOOST_REQUIRE(Slicer::SerializerPtr(Slicer::FileSerializerFactory::createNew(".json", "/some.json"))); + BOOST_REQUIRE(Slicer::DeserializerPtr(Slicer::FileDeserializerFactory::createNew(".json", "/some.json"))); + BOOST_REQUIRE(Slicer::SerializerPtr(Slicer::FileSerializerFactory::createNew(".js", "/some.js"))); + BOOST_REQUIRE(Slicer::DeserializerPtr(Slicer::FileDeserializerFactory::createNew(".js", "/some.js"))); + BOOST_REQUIRE(Slicer::SerializerPtr(Slicer::StreamSerializerFactory::createNew("application/javascript", std::cout))); + BOOST_REQUIRE(Slicer::DeserializerPtr(Slicer::StreamDeserializerFactory::createNew("application/javascript", std::cin))); + BOOST_REQUIRE(Slicer::SerializerPtr(Slicer::StreamSerializerFactory::createNew("application/javascript", std::cout))); + BOOST_REQUIRE(Slicer::DeserializerPtr(Slicer::StreamDeserializerFactory::createNew("application/javascript", std::cin))); +} + diff --git a/slicer/slicer/serializer.cpp b/slicer/slicer/serializer.cpp new file mode 100644 index 0000000..4856350 --- /dev/null +++ b/slicer/slicer/serializer.cpp @@ -0,0 +1,10 @@ +#define BOOST_FILESYSTEM_DYN_LINK +#define BOOST_FILESYSTEM_SOURCE +#include "serializer.h" +#include + +INSTANTIATEFACTORY(Slicer::Serializer, std::ostream &); +INSTANTIATEFACTORY(Slicer::Deserializer, std::istream &); +INSTANTIATEFACTORY(Slicer::Serializer, const boost::filesystem::path &); +INSTANTIATEFACTORY(Slicer::Deserializer, const boost::filesystem::path &); + diff --git a/slicer/slicer/serializer.h b/slicer/slicer/serializer.h index b7b4541..44cce01 100644 --- a/slicer/slicer/serializer.h +++ b/slicer/slicer/serializer.h @@ -5,19 +5,26 @@ #include #include #include +#include +#include namespace Slicer { - class Serializer : public IceUtil::Shared { + class DLL_PUBLIC Serializer : public IceUtil::Shared { public: virtual void Serialize(ModelPartPtr) = 0; }; typedef IceUtil::Handle SerializerPtr; - class Deserializer : public IceUtil::Shared { + class DLL_PUBLIC Deserializer : public IceUtil::Shared { public: virtual void Deserialize(ModelPartPtr) = 0; }; typedef IceUtil::Handle DeserializerPtr; + + typedef AdHoc::Factory StreamSerializerFactory; + typedef AdHoc::Factory StreamDeserializerFactory; + typedef AdHoc::Factory FileSerializerFactory; + typedef AdHoc::Factory FileDeserializerFactory; } #endif diff --git a/slicer/slicer/slicer.h b/slicer/slicer/slicer.h index f58e8e1..dc5084d 100644 --- a/slicer/slicer/slicer.h +++ b/slicer/slicer/slicer.h @@ -7,15 +7,28 @@ namespace Slicer { template + IceInternal::Handle + Deserialize(SerializerParams && ... sp) __attribute__ ((deprecated)); + template + void + Serialize(IceInternal::Handle object, SerializerParams && ... sp) __attribute__ ((deprecated)); + + template Object - DeserializeAny(SerializerParams && ... sp) + DeserializeAnyWith(DeserializerPtr deserializer) { IceUtil::Handle> root = new ModelPartForRoot(); - DeserializerPtr deserializer = new Deserializer(sp ...); deserializer->Deserialize(root); return root->GetModel(); } + template + Object + DeserializeAny(SerializerParams && ... sp) + { + return DeserializeAnyWith(new Deserializer(sp ...)); + } + template IceInternal::Handle Deserialize(SerializerParams && ... sp) @@ -23,13 +36,20 @@ namespace Slicer { return DeserializeAny, SerializerParams...>(sp ...); } + template + void + SerializeAnyWith(Object object, SerializerPtr serializer) + { + IceUtil::Handle> root = new ModelPartForRoot(object); + serializer->Serialize(root); + } + template void SerializeAny(Object object, SerializerParams && ... sp) { IceUtil::Handle> root = new ModelPartForRoot(object); - SerializerPtr serializer = new Serializer(sp ...); - serializer->Serialize(root); + SerializeAnyWith(object, new Serializer(sp ...)); } template diff --git a/slicer/test/serializers.cpp b/slicer/test/serializers.cpp index 0d309dc..4870bec 100644 --- a/slicer/test/serializers.cpp +++ b/slicer/test/serializers.cpp @@ -422,6 +422,38 @@ BOOST_AUTO_TEST_CASE( json_rootEnums_json ) verifyByFile("enum2.json", checkSomeNumbers); } +BOOST_AUTO_TEST_CASE( json_streams ) +{ + const auto tmpf = tmp / "byStream"; + const auto inFile = root / "initial" / "inherit-c.json"; + const auto outFile = tmpf / "streamout.json"; + boost::filesystem::create_directories(tmpf); + { + std::ifstream in(inFile.string()); + auto d = Slicer::DeserializeAny(in); + checkInherits_types(d); + std::ofstream out(outFile.string()); + Slicer::SerializeAny(d, out); + } + diff(inFile, outFile); +} + +BOOST_AUTO_TEST_CASE( xml_streams ) +{ + const auto tmpf = tmp / "byStream"; + const auto inFile = root / "initial" / "inherit-b.xml"; + const auto outFile = tmpf / "streamout.xml"; + boost::filesystem::create_directories(tmpf); + { + std::ifstream in(inFile.string()); + auto d = Slicer::DeserializeAny(in); + checkInherits_types(d); + std::ofstream out(outFile.string()); + Slicer::SerializeAny(d, out); + } + diff(inFile, outFile); +} + BOOST_AUTO_TEST_CASE( invalid_enum ) { IceUtil::Handle> rootmp = new Slicer::ModelPartForRoot(); @@ -461,13 +493,19 @@ BOOST_AUTO_TEST_CASE( any ) const boost::filesystem::path output = tmpf / "builtins.xml"; BOOST_TEST_CHECKPOINT("Deserialize with wrapper"); +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" TestModule::BuiltInsPtr object = Slicer::Deserialize(input); +#pragma GCC diagnostic pop BOOST_TEST_CHECKPOINT("Test object"); checkBuiltIns_valuesCorrect(object); BOOST_TEST_CHECKPOINT("Serialize with wrapper"); +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" Slicer::Serialize(object, output); +#pragma GCC diagnostic pop BOOST_TEST_CHECKPOINT("Checksum: " << input << " === " << output); diff(input, output); diff --git a/slicer/xml/serializer.cpp b/slicer/xml/serializer.cpp index 6f5df3a..c6c6c5f 100644 --- a/slicer/xml/serializer.cpp +++ b/slicer/xml/serializer.cpp @@ -8,6 +8,11 @@ #include #include +NAMEDFACTORY(".xml", Slicer::XmlFileSerializer, Slicer::FileSerializerFactory); +NAMEDFACTORY(".xml", Slicer::XmlFileDeserializer, Slicer::FileDeserializerFactory); +NAMEDFACTORY("application/xml", Slicer::XmlStreamSerializer, Slicer::StreamSerializerFactory); +NAMEDFACTORY("application/xml", Slicer::XmlStreamDeserializer, Slicer::StreamDeserializerFactory); + namespace Slicer { const std::string md_attribute = "xml:attribute"; const std::string md_text = "xml:text"; @@ -274,6 +279,33 @@ namespace Slicer { ModelTreeProcessElement(doc->create_root_node(name), mp, defaultElementCreator); } + XmlStreamSerializer::XmlStreamSerializer(std::ostream & s) : + strm(s) + { + } + + XmlStreamDeserializer::XmlStreamDeserializer(std::istream & s) : + strm(s) + { + } + + void + XmlStreamDeserializer::Deserialize(ModelPartPtr modelRoot) + { + xmlpp::DomParser dom; + dom.parse_stream(strm); + auto doc = dom.get_document(); + DocumentTreeIterate(doc, modelRoot); + } + + void + XmlStreamSerializer::Serialize(ModelPartPtr modelRoot) + { + xmlpp::Document doc; + modelRoot->OnEachChild(boost::bind(&XmlSerializer::ModelTreeIterateRoot, &doc, _1, _2)); + doc.write_to_stream(strm); + } + XmlFileSerializer::XmlFileSerializer(const boost::filesystem::path & p) : path(p) { diff --git a/slicer/xml/serializer.h b/slicer/xml/serializer.h index a57e846..c580cde 100644 --- a/slicer/xml/serializer.h +++ b/slicer/xml/serializer.h @@ -21,6 +21,16 @@ namespace Slicer { static void ModelTreeProcessElement(xmlpp::Element * n, ModelPartPtr mp, const ElementCreator &); }; + class XmlStreamSerializer : public XmlSerializer { + public: + DLL_PUBLIC XmlStreamSerializer(std::ostream &); + + virtual void Serialize(ModelPartPtr) override; + + private: + std::ostream & strm; + }; + class XmlFileSerializer : public XmlSerializer { public: DLL_PUBLIC XmlFileSerializer(const boost::filesystem::path &); @@ -47,6 +57,16 @@ namespace Slicer { static void DocumentTreeIterate(const xmlpp::Document * doc, ModelPartPtr mp); }; + class XmlStreamDeserializer : public XmlDeserializer { + public: + DLL_PUBLIC XmlStreamDeserializer(std::istream &); + + virtual void Deserialize(ModelPartPtr) override; + + private: + std::istream & strm; + }; + class XmlFileDeserializer : public XmlDeserializer { public: DLL_PUBLIC XmlFileDeserializer(const boost::filesystem::path &); diff --git a/slicer/xml/testSpecifics.cpp b/slicer/xml/testSpecifics.cpp index 20f65fe..001cfb0 100644 --- a/slicer/xml/testSpecifics.cpp +++ b/slicer/xml/testSpecifics.cpp @@ -1,4 +1,4 @@ -#define BOOST_TEST_MODULE db_insert +#define BOOST_TEST_MODULE xml_specifics #include #include #include "serializer.h" @@ -46,3 +46,11 @@ BOOST_AUTO_TEST_CASE( int_values ) BOOST_REQUIRE_THROW(BoostThrowWrapperHelper(doc.get_document()), std::bad_cast); } +BOOST_AUTO_TEST_CASE( factories ) +{ + BOOST_REQUIRE(Slicer::SerializerPtr(Slicer::FileSerializerFactory::createNew(".xml", "/some.xml"))); + BOOST_REQUIRE(Slicer::DeserializerPtr(Slicer::FileDeserializerFactory::createNew(".xml", "/some.xml"))); + BOOST_REQUIRE(Slicer::SerializerPtr(Slicer::StreamSerializerFactory::createNew("application/xml", std::cout))); + BOOST_REQUIRE(Slicer::DeserializerPtr(Slicer::StreamDeserializerFactory::createNew("application/xml", std::cin))); +} + -- cgit v1.2.3