zcsizmadia / ZCS.Utf8Json

Definitely Fastest and Zero Allocation JSON Serializer for C#(NET, .NET Core, Unity, Xamarin).
MIT License
35 stars 7 forks source link

Is it possible to support data source is int type and automatically convert to Object data structure is bool type? #72

Closed SyaoranChang closed 9 months ago

SyaoranChang commented 9 months ago

Hi,

I'm using Unity engine. Is it possible to support data source is int type and automatically convert to Object data structure is bool type? json {"GUID":1, "LimitedTime":1}

structure public class S_CycleQuestList_Tmp { public int GUID; public bool LimitedTime; }

Error log: JsonParsingException: expected:'true | false', actual:'1', at offset:260

zcsizmadia commented 9 months ago

The Json boolean valid values are only true and false. However it is possible to write a custom converter for boolean which automatically detects when reading if a value is a string "true", "false", integer zero non-zero, or truw/false and set the bool value accordingly, while the write step follows the json standard of tru/false keywords.

The biggest issue is incompatibility with other json serializers. If you plan to migrate to other json serializers, this behaviour has to be implemented as well.

I think the Newtionsoft.aspnet library does convert integers to booleans automatically if it detects it, however the original Newtonsoft library does not.

zcsizmadia commented 9 months ago

Here is a sample code snippet, which should deserialize automatically to boolean from integer, string or true/false keyword, but serialize via the default bool serializer (true/false keyword):

public class CustomBooleanFormatter : IJsonFormatter<bool>
{
    public bool Deserialize(ref JsonReader reader, IJsonFormatterResolver formatterResolver)
    {
        switch (reader.GetCurrentJsonToken())
        {
            case JsonToken.Number:
                return formatterResolver.GetFormatterWithVerify<int>().Deserialize(ref reader, formatterResolver) != 0;

            case JsonToken.String:
                return formatterResolver.GetFormatterWithVerify<string>().Deserialize(ref reader, formatterResolver).ToLower() == "true";

            default:
                return formatterResolver.GetFormatterWithVerify<bool>().Deserialize(ref reader, formatterResolver);
        }
    }

    public void Serialize(ref JsonWriter writer, bool value, IJsonFormatterResolver formatterResolver)
    {
        formatterResolver.GetFormatterWithVerify<bool>().Serialize(ref writer, value, formatterResolver);
    }
}

[DataContract]
public class A
{
    [DataMember]
    [JsonFormatter(typeof(CustomBooleanFormatter))]
    public bool value { get; set; }
}
SyaoranChang commented 9 months ago

Hi,

Thank you for your answer.

1.I'm currently using Newtonsoft.Json-for-Unity, which can automatically convert int to bool, but the whole conversion time to object is a bit long, so I'd like to try looking at Utf8Json to see if there's a chance to shorten the conversion time to object.

2.I've tried CustomBooleanFormatter , and I can successfully deserialize S_CycleQuestList_Tmp, but this way I have to add it to all the other structure's bool variables, so maybe I should try to let excel check the bool first and output true or false, that's a more correct way, I don't know how long it will take, though.

zcsizmadia commented 9 months ago

You can set the CustomBooleanConverter as the default/global bool converter for the serializer. In that case you do not need to modify any of the existing classes. All bools will use that deserialier.

SyaoranChang commented 9 months ago

You can set the CustomBooleanConverter as the default/global bool converter for the serializer. In that case you do not need to modify any of the existing classes. All bools will use that deserialier.

Excuse me, is that how it's written? It doesn't seem to be working?

// use global-singleton CompositeResolver. // This method initialize CompositeResolver and set to default JsonSerializer CompositeResolver.RegisterAndSetAsDefault(new IJsonFormatter[] { // add custome formatters, use other DateTime format. // if target type is struct, requires add nullable formatter too(use NullableXxxFormatter or StaticNullableFormatter(innerFormatter)) new CustomBooleanFormatter() }, new[] { // set StandardResolver or your use resolver chain Utf8Json.Resolvers.StandardResolver.Default, });

zcsizmadia commented 9 months ago

Generally the code you have above is what I would have done, however it seems like overwriting built-in type converters is ignored and not supported at this point.