2

I have the following json:

{
   "issue" : 
   {
      "id": 1,
      "project":
      {
         "id":1,
         "name":"name of project"
      }
   }
}

I'm trying to deserialize this json to the follwing class:

public class Issue
{
    public int? id { get; set; }
    public int project_id { get; set; }
    public string project_name { get; set; }
}

Theres a way to get the child attribute and set to the father?

Adolfok3
  • 304
  • 3
  • 14
  • First Deserialise json it's according class. then map it to your object. – Drag and Drop May 16 '18 at 12:56
  • Something like this : https://stackoverflow.com/a/32783339/6560478. there is a lot of dupe around, and a lot of way to do it. – Drag and Drop May 16 '18 at 12:57
  • Deserialise does not work, the project_id value is never setted in deserialise. – Adolfok3 May 16 '18 at 13:00
  • "**its** according class" I mean used [Json2Csharp](http://json2csharp.com/) or Visualstudio special paste , to find the right class. you have a json kinda a textual representation of an object. if you want an other object you have to : 1 load the object from its representation (deserialise) then map to the new object. – Drag and Drop May 16 '18 at 13:05

4 Answers4

2

One of the simplest solution is to convert to JObject and using that creates the the required object from it.

var jObject = JsonConvert.DeserializeObject<JObject>(text);

var issue = new Issue() {id = (int?)jObject["issue"]["id"], project_id = (int)jObject["issue"]["project"]["id"], project_name = (string)jObject["issue"]["project"]["name"]};

Below code does the mentioned:

using System;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

public class Issue
{
    public int? id { get; set; }
    public int project_id { get; set; }
    public string project_name { get; set; }

    public override string ToString()
    {
        return "Id: " + id + " project Id: " + project_id + " project name : " + project_name;
    }
}


public class Program
{
    public static void Main()
    {
        var text = "{ \"issue\" :  { \"id\": 1, \"project\": { \"id\": 2, \"name\":\"name of project\" }}}";

        var jObject = JsonConvert.DeserializeObject<JObject>(text);

        var issue = new Issue() {id = (int?)jObject["issue"]["id"], project_id = (int)jObject["issue"]["project"]["id"], project_name = (string)jObject["issue"]["project"]["name"]};
        Console.WriteLine(issue);
    }
}

You can check the Live demo here.

user1672994
  • 10,509
  • 1
  • 19
  • 32
0

You need to create new Class for project :

Issue Class :

public class Issue
{
    public int id { get; set; }
    public Project project { get; set; }
}

Project Class :

public class Project
{
    public int id { get; set; }
    public String name { get; set; }
}

If you really need to have project_id and project_name in your Issue Class, you can do this :

public class Issue
{
    public int id { get; set; }
    public Project project { get; set; }

    public int getProjectId() {
        return this.getProject.getId;
    }
    //Do the same for projectName
}

Hope this help.

LaPoule
  • 324
  • 1
  • 11
  • 1
    OP wants the project properties to be part of the base object, not to create a new one. – DavidG May 16 '18 at 12:55
  • Your JSONObject `Issue` attribut have a `project` JSONObject. So, your `project.id` and `project.name` are attributs of `project` – LaPoule May 16 '18 at 13:02
  • yes, I'm looking for something like : JsonProperty("project/id"). But this do does not work. – Adolfok3 May 16 '18 at 13:21
  • @JsonProperty("yourValueName") to set your name to use before your getter. Ex : @JsonProperty("nameToUse") public String getAnotherName() {} //return the "nameToUse" attribut See : https://github.com/FasterXML/jackson-annotations/wiki/Jackson-Annotations – LaPoule May 16 '18 at 13:54
0

Here is a way to do that

And here is the code

public class ConventionBasedConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return typeof(YOUR-OBJECT).IsAssignableFrom(objectType);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var daat = JObject.Load(reader);
        var yourObject = new YOUR-OBJECT();

        foreach (var prop in yourObject 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))
                {
                    //split by the delimiter, and traverse recursevly according to the path
                    var conventions = propName.Split('/');
                    object propValue = null;
                    JToken token = null;
                    for (var i = 0; i < conventions.Length; i++)
                    {
                        if (token == null)
                        {
                            token = daat[conventions[i]];
                        }
                        else {
                            token = token[conventions[i]];
                        }
                        if (token == null)
                        {
                            //silent fail: exit the loop if the specified path was not found
                            break;
                        }
                        else
                        {
                            //store the current value
                            if (token is JValue)
                            {
                                propValue = ((JValue)token).Value;
                            }
                        }
                    }

                    if (propValue != null)
                    {
                        //workaround for numeric values being automatically created as Int64 (long) objects.
                        if (propValue is long && prop.PropertyType == typeof(Int32))
                        {
                            prop.SetValue(yourObject, Convert.ToInt32(propValue));
                        }
                        else
                        {
                            prop.SetValue(yourObject, propValue);
                        }
                    }
                }
            }
        }
        return yourObject;
    }

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

Then use it like:

 var settings = new JsonSerializerSettings();
 settings.Converters.Add(new ConventionBasedConverter());
 JsonConvert.DeserializeObject<YOUR-OBJECT>(jsonString, settings);
Hesam Faridmehr
  • 1,176
  • 8
  • 20
0

Here is another way to do it. With Cinchoo ETL - an open source library along with JSON path, you can do the deserialization with few lines of code

public class Issue
{
    [ChoJSONRecordField(JSONPath = "$..id")]
    public int? id { get; set; }
    [ChoJSONRecordField(JSONPath = "$..project.id")]
    public int project_id { get; set; }
    [ChoJSONRecordField(JSONPath = "$..project.name")]
    public string project_name { get; set; }
}

static void Sample33()
{
    string json = @"{
       ""issue"" : 
       {
          ""id"": 1,
          ""project"":
          {
             ""id"":1,
             ""name"":""name of project""
          }
       }
    }";
    var issue = ChoJSONReader<Issue>.LoadText(json).First();
}

Disclaimer: I'm the author of this library.

Cinchoo
  • 6,088
  • 2
  • 19
  • 34