0

I got stuck on parsing json in incorrect format. I receive the json from third party so it's not possible to change it. I want to skip properties which are not in correct format and return default value instead.

Let's say I have an object with only one integer attribute MyIntAttribute but in real scenario I have more attributes with different types which can be incorrect.

I have this json:

        var json = @"[
            { ""MyIntAttribute"": 100 },
            { ""MyIntAttribute"": {
                ""wrongObject"": 1,
                ""help"": ""this is wrong""
            }}
        ]";

        var collection = JsonConvert.DeserializeObject<List<MyObject>>(json);

My goal is to get collection with two objects. First has value 100 in the attribute since it is correct in json and the second object with default value 0 because there is some nonsense object instead of integer value.

First I tried to use Error handling in JsonSerializerSettings like this:

Error = (sender, args) => { args.ErrorContext.Handled = true; }

It will skip all errors but it doesn't create objects with default value. So I ended up with only one object and the second one with incorect format was not added in the collection.

Then I tried to create custom convertor:

public class ParsingErrorConvertor : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return true;
    }

    public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }

    public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
    {
        try
        {
            return serializer.Deserialize(reader, objectType);
        }
        catch (Exception e)
        {
            var t = objectType.IsValueType ? Activator.CreateInstance(objectType) : null;
            return t;
        }
    }

My idea was to use this convertor only for attributes where I want to get default value if something goes wrong but I am still missing something.

Kit
  • 20,354
  • 4
  • 60
  • 103
EdWood
  • 875
  • 3
  • 19
  • 37
  • Have you tried Json.NET's [built-in error handling](https://www.newtonsoft.com/json/help/html/ErrorHandlingEvent.htm)? See [Ignore parsing errors during JSON.NET data parsing](https://stackoverflow.com/q/26107656/3744182). (Note that, while you can ignore serialization errors, you can't really ignore *parsing* errors due to malformed JSON, because `JsonTextReader` won't know how to continue.) Json.NET's error handling is self-admitted to be [very flaky](https://github.com/JamesNK/Newtonsoft.Json/issues/1580#issuecomment-358546723) so it might not work for you; give it a try and see if it does. – dbc Aug 09 '21 at 21:31
  • 1
    It won't work for me, it will completly skip the whole object instead of attribute only. – EdWood Aug 10 '21 at 07:13

1 Answers1

0

This is solution.

public class ErrorDefaultConvertor : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return true;
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JToken token = JToken.Load(reader);
        if (token.Type == JTokenType.Object)
        {
            if (objectType.IsValueType) return Activator.CreateInstance(objectType);
            return null;
        }

        return token.ToObject(objectType);
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        serializer.Serialize(writer, value);
    }
}

Use it with attribute.

    [JsonConverter(typeof(ErrorDefaultConvertor))]
    public int MyIntAttribute { get; set; }
EdWood
  • 875
  • 3
  • 19
  • 37