Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Deserializing JSON when sometimes array and sometimes object

I'm having a bit of trouble deserializing data returned from Facebook using the JSON.NET libraries.

The JSON returned from just a simple wall post looks like:

{     "attachment":{"description":""},     "permalink":"http://www.facebook.com/permalink.php?story_fbid=123456789" } 

The JSON returned for a photo looks like:

"attachment":{         "media":[             {                 "href":"http://www.facebook.com/photo.php?fbid=12345",                 "alt":"",                 "type":"photo",                 "src":"http://photos-b.ak.fbcdn.net/hphotos-ak-ash1/12345_s.jpg",                 "photo":{"aid":"1234","pid":"1234","fbid":"1234","owner":"1234","index":"12","width":"720","height":"482"}}         ], 

Everything works great and I have no problems. I've now come across a simple wall post from a mobile client with the following JSON, and deserialization now fails with this one single post:

"attachment":     {         "media":{},         "name":"",         "caption":"",         "description":"",         "properties":{},         "icon":"http://www.facebook.com/images/icons/mobile_app.gif",         "fb_object_type":""     }, "permalink":"http://www.facebook.com/1234" 

Here is the class I am deserializing as:

public class FacebookAttachment     {         public string Name { get; set; }         public string Description { get; set; }         public string Href { get; set; }         public FacebookPostType Fb_Object_Type { get; set; }         public string Fb_Object_Id { get; set; }          [JsonConverter(typeof(FacebookMediaJsonConverter))]         public List<FacebookMedia> { get; set; }          public string Permalink { get; set; }     } 

Without using the FacebookMediaJsonConverter, I get an error: Cannot deserialize JSON object into type 'System.Collections.Generic.List`1[FacebookMedia]'. which makes sense, since in the JSON, Media is not a collection.

I found this post which describes a similar problem, so I've attempted to go down this route: Deserialize JSON, sometimes value is an array, sometimes "" (blank string)

My converter looks like:

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) {      if (reader.TokenType == JsonToken.StartArray)           return serializer.Deserialize<List<FacebookMedia>>(reader);      else           return null; } 

Which works fine, except I now get a new exception:

Inside JsonSerializerInternalReader.cs, CreateValueInternal(): Unexpected token while deserializing object: PropertyName

The value of reader.Value is "permalink". I can clearly see in the switch that there's no case for JsonToken.PropertyName.

Is there something I need to do differently in my converter? Thanks for any help.

like image 679
mfanto Avatar asked Mar 07 '11 20:03

mfanto


People also ask

Why do we need to deserialize JSON?

After the byte strings are transmitted, the receiver will have to recover the original object from the byte string. This is known as deserialization. which can be stored or sent through wire to anywhere. The receiver can then deserialize this string to get back the original object.

What is the difference between serialize and deserialize JSON?

JSON is a format that encodes objects in a string. Serialization means to convert an object into that string, and deserialization is its inverse operation (convert string -> object). If you serialize this result it will generate a text with the structure and the record returned.

How do I deserialize a JSON file?

A common way to deserialize JSON is to first create a class with properties and fields that represent one or more of the JSON properties. Then, to deserialize from a string or a file, call the JsonSerializer. Deserialize method.

How does JSON deserialize work?

In Deserialization, it does the opposite of Serialization which means it converts JSON string to custom . Net object. In the following code, it calls the static method DeserializeObject() of the JsonConvert class by passing JSON data. It returns a custom object (BlogSites) from JSON data.


1 Answers

A very detailed explanation on how to handle this case is available at "Using a Custom JsonConverter to fix bad JSON results".

To summarize, you can extend the default JSON.NET converter doing

  1. Annotate the property with the issue

    [JsonConverter(typeof(SingleValueArrayConverter<OrderItem>))] public List<OrderItem> items; 
  2. Extend the converter to return a list of your desired type even for a single object

    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;     } } 

As mentioned in the article this extension is not completely general but it works if you are fine with getting a list.

like image 86
Camilo Martinez Avatar answered Sep 27 '22 20:09

Camilo Martinez