Details
Description
When one has a data object which has an IBinaryObject property, like so:
class Model { public IBinaryObject Value { get; set; } }
.. and proceeds to fill that property with an IBinaryObject of an unknown type (e.g. a binary object from a cache that has WithKeepBinary on):
var binary = ignite.GetBinary(); var model = new Model { Value = binary.GetBuilder("nonexistent").Build() };
Then, the resulting object is savable/loadable from caches, as expected:
var cache = ignite.GetOrCreateCache<string, Model>("models"); cache.Put("model", model); var modelFromCache = cache.Get("model"); // Equivalent to model
However, trying to convert the object to IBinaryObject (using ToBinary) and then deserializing that manually fails:
var binaryObject = binary.ToBinary<IBinaryObject>(model); var modelFromBinary = binaryObject.Deserialize<Model>(); // Unknown pair [platformId=1, typeId=486454369]
I have attached a program which reproduces the issue.
After investigating the issue, it seems to occur because BinaryObject.Deserialize<T>() uses BinaryMode.Deserialize. This, in turn, causes BinaryReader.ReadBinaryObject() to call BinaryReader.Deserialize() for the first BinaryTypeId.Binary object found (while switching to BinaryMode.KeepBinary for nested objects). Then, BinaryReader.ReadFullObject() gets called, and not knowing better, tries to deserialize the object of a nonexistent type.
Now, BinaryMode.Deserialize is also used by CacheClient. However, upon further investigation of the values passed to Marshaller.Unmarshall, CacheClient unmarshalls values starting with BinaryTypeId.Binary, while BinaryObject unmarshalls values starting directly with BinaryUtils.HdrFull; thus, BinaryReader functions correctly for caches but fails with binary objects.
Due to the this, I think the proper fix would be to change BinaryObject.Deserialize<T>() to use BinaryMode.KeepBinary. I have attached a patch file containing that fix and an accompanying test.
Attachments
Attachments
Issue Links
- links to