Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Serializing an object array to JSON

I have a type which is a wrapper over a dictionary - basically a key/value store. I would like to serialize an array of objects of this type to JSON. I am pretty new to JSON and Json.NET (newtonsoft.json).

My type has a method called - ToJson which serializes its dictionary to json as follows

public string ToJson()
{
  return JsonConvert.SerializeObject(this.values);
}    

And then I try to serialize an array of these objects

var json = JsonConvert.SerializeObject(objectArray)

Of course this does not work because each object in the array is serialized and I do not know how to direct the serialization process to my 'ToJson' method for each object.

I can get it to work exactly as I want it if I pass in an array of Dictionary objects.

Maybe I am missing some serialization attribute?

EDIT:

After reading some more documentation I tried a shorter way (before considering the JsonConverter approach) - using the 'JsonPropertyAttribute'. Applying it to the private Dictionary member almost did the job except that I also get the member name serialized, which I do not want. Any way to just serialize the member value and not the member name by using the JsonPropertyAttribute?

like image 412
alwayslearning Avatar asked Feb 07 '14 14:02

alwayslearning


1 Answers

In order to serialize your wrapper class such that its internal dictionary appears in the JSON as if the wrapper were not there, you need a custom JsonConverter. A JsonConverter gives you direct control over what gets serialized and/or deserialized for a particular class.

Below is a converter that should work for your case. Since you didn't really provide any details about your wrapper class other than it has a field called values to hold the dictionary, I used reflection to gain access to it. If your class has public methods to manipulate the dictionary directly, you can change the converter to use those methods instead, if you prefer. Here is the code:

class DictionaryWrapperConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return (objectType == typeof(MyWrapper));
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        MyWrapper wrapper = (MyWrapper)value;
        FieldInfo field = typeof(MyWrapper).GetField("values", BindingFlags.NonPublic | BindingFlags.Instance);
        JObject jo = JObject.FromObject(field.GetValue(wrapper));
        jo.WriteTo(writer);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JObject jo = JObject.Load(reader);
        MyWrapper wrapper = new MyWrapper();
        FieldInfo field = typeof(MyWrapper).GetField("values", BindingFlags.NonPublic | BindingFlags.Instance);
        field.SetValue(wrapper, jo.ToObject(field.FieldType));
        return wrapper;
    }
}

To tie the custom converter to your wrapper class, you can add a [JsonConverter] attribute to the class definition:

[JsonConverter(typeof(DictionaryWrapperConverter))]
class MyWrapper : IEnumerable
{
    Dictionary<string, string> values = new Dictionary<string, string>();

    public void Add(string key, string value)
    {
        values.Add(key, value);
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return values.GetEnumerator();
    }
}

Here is a full demo showing the converter in action, first serializing and deserializing a single instance of the wrapper class, then serializing and deserializing a list of wrappers:

class Program
{
    static void Main(string[] args)
    {
        MyWrapper wrapper = new MyWrapper();
        wrapper.Add("foo", "bar");
        wrapper.Add("fizz", "bang");

        // serialize single wrapper instance
        string json = JsonConvert.SerializeObject(wrapper, Formatting.Indented);

        Console.WriteLine(json);
        Console.WriteLine();

        // deserialize single wrapper instance
        wrapper = JsonConvert.DeserializeObject<MyWrapper>(json);

        foreach (KeyValuePair<string, string> kvp in wrapper)
        {
            Console.WriteLine(kvp.Key + "=" + kvp.Value);
        }
        Console.WriteLine();
        Console.WriteLine("----------\n");

        MyWrapper wrapper2 = new MyWrapper();
        wrapper2.Add("a", "1");
        wrapper2.Add("b", "2");
        wrapper2.Add("c", "3");

        List<MyWrapper> list = new List<MyWrapper> { wrapper, wrapper2 };

        // serialize list of wrappers
        json = JsonConvert.SerializeObject(list, Formatting.Indented);

        Console.WriteLine(json);
        Console.WriteLine();

        // deserialize list of wrappers
        list = JsonConvert.DeserializeObject<List<MyWrapper>>(json);

        foreach (MyWrapper w in list)
        {
            foreach (KeyValuePair<string, string> kvp in w)
            {
                Console.WriteLine(kvp.Key + "=" + kvp.Value);
            }
            Console.WriteLine();
        }
    }
}

Output:

{
  "foo": "bar",
  "fizz": "bang"
}

foo=bar
fizz=bang

----------

[
  {
    "foo": "bar",
    "fizz": "bang"
  },
  {
    "a": "1",
    "b": "2",
    "c": "3"
  }
]

foo=bar
fizz=bang

a=1
b=2
c=3
like image 174
Brian Rogers Avatar answered Oct 23 '22 00:10

Brian Rogers