4

Given the following nested JSON string:

string s = @"
{
    ""id"": 10,
    ""fields"":{
        ""issuetype"": {
            ""name"": ""Name of the jira item""
        }
    }
}";

How can I deserialize it to the following "flattened" class, using the JsonPropertyAttribute:

public class JiraIssue
{
    [JsonProperty("id")]
    public int Id { get; set; }
    [JsonProperty("fields/issuetype/name")]
    public string Type { get; set; }
}

I'm trying to specify a "navigation" rule based on / as a separator in the name of the JSON property.

Basically, I want to specify that JsonProperty("fields/issuetype/name") should be used as a navigation rule to the nested property fields.issuetype.name, which obviously does not work:

var d = Newtonsoft.Json.JsonConvert.DeserializeObject<JiraIssue>(s);
Console.WriteLine("Id:" + d.Id);
Console.WriteLine("Type" + d.Type);

The above recognizes only the Id:

Id: 10
Type:

What do I have to implement to tell Json.NET to use the "/" as a navigation path to the desired nested property?

Lucian
  • 3,981
  • 5
  • 30
  • 34

1 Answers1

3

This is One possible way -

internal class ConventionBasedConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return typeof(JiraIssue).IsAssignableFrom(objectType);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var daat = JObject.Load(reader);
        var ret = new JiraIssue();

        foreach (var prop in ret.GetType().GetProperties(BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Instance))
        {
            var attr = prop.GetCustomAttributes(false).FirstOrDefault();
            if (attr != null)
            {
                var propName = ((JsonPropertyAttribute)attr).PropertyName;
                if (!string.IsNullOrWhiteSpace(propName))
                {
                    var conventions = propName.Split('/');
                    if (conventions.Length == 3)
                    {
                        ret.Type = (string)((JValue)daat[conventions[0]][conventions[1]][conventions[2]]).Value;
                    }

                    ret.Id = Convert.ToInt32(((JValue)daat[propName]).Value);
                }                        
            }
        }


        return ret;
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {

    }
}

var settings = new JsonSerializerSettings();
settings.Converters.Add(new ConventionBasedConverter());
var o = JsonConvert.DeserializeObject<JiraIssue>(s, settings);
Amit Kumar Ghosh
  • 3,618
  • 1
  • 20
  • 24
  • 1
    Thanks a lot for this, your code was not working out of the box for me. I've fixed a couple of issues on it and made it in such a way that it will traverse any number of nodes. I've uploaded this gist if you want to look at the final version: https://gist.github.com/lucd/cdd57a2602bd975ec0a6 – Lucian Feb 25 '16 at 15:08
  • This is exactly what I wanted. You made my life easier. – suman Aug 28 '18 at 09:50