[Fork] [Fork] [Fork] Deep Nested Object Properties Json Serialization

CSharp · Console

/Program.cs

using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

public class Program
{
    public static void Main()
    {
        var dataMapperModels = new List<DataMapper>();

        var model = new DataMapper
        {
            Name = "performanceLevels",
            SubDataMappers = new List<DataMapper>()
            {
                new DataMapper()
                {
                    Name = "performanceLevel_1",
                    SubDataMappers = new List<DataMapper>()
                    {
                        new DataMapper()
                        {
                            Name = "title",
                            DataMapperProperty = new DataMapperProperty()
                                    {
                                        Source = "column",
                                        SourceColumn = "title-column",
                                        DataType = "string",
                                        Default = "N/A",
                                        SourceTable = null,
                                        Value = null
                                    }
                        },
                        new DataMapper()
                        {
                            Name = "version",
                            DataMapperProperty = new DataMapperProperty()
                                    {
                                        Source = "column",
                                        SourceColumn = "version-column",
                                        DataType = "int",
                                        Default = "1",
                                        SourceTable = null,
                                        Value = null
                                    }
                        },
						new DataMapper()
                        {
                            Name = "threeLevels",
							SubDataMappers = new List<DataMapper>()
							{
								new DataMapper()
                        		{
									Name = "version",
									DataMapperProperty = new DataMapperProperty()
											{
												Source = "column",
												SourceColumn = "version-column",
												DataType = "int",
												Default = "1",
												SourceTable = null,
												Value = null
											}
								}
							}
                        }
                    }
                },
                new DataMapper()
                {
                    Name = "performanceLevel_2",
                    SubDataMappers = new List<DataMapper>()
                    {
                        new DataMapper()
                        {
                            Name = "title",
                            DataMapperProperty = new DataMapperProperty()
                                    {
                                        Source = "column",
                                        SourceColumn = "title-column",
                                        DataType = "string",
                                        Default = "N/A",
                                        SourceTable = null,
                                        Value = null
                                    }
                        },
                        new DataMapper()
                        {
                            Name = "version",
                            DataMapperProperty = new DataMapperProperty()
                                    {
                                        Source = "column",
                                        SourceColumn = "version-column",
                                        DataType = "int",
                                        Default = "1",
                                        SourceTable = null,
                                        Value = null
                                    }
                        }
                    }
                }
            }
        };


        dataMapperModels.Add(model);
		
		var settings = new JsonSerializerSettings()
        {
			Converters = new List<JsonConverter> { new DataMapperListConverter() },
            Formatting = Formatting.Indented
        };

        var jsonMap = JsonConvert.SerializeObject(dataMapperModels, settings);
        Console.WriteLine(jsonMap);
		Console.WriteLine("\n------------------------------");
		
		var list = JsonConvert.DeserializeObject<List<DataMapper>>(jsonMap, settings);
		Dump(list);
    }

	private static void Dump(List<DataMapper> list, string indent = "")
	{
	    foreach (DataMapper mapper in list)
		{
			Console.WriteLine();
		    Console.WriteLine(indent + "Name: " + mapper.Name);
			if (mapper.DataMapperProperty != null)
			{
			    Console.WriteLine(indent + "DataType: " + mapper.DataMapperProperty.DataType);
			    Console.WriteLine(indent + "Source: " + mapper.DataMapperProperty.Source);
			    Console.WriteLine(indent + "SourceColumn: " + mapper.DataMapperProperty.SourceColumn);
			    Console.WriteLine(indent + "Default: " + mapper.DataMapperProperty.Default);
			}
			if (mapper.SubDataMappers != null && mapper.SubDataMappers.Count > 0)
			{
				Console.WriteLine(indent + "SubMappers:");
				Dump(mapper.SubDataMappers, indent + "   ");
			}
		}
	}
}


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

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        List<DataMapper> list = (List<DataMapper>)value;
        if (list.Any(dm => dm.DataMapperProperty != null))
        {
            JObject obj = new JObject(list.Select(dm =>
            {
                JToken val;
                if (dm.DataMapperProperty != null)
                    val = JToken.FromObject(dm.DataMapperProperty, serializer);
                else 
                    val = JToken.FromObject(dm.SubDataMappers, serializer);
                return new JProperty(dm.Name, val);
            }));
            obj.WriteTo(writer);
        }
        else
        {
            serializer.Serialize(writer,
                list.Select(dm => new Dictionary<string, List<DataMapper>>
                {
                    { dm.Name, dm.SubDataMappers }
                }));
        }
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JToken token = JToken.Load(reader);
        if (token.Type == JTokenType.Object)
        {
            return token.Children<JProperty>()
                 .Select(jp => 
                 {
                     DataMapper mapper = new DataMapper { Name = jp.Name };
                     JToken val = jp.Value;
                     if (val["data-type"] != null)
                         mapper.DataMapperProperty = jp.Value.ToObject<DataMapperProperty>(serializer);
                     else
                         mapper.SubDataMappers = jp.Value.ToObject<List<DataMapper>>(serializer);
                     return mapper;
                 })
                 .ToList();
        }
        else if (token.Type == JTokenType.Array)
        {
            return token.Children<JObject>()
                .SelectMany(jo => jo.Properties())
                .Select(jp => new DataMapper
                {
                    Name = jp.Name,
                    SubDataMappers = jp.Value.ToObject<List<DataMapper>>(serializer)
                })
                .ToList();
        }
        else
        {
            throw new JsonException("Unexpected token type: " + token.Type.ToString());
        }
    }
}



public class DataMapper
{
    public DataMapper()
    {
        SubDataMappers = new List<DataMapper>();
    }

    [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
    public string Name { get; set; }

    [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
    public DataMapperProperty DataMapperProperty { get; set; }

    [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
    public List<DataMapper> SubDataMappers { get; set; }
}

public class DataMapperProperty
{
    [JsonProperty(PropertyName = "data-type", NullValueHandling = NullValueHandling.Ignore)]
    public string DataType { get; set; }

    [JsonProperty(PropertyName = "source", NullValueHandling = NullValueHandling.Ignore)]
    public string Source { get; set; }

    [JsonProperty(PropertyName = "source-column", NullValueHandling = NullValueHandling.Ignore)]
    public string SourceColumn { get; set; }

    [JsonProperty(PropertyName = "source-table", NullValueHandling = NullValueHandling.Ignore)]
    public string SourceTable { get; set; }

    [JsonProperty(PropertyName = "default", NullValueHandling = NullValueHandling.Ignore)]
    public string Default { get; set; }

    [JsonProperty(PropertyName = "value", NullValueHandling = NullValueHandling.Ignore)]
    public string Value { get; set; }

    public static explicit operator DataMapperProperty(JToken v)
    {
        return new DataMapperProperty()
        {
            DataType = v.Value<string>("data-type"),
            Source = v.Value<string>("source"),
            SourceColumn = v.Value<string>("source-column"),
            SourceTable = v.Value<string>("source-table"),
            Default = v.Value<string>("default"),
            Value = v.Value<string>("value")
        };
    }
}
;