Deserialize inconsistent JSON property

╄→尐↘猪︶ㄣ 提交于 2020-08-09 08:02:11

问题


Hopefully someone can help me with the following inconsistency occurring in a large JSON file that I am attempting to deserialize using Newtonsoft.Json.

One of the properties of the object occasionally appears as:

"roles": [
  {
    "field1" : "value",
    "field2" : "value"
  }
]

While other times that same property appears as:

"roles": {
  "roles": [
    {
      "field1" : "value",
      "field2" : "value"
    }
  ]
}

For reference, this property is implemented in its class as:

[JsonProperty("roles")]
public List<Role> Roles { get; set; }

What I need to happen is that whenever the second situation above occurs, the object contents are deserialized like the first situation. i.e. the "outer" object is discarded/ignored

I have managed to handle another inconsistency in this file when a separate property sometimes occurs as an object and sometimes as an array using the following approach in its class definition:

[JsonConverter(typeof(SingleValueArrayConverter<Address>))]
public List<Address> Location { get; set; }

And implemented as:

public class SingleValueArrayConverter<T> : JsonConverter
{
    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)
    {
        object retVal = new Object();
        if (reader.TokenType == JsonToken.StartObject)
        {
            T instance = (T)serializer.Deserialize(reader, typeof(T));
            retVal = new List<T>() { instance };
        }
        else if (reader.TokenType == JsonToken.StartArray)
        {
            retVal = serializer.Deserialize(reader, objectType);
        }
        return retVal;
    }

    public override bool CanConvert(Type objectType)
    {
        return true;
    }
}

However, I am unable to work out this issue. Can anyone help?


回答1:


You can handle this inconsistency with a JsonConverter also. It will be a little different than the one you have, but the idea is very similar:

public class ArrayOrWrappedArrayConverter<T> : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return typeof(List<T>).IsAssignableFrom(objectType);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JToken token = JToken.Load(reader);
        if (token.Type == JTokenType.Array)
        {
            return CreateListFromJArray((JArray)token, serializer);
        }
        if (token.Type == JTokenType.Object)
        {
            JObject wrapper = (JObject)token;
            JProperty prop = wrapper.Properties().FirstOrDefault();
            if (prop.Value.Type == JTokenType.Array)
            {
                return CreateListFromJArray((JArray)prop.Value, serializer);
            }
        }
        // If the JSON is not what we expect, just return an empty list.
        // (Could return null or throw an exception here instead if desired.)
        return new List<T>();
    }

    private List<T> CreateListFromJArray(JArray array, JsonSerializer serializer)
    {
        List<T> list = new List<T>();
        serializer.Populate(array.CreateReader(), list);
        return list;
    }

    public override bool CanWrite => false;

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

Then just add the converter to your Roles property and you should be good to go:

[JsonProperty("roles")]
[JsonConverter(typeof(ArrayOrWrappedArrayConverter<Role>))]
public List<Role> Roles { get; set; }

Working demo: https://dotnetfiddle.net/F6qgQB




回答2:


the easiest way (not necessarily the cleanest) would be to manually alter the string before deserialising -

jsonString = jsonString.replace("\"roles\": {", "\"rolesContainer\": {");
jsonString = jsonString.replace("\"roles\":{", "\"rolesContainer\": {");

and then in your main code you would have both rolesContainer and roles as fields - and then merge them after

public List<Role> roles { get; set; }
public RoleContainer rolesContainer { get; set; }
public class RoleContainer {
    Public List<Role> roles;
}

it's dirty, but it should work



来源:https://stackoverflow.com/questions/63045851/deserialize-inconsistent-json-property

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!