当只有一个条目时,反序列化json,其中属性具有对象而不是数组?

时间:2017-07-11 09:14:23

标签: c# json.net

我必须处理的API在数组中只有一个条目时返回一个对象,否则返回一个正确的数组。这是一个例子:

只有一个条目:

{
  "product": {
    "offers": {
      "id": 1,
      "price": 55.6
    }
  }
}

不止一个条目:

{
  "product": {
    "offers": [
      {
        "id": 1,
        "price": 55.6
      },
      {
        "id": 2,
        "price": 34.6
      },
    ]
  }
}

是否有某种方法可以编写代码,将这两种变体反序列化为数组而无需为整个(深层嵌套)响应编写完整的JsonConverter?除了这个奇怪的看似设计决策,JSON.net可以轻松地反序列化它,所以我想知道是否有JSON.net功能允许我写这样的东西:

if (hasExpectedArray && hasEncounteredObject) {
  deserialized.property = new List<T>();
  deserialized.property.Add(objectEncountered);
}

我的另一个想法是预先解析JSON并使用一些搜索和替换功能来将所有可以是数组的对象更改为数组。但这看起来很脏又脆。

编辑:实际上忘记了第三种情况:它也可以是一个字符串,或者其中一个数组成员可以是一个字符串:

{
  "product": {
    "offers": "This is an offer"
  }
}

{
  "product": {
    "offers": [
      {
        "id": 1,
        "price": 55.6
      },
      "This is another offer"
    ]
  }
}

1 个答案:

答案 0 :(得分:8)

发布此消息后不久,我在搜索结果中找到了一个可以解决这个问题的博客文章:

http://michaelcummings.net/mathoms/using-a-custom-jsonconverter-to-fix-bad-json-results/

编辑2017-07-19:弹出另一个博文:http://trycatchfail.com/blog/post/Dealing-with-Horrid-No-Good-Very-Bad-APIs-Using-JSONNET

如果它发生故障,这里是JsonConverter的相关代码:

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 interface IHasContent
{
    string Content { get; set; }
}

因为至少只有字符串的类型总是具有相同的名称。

有问题的类型得到了属性和接口:

[JsonConverter(typeof(SingleValueArrayConverter<ShippingInfo>))]
public class ShippingInfo : IHasContent

对于字符串转换,我添加了一个简单的隐式运算符:

public static implicit operator ShippingInfo(string s)
{
    return new ShippingInfo { Content = s };
}

转换器有一些类型限制:

public class SingleValueArrayConverter<T> : JsonConverter where T : IHasContent, new()

最后,这是ReadJson方法:

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
    object retVal;
    switch (reader.TokenType)
    {
        case JsonToken.StartObject:
            var instance = (T)serializer.Deserialize(reader, typeof(T));
            retVal = new List<T> { instance };
            break;

        case JsonToken.StartArray:
            retVal = serializer.Deserialize(reader, objectType);
            break;

        case JsonToken.String:
            retVal = ReadStringAsContentObject();
            break;

        default:
            throw new ArgumentException();
    }
    return retVal;
    object ReadStringAsContentObject()
    {
        var content = new T();
        content.Content = reader.ReadAsString();
        var returnObject = new List<T> { content };
        return returnObject;
    }
}