rpgmaker / NetJSON

Faster than Any Binary? Benchmark: http://theburningmonk.com/2014/08/json-serializers-benchmarks-updated-2/
MIT License
231 stars 29 forks source link

Custom serialization of an arbitary type #215

Closed jfontsaballs closed 5 years ago

jfontsaballs commented 5 years ago

Hello,

As you recommended in #214 I request a new feature which allows costumizing serialization for certain types. Maybe it could be implemented using a function that allows two delegates to be registered (or an interface with two methods). First delegate/method would provide serialization for the type; second delegate would provide deserialization. JSON.NET provides a similar functionality (see JSON.NET Implementing Custom Serialization).

Maybe you could create these delegates:

public delegate string SerializeToJson<Type>(Type instance);
public delegate Type DeserializeFrojmJson<Type>(string jsonString);

Or an equivalent interface

public interface ICustomSerializer<Type>
{
    string SerializeToJson(Type instance);
    Type DeserializeFrojmJson(string jsonString);
}

And then you could add this method to the NetJSON class:

    public static void registerCursomSerialization<Type>(SerializeToJson<Type> serializationDelegate, DeserializeFrojmJson<Type> deserializationDelegate) { ... }

// or

    public static void registerSerializer<Type>(ICustomSerializer<Type> customSerializer) { ... }

When a custom serialization is registered for a type, it is used every time this type is encountered instead of standard serialization.

Thank-you

rpgmaker commented 5 years ago

Thanks for giving all the details.

rpgmaker commented 5 years ago

I will take a look at this in the weekend. Thanks

rpgmaker commented 5 years ago

Is it fine if i don't support/ignore registration after the type has been processed by the standard serialization? The reason for this is because it faster if the custom registration is compiled into memory before the type is ever encountered instead of having to do dynamic lookup at runtime.

jfontsaballs commented 5 years ago

My intended use case is to register custom serializations before performing any serialization, so it would be ok. Thank you very much for your great work.

rpgmaker commented 5 years ago

Cool. Btw for the deserialization it is a little bit complicated since it is going to be difficult to infer how much of your data needs to be read before been passed on to your custom deserializer logic as string. Currently the internal logic uses the following structure

T Deserialize(char* ptr, ref int index, NetJSONSettings settings). Would you be fine with this type of signature as it will require that you manually control the index increment to retrieve your data from the pointer provided.

I can provide a simple example of how to work with it. The only downside is over incrementing the index provided for navigation of the pointer which could cause other issue such as incomplete deserialization.

Let me know your feedback.

Thanks,

jfontsaballs commented 5 years ago

Most of the .NET code I write is for LOB applications and we try to keep this code as free as possible from implementation details such as pointers. So, I'm no willing to use such a signature directly in my application code.

However, if you could provide an example of how to use it, I'm pretty sure I can develop some easier to use methods on top of it, which would be acceptable inside application code. To sum up, the signature you propose is adequate but some work will be necessary on my part to adapt it to my requirements ( I will try to share my code in case could be interesting for you).

Thank you very much!

rpgmaker commented 5 years ago

Here is an example of what it will look like. In my example, i created a custom class that serializes the name property as "{Name}". Let me know your thoughts, writing a custom wrapper to hide the pointers will be tough to do again unless maybe i have a stringreader class that is exposes that manages the pointer and navigation of the index internally.

So that it will end up looking more like this: T Deserialize(StringReaderEx reader, NetJSONSettings settings); instead of the below image

image

jfontsaballs commented 5 years ago

Thanks for the example.

In my opinion, a signature using StringReader would provide protection against misuse of the pointer, which can happen (among other reasons) when trying to deserialize improperly formatted data.

If sticking with the char* signature, some means should be provided to avoid memory overrun that do not rely in proper format of the string to be deserialized (maximum value of the index parameter, for instance).

rpgmaker commented 5 years ago

Ok, let me try to see what I can do to abstract the pointer access. Thanks

rpgmaker commented 5 years ago

Still trying to figure out a way to simplify the access without exposing pointers. Thanks for been patient

jfontsaballs commented 5 years ago

If preventing the exposure of the pointer proves to be too much work, adding an additional parameter to that signature which provides an upper limit to the index should be enough to allow the inclusion of a check, in the algorithms that implement it, to prevent a memory overrun should something unexpected occur.

With this information, an adequate abstraction can be developed on top of it at a later date if it becomes necessary.

rpgmaker commented 5 years ago

That is a good point. But the upper limit will be difficult to set for the caller since you cannot predict it unless your custom serialization has a fixed length for data. Upper limit will definitely allow to extract a string from the incoming json without the extra loops.

I will think about it and it see what can be done. And thanks again for the idea.

rpgmaker commented 5 years ago

I have not forgotten about your request. Still have not came up with a clever way to use the pointer. And i did not get any reply from you regarding the fix length idea.

rpgmaker commented 5 years ago

I got something working now without the upper limit. Just removing the reflection code then it should be good to go.

image

rpgmaker commented 5 years ago

Please test and let me know if it works as expected for you then i can publish it as a nuget package. Thanks

rpgmaker commented 5 years ago

I think my solution to custom type serializer is more type safe than the way it is done in JSON.net which provides type instead of the concrete object itself.

jfontsaballs commented 5 years ago

It looks really promising. I'll test it tomorrow when I'm in front of the computer. Thank you very much!

rpgmaker commented 5 years ago

I went ahead and published the nuget package already