serializr
serializr copied to clipboard
[Feature] context for serialization
deserialization uses a Context
with all deserializers. Custom serializers become more flexible if the serialization process uses the same mechanism.
purpose
support automatic creation of references with a custom serializer.
explanation
A context can be used as a place to store temporary data for serialization. A custom serializer can make use of this temporary data to keep track on all serialized objects and serialize only IDs for those, that have already been serialized. Of course, the companion custom deserializer need to know about such IDs, decode them and behave much like the deserializer of reference()
.
All this would be impossible without keeping track on all already serialized entities.
Coverage increased (+0.5%) to 92.57% when pulling 503784b0064154c5f0b57767bf7447bfec1119c1 on nros:feature_serialize-context into 59fe6e569ec72c102bc8ed3a2ec3697edea35bf0 on mobxjs:master.
Coverage increased (+0.5%) to 92.585% when pulling a80c0c01b2e43dbd7c973666e39c48c74999a2c0 on nros:feature_serialize-context into 59fe6e569ec72c102bc8ed3a2ec3697edea35bf0 on mobxjs:master.
Coverage increased (+0.5%) to 92.702% when pulling dfed41d1df02900c6604f5d42fb5f58562ef2714 on nros:feature_serialize-context into c85a6376fdc535ace2661e5a35686e1928d53901 on mobxjs:master.
Thanks to these changes, I was able to create a custom serializer/deserializer that keeps track on all serialized entities and automatically stores only a reference (as the ID) in case the entity has already been serialized. This avoids breaking up in-memory references during serialization and creating duplicates upon deserializing.
To make that work, I had to tackle #65 as well with this custom serializer. So the serializer stores a class identifier along the serialized data and uses a dependency injection system to create instances for this class identifier upon deserialization.
Using a custom serializer to support these features seems less invasive than changing serializr
itself. So maybe this will help others too.
I would appreciate if you accept this PR, although some internal functions are exposed. This is only done for the good, to make custom serializers integrate better with serializr
, like benefitting from the reference resolving system.
I’m busy recently, I would have spare time to review this feauture seriously until weekend ... I reply to this just let you know we saw your nice works. 👍
@nros let's hold off on this PR until we finish the discussion on #65
@nros I need exactly this, along with the support for containers of polymorphic objects. I've pulled your feature branch for this, but I am new to serializr (and Javascript - using Typescript actually), so a rough example of your custom serializer/deserializer maintaining the context would be very helpful for me. By the way, I implemented a scheme that works like this in C++ over 20 years ago and have been using it ever since in applications built from plugins.
@nros to achieve what I envisage at the top level, I would like to pass a context object to the serialize<T>()
function (and the deserialize<T>()
function) so that I can control the lifetime of the dictionary of references. I would like to pass the reference dictionary filled in when serializing a full snapshot of the state of the app to subsequent calls to serialize() for incremental actions that occur after the snapshot is written.
I currently can't see how to achieve this control with a custom serializer alone.
@spinorkit see this example: https://gist.github.com/nros/7791baca1927ee6b25e790da76544d99
This is almost a year old by now. Any hope for it being merged? I have exactly the same use case - I need to serialize cyclic graph, preferably in a way compatible with json.net
@nros @spinorkit I am happy to have a look at this, if there is still a need. However, please provide some test cases, that can be a basis for the discussion of the optimal API changes. Ideally you can make some respective enhancements in test/typescript/ts.ts for the PR
**Update: ** I think I misunderstood the intent of this PR. I might put this suggestion in a separate issue.
~I believe this same feature could easily be achieved by defining this function~
export function deserializeWithContext(context: Context, _class: any, serialized: any) {
return deserializeObjectWithSchema(context, getDefaultModelSchema(_class)!, serialized, () => {}, undefined);
}
~deserializeObjectWithSchema
is (defined below)~ https://github.com/mobxjs/serializr/blob/69fed6f55bf04a2cfa07dd8cb5863af7a44be9a8/src/core/deserialize.ts#L120
~But it is not a part of the serializr
public api, and thus it is not re-exported by serializr
~
It's been a while. The project depending on this fix has already been abondoned and replaced by a Java+Vue re-implementation. I'll do my best to update my MR and provide some test cases within the next weeks.