# HG changeset patch # User Jacob Carlborg # Date 1313243839 -7200 # Node ID beb4afce2f3ed31d9d9b46f20020d59b1b60b17f # Parent a7dea44fa9e387272b04c0ac05563bb05153f24c Fixed (de)serializing through base class reference, including unit test. diff -r a7dea44fa9e3 -r beb4afce2f3e orange/serialization/Serializer.d --- a/orange/serialization/Serializer.d Sat Aug 13 15:24:52 2011 +0200 +++ b/orange/serialization/Serializer.d Sat Aug 13 15:57:19 2011 +0200 @@ -56,13 +56,15 @@ Id id; string key; } - + ErrorCallback errorCallback_; Archive archive_; size_t keyCounter; Id idCounter; + void delegate (Object, Mode mode) [ClassInfo] registeredTypes; + RegisterBase[string] serializers; RegisterBase[string] deserializers; @@ -95,6 +97,24 @@ setThrowOnErrorCallback(); } + void register (T : Object) () + { + registeredTypes[T.classinfo] = &downcastSerialize!(T); + } + + private void downcastSerialize (T : Object) (Object value, Mode mode) + { + auto casted = cast(T) value; + assert(casted); + assert(casted.classinfo is T.classinfo); + + if (mode == serializing) + objectStructSerializeHelper(casted); + + else + objectStructDeserializeHelper(casted); + } + Archive archive () { return archive_; @@ -126,6 +146,7 @@ serializers = null; deserializers = null; + registeredTypes = null; serializedReferences = null; deserializedReferences = null; @@ -134,7 +155,10 @@ deserializedSlices = null; serializedValues = null; + deserializedValues = null; + serializedPointers = null; + deserializedPointers = null; hasBegunSerializing = false; hasBegunDeserializing = false; @@ -231,9 +255,20 @@ else { if (isBaseClass(value)) - throw new SerializationException(`The object of the static type "` ~ T.stringof ~ `" have a different runtime type (` ~ runtimeType ~ `) and therefore needs to register a serializer for its type "` ~ runtimeType ~ `".`, __FILE__, __LINE__); - - objectStructSerializeHelper(value); + { + if (auto serializer = value.classinfo in registeredTypes) + (*serializer)(value, serializing); + + else + throw new SerializationException( + `The object of the static type "` ~ T.stringof ~ + `" have a different runtime type (` ~ runtimeType ~ + `) and therefore needs to either register its type or register a serializer for its type "` + ~ runtimeType ~ `".`, __FILE__, __LINE__); + } + + else + objectStructSerializeHelper(value); } }); }); @@ -469,9 +504,20 @@ else { if (isBaseClass(value)) - throw new SerializationException(`The object of the static type "` ~ T.stringof ~ `" have a different runtime type (` ~ runtimeType ~ `) and therefore needs to register a deserializer for its type "` ~ runtimeType ~ `".`, __FILE__, __LINE__); + { + if (auto deserializer = value.classinfo in registeredTypes) + (*deserializer)(value, deserializing); - objectStructDeserializeHelper(value); + else + throw new SerializationException( + `The object of the static type "` ~ T.stringof ~ + `" have a different runtime type (` ~ runtimeType ~ + `) and therefore needs to either register its type or register a deserializer for its type "` + ~ runtimeType ~ `".`, __FILE__, __LINE__); + } + + else + objectStructDeserializeHelper(value); } }); }); @@ -995,10 +1041,7 @@ private bool isBaseClass (T) (T value) { - auto name = value.classinfo.name; - auto index = name.lastIndexOf('.'); - - return T.stringof != name[index + 1 .. $]; + return value.classinfo !is T.classinfo; } private Id nextId () diff -r a7dea44fa9e3 -r beb4afce2f3e tests/BaseClass.d --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/BaseClass.d Sat Aug 13 15:57:19 2011 +0200 @@ -0,0 +1,78 @@ +/** + * Copyright: Copyright (c) 2011 Jacob Carlborg. All rights reserved. + * Authors: Jacob Carlborg + * Version: Initial created: Aug 7, 2011 + * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0) + */ +module tests.BaseClass; + +import orange.core.string; +import orange.serialization.Serializer; +import orange.serialization.archives.XMLArchive; +import orange.test.UnitTester; +import tests.Util; + +Serializer serializer; +XMLArchive!(char) archive; + +class Base +{ + int a; + + int getA () + { + return a; + } + + int getB () + { + return a; + } +} + +class Sub : Base +{ + int b; + + int getB () + { + return b; + } +} + +Sub sub; +Base base; + +unittest +{ + archive = new XMLArchive!(char); + serializer = new Serializer(archive); + + sub = new Sub; + sub.a = 3; + sub.b = 4; + base = sub; + + describe("serialize subclass through a base class reference") in { + it("should return serialized subclass with the static type \"Base\" and the runtime type \"tests.BaseClass.Sub\"") in { + serializer.reset; + serializer.register!(Sub); + serializer.serialize(base); + + assert(archive.data().containsDefaultXmlContent()); + assert(archive.data().containsXmlTag("object", `runtimeType="tests.BaseClass.Sub" type="Base" key="0" id="0"`)); + assert(archive.data().containsXmlTag("int", `key="b" id="1"`, "4")); + assert(archive.data().containsXmlTag("base", `type="Base" key="1" id="2"`)); + assert(archive.data().containsXmlTag("int", `key="a" id="3"`, "3")); + }; + }; + + describe("deserialize subclass through a base class reference") in { + it("should return a deserialized subclass with the static type \"Base\" and the runtime type \"tests.BaseClass.Sub\"") in { + auto subDeserialized = serializer.deserialize!(Base)(archive.untypedData); + + assert(sub.a == subDeserialized.getA); + assert(sub.b == subDeserialized.getB); + }; + }; +} \ No newline at end of file diff -r a7dea44fa9e3 -r beb4afce2f3e unittest.sh --- a/unittest.sh Sat Aug 13 15:24:52 2011 +0200 +++ b/unittest.sh Sat Aug 13 15:57:19 2011 +0200 @@ -29,6 +29,7 @@ tests/Array.d \ tests/AssociativeArray.d \ tests/AssociativeArrayReference.d \ +tests/BaseClass.d \ tests/Enum.d \ tests/Event.d \ tests/Object.d \