diff options
author | Dan Goodliffe <dan@randomdan.homeip.net> | 2016-01-19 22:19:23 +0000 |
---|---|---|
committer | Dan Goodliffe <dan@randomdan.homeip.net> | 2016-01-19 22:19:23 +0000 |
commit | 336b1f9ca5cbb96027c768c3109c6aacafa6e1af (patch) | |
tree | b28c67f27f3163914dfc23d509220b24e3cb0bdd | |
parent | Split type specific model parts into their own file. (diff) | |
download | slicer-336b1f9ca5cbb96027c768c3109c6aacafa6e1af.tar.bz2 slicer-336b1f9ca5cbb96027c768c3109c6aacafa6e1af.tar.xz slicer-336b1f9ca5cbb96027c768c3109c6aacafa6e1af.zip |
Add support for json/xml stream serializers and support for serializer factories based on mime types and file extensions
-rw-r--r-- | slicer/json/Jamfile.jam | 20 | ||||
-rw-r--r-- | slicer/json/serializer.cpp | 35 | ||||
-rw-r--r-- | slicer/json/serializer.h | 20 | ||||
-rw-r--r-- | slicer/json/testSpecifics.cpp | 18 | ||||
-rw-r--r-- | slicer/slicer/serializer.cpp | 10 | ||||
-rw-r--r-- | slicer/slicer/serializer.h | 11 | ||||
-rw-r--r-- | slicer/slicer/slicer.h | 28 | ||||
-rw-r--r-- | slicer/test/serializers.cpp | 38 | ||||
-rw-r--r-- | slicer/xml/serializer.cpp | 32 | ||||
-rw-r--r-- | slicer/xml/serializer.h | 20 | ||||
-rw-r--r-- | slicer/xml/testSpecifics.cpp | 10 |
11 files changed, 234 insertions, 8 deletions
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 : : : : <library>../..//glibmm ; lib boost_system ; lib boost_filesystem ; +lib boost_utf : : <name>boost_unit_test_framework ; lib IceUtil ; lib adhocutil : : : : <include>/usr/include/adhocutil ; lib slicer-json : - [ glob *.cpp ] + [ glob *.cpp : test*.cpp ] : <include>.. <library>boost_system @@ -22,3 +25,18 @@ lib slicer-json : : : <library>jsonpp ; + +run testSpecifics.cpp + : : : + <define>BOOST_TEST_DYN_LINK + <library>slicer-json + <library>boost_utf + <library>../test//slicer-test + <library>../test//common + <library>../slicer//slicer + <include>.. + <dependency>../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 <fstream> #include <glibmm/ustring.h> +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 <boost/test/unit_test.hpp> +#include <slicer/slicer.h> +#include "serializer.h" +#include <types.h> + +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 <factory.impl.h> + +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 <IceUtil/Handle.h> #include <boost/filesystem/path.hpp> #include <slicer/modelParts.h> +#include <visibility.h> +#include <factory.h> namespace Slicer { - class Serializer : public IceUtil::Shared { + class DLL_PUBLIC Serializer : public IceUtil::Shared { public: virtual void Serialize(ModelPartPtr) = 0; }; typedef IceUtil::Handle<Serializer> SerializerPtr; - class Deserializer : public IceUtil::Shared { + class DLL_PUBLIC Deserializer : public IceUtil::Shared { public: virtual void Deserialize(ModelPartPtr) = 0; }; typedef IceUtil::Handle<Deserializer> DeserializerPtr; + + typedef AdHoc::Factory<Serializer, std::ostream &> StreamSerializerFactory; + typedef AdHoc::Factory<Deserializer, std::istream &> StreamDeserializerFactory; + typedef AdHoc::Factory<Serializer, const boost::filesystem::path &> FileSerializerFactory; + typedef AdHoc::Factory<Deserializer, const boost::filesystem::path &> 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,29 +7,49 @@ namespace Slicer { template <typename Deserializer, typename Object, typename ... SerializerParams> + IceInternal::Handle<Object> + Deserialize(SerializerParams && ... sp) __attribute__ ((deprecated)); + template <typename Deserializer, typename Object, typename ... SerializerParams> + void + Serialize(IceInternal::Handle<Object> object, SerializerParams && ... sp) __attribute__ ((deprecated)); + + template <typename Object> Object - DeserializeAny(SerializerParams && ... sp) + DeserializeAnyWith(DeserializerPtr deserializer) { IceUtil::Handle<ModelPartForRoot<Object>> root = new ModelPartForRoot<Object>(); - DeserializerPtr deserializer = new Deserializer(sp ...); deserializer->Deserialize(root); return root->GetModel(); } template <typename Deserializer, typename Object, typename ... SerializerParams> + Object + DeserializeAny(SerializerParams && ... sp) + { + return DeserializeAnyWith<Object>(new Deserializer(sp ...)); + } + + template <typename Deserializer, typename Object, typename ... SerializerParams> IceInternal::Handle<Object> Deserialize(SerializerParams && ... sp) { return DeserializeAny<Deserializer, IceInternal::Handle<Object>, SerializerParams...>(sp ...); } + template <typename Object> + void + SerializeAnyWith(Object object, SerializerPtr serializer) + { + IceUtil::Handle<ModelPartForRoot<Object>> root = new ModelPartForRoot<Object>(object); + serializer->Serialize(root); + } + template <typename Serializer, typename Object, typename ... SerializerParams> void SerializeAny(Object object, SerializerParams && ... sp) { IceUtil::Handle<ModelPartForRoot<Object>> root = new ModelPartForRoot<Object>(object); - SerializerPtr serializer = new Serializer(sp ...); - serializer->Serialize(root); + SerializeAnyWith(object, new Serializer(sp ...)); } template <typename Serializer, typename Object, typename ... SerializerParams> 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<TestModule::SomeNumbers, Slicer::JsonFileDeserializer>("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<Slicer::JsonStreamDeserializer, TestModule::InheritanceContPtr>(in); + checkInherits_types(d); + std::ofstream out(outFile.string()); + Slicer::SerializeAny<Slicer::JsonStreamSerializer>(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<Slicer::XmlStreamDeserializer, TestModule::InheritanceContPtr>(in); + checkInherits_types(d); + std::ofstream out(outFile.string()); + Slicer::SerializeAny<Slicer::XmlStreamSerializer>(d, out); + } + diff(inFile, outFile); +} + BOOST_AUTO_TEST_CASE( invalid_enum ) { IceUtil::Handle<Slicer::ModelPartForRoot<TestModule::SomeNumbers>> rootmp = new Slicer::ModelPartForRoot<TestModule::SomeNumbers>(); @@ -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<Slicer::XmlFileDeserializer, TestModule::BuiltIns>(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<Slicer::XmlFileSerializer>(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 <stdexcept> #include <glibmm/ustring.h> +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 <boost/test/unit_test.hpp> #include <slicer/slicer.h> #include "serializer.h" @@ -46,3 +46,11 @@ BOOST_AUTO_TEST_CASE( int_values ) BOOST_REQUIRE_THROW(BoostThrowWrapperHelper<Ice::Int>(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))); +} + |