Let me try to simplify my question by extracting and abstracting relevant information from a complex object and large JSON text.

Class Foo()
{
  string Name;
  Version[] versions;
}

JsonText(converted from XML) can be something like this:

  "Foo": {
    "Name": "test",
    "versions": {
        "Major": "1",
        "Minor": "1"
    },
    "versions": {
        "Major": "2",
        "Minor": "1"
    },
    "versions": {
        "Major": "3",
        "Minor": "1"
    }
    }

or the following:

  "Foo": {
    "Name": "test",
    "versions": {
        "Major": "1",
        "Minor": "1"
    }
    }

JsonConvert.DeserializeObject(JsonText) results in:

Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'Version[]' because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.

Is it possible to do this desrialization?

1 Answers

1
Anu Viswan On

Updated based on commment

Your Json doesn't look valid. A Json needs to be enclosed with "[" "]". For example,

[ "Ford", "BMW", "Fiat" ]

If you are allowed to modify your Json, You could modify the Json as following

{
"Foo": 
{
    "Name": "test",
    "versions": [
    {
        "Major": "1",
        "Minor": "1"
    },
    {
        "Major": "2",
        "Minor": "1"
    },
    {
        "Major": "3",
        "Minor": "1"
    }]
}
}

Based on your comment, you would like to avoid the Json Array Syntax if there is only a single element. On other cases, you would like to stick to Array Syntax. In such scenario,you could write a Custom Json Converter.

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

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JToken token = JToken.Load(reader);
        if (token.Type == JTokenType.Array)
        {
            return token.ToObject<List<T>>().ToArray();
        }
        return new List<T> { token.ToObject<T>() }.ToArray();
    }

    public override bool CanWrite
    {
        get { return false; }
    }

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

You can decorate your class with JsonConverter attribute to use the Custom Json Converter.

class Wrapper
{
    public Foo Foo{get;set;}
}
class Foo
{
  [JsonProperty("Name")]
  public string Name{get;set;}

  [JsonProperty("versions")]
  [JsonConverter(typeof(CustomConverter<Version>))]
  public Version[] versions{get;set;}
}

Now you can deserialize as

var result =JsonConvert.DeserializeObject<Wrapper>(str);

This would now work, if you use either of following Json definition.

 {
    'Foo': 
    {
        'Name': 'test',
        'versions': [
        {
            'Major': '1',
            'Minor': '1'
        },
        {
            'Major': '2',
            'Minor': '1'
        },
        {
            'Major': '3',
            'Minor': '1'
        }]
    }
    }

Single Version (Without Array syntax)

  {
    'Foo': 
    {
        'Name': 'test',
        'versions': 
        {
            'Major': '1',
            'Minor': '1'
        }
    }
    }