Surrogate int, float and decimal with Json.NET

We use Json.net for serialization. and we want to allow serialization of any type of custom class / message.

One thing that Json.net cannot support out of the box is to store an int , float or decimal in the object field. eg.

  public class SomeMessage { public object Something {get;set;} } 

if I store int , float or decimal in the Something field, it will be deserialized in either long or double (since json.net can do nothing but guess the primitive type in json ("foo": 123 <int or long?)

Im fully aware that I can use the correct type for the property and set various hints.

But I want to solve this for any random class / post.

My current approach is a custom JsonConverter that deals with the above types and then serializes them into a surrogate type that contains the value as a string and discriminator for what type it is. And then on ReadJson I will return to the correct type.

There is a lot of overheating for this. especially for the surrogate type. "foo.bar.baz.PrimitiveSurrogate, mylib"

Can I customize how to save this name? for example if I want to apply aliases to some specific types?

Are there other approaches? I could serialize all of this into a special line instead, which would be smaller, but again, which iffy feels like.

So, what are my options here if I want to save primitives with their correct type when stored in an untyped structure?

[change]

Normal Json:

 { "foo":123 } 

vs.

Our current surrogate version:

 { "foo": { "$type":"Akka.Serialization.PrimitiveSurrogate, Akka", "V":"123", "T":1 } } 

I could replace V and T with just ā€œVā€: ā€œ123Lā€ and parse the suffix, since we only store int, float and decimal in this type, so we can easily have a hard-coded delimiter.

But that still does not get rid of the $ type for the surrogate itself, I would like to at least shorten it to the `` $ type ":" Surrogate "type or something in this direction.

[Change again] I got to:

 {"$type":"Akka.Util.PrimitiveSurrogate, Akka","V":"F123.456"} 

But I really want to get rid of the long name and replace the alias in some way.

[Change again again]

Now I understand:

 {"$":"M123.456"} 

This is good enough imo. We do not need to interact with any other json system, its only by our structure at both ends, so the created format works, even if it is not.

+6
source share
1 answer

How important is payload size? You could, for example, embed metadata about the type of each primitive, essentially linking the data contract with the data. For instance:

 { "someInteger": 123, "$someInteger.clrType": " System.Int32" } 

EDIT:

If the payload size is most important, you can do something like:

 { "someInteger.i": 123 } 

This will reduce the payload increase to two characters by a primitive value. I am sure the dot is safe to use as a delimiter; those. for the CLR identifier there should not be the identifier "someInteger.i", although I would double check this for compliance with the specification (valid identifiers in the CLR are regulated by the following document: Appendix 7 http://www.unicode.org/reports/tr15/tr15- 18.html # Programming% 20Language% 20Identifiers ).

If you really want to compress it, you can remove the separator (.) And property name suffix with a single Unicode character, which is forbidden by the CLR specification, to represent the desired primitive type. A bit hacked, but it will reduce the payload on another byte .; -)

+4
source

Source: https://habr.com/ru/post/983700/


All Articles