Roberto
Roberto

Reputation: 11

Deserializing some JSON properties to a child object with Newtonsoft.Json

I have this string in JSON format:

{
    "hr": "12:56",
    "vs": [
        {
            "pre": "73833",
            "a": true,
            "posx": "-46.688962875",
            "posy": "-23.632046625"
        },
        {
            "pre": "73722",
            "a": true,
            "posx": "-46.773388125",
            "posy": "-23.68939025"
        }                               
    ]
}

I want to deserialize the JSON to this class:

public class Tracking
{
    [JsonProperty(PropertyName = "hr")]
    public string Hour { get; set; }

    [JsonProperty(PropertyName = "vs")]
    public IList<Vehicle> Vehicles { get; set; }
}

The Vehicle class currently has the following attributes:

public class Vehicle
{
    [JsonProperty (PropertyName = "pre")]
    public string Prefix {get; set; }

    [JsonProperty (PropertyName = "posx")]
    public string Y {get; set; }

    [JsonProperty (PropertyName = "posy")]
    public string X {get; set; }
}

Instead, I would like to deserialize the posx and posy attributes into a child class called Position with X and Y properties:

public class Position
{
    [JsonProperty (PropertyName = "posx")]
    public string Y {get; set; }

    [JsonProperty (PropertyName = "posy")]
    public string X {get; set; }
}

Resulting in the following Vehicle class:

public class Vehicle
{
    [JsonProperty (PropertyName = "pre")]
    public string Prefix {get; set; }

    public Position Position {get; set; }
}

I intend to use the Position class on more places on my system and would not like to repeat these properties. But when deserializing with the new structure, the Position property returns null.

{
    "hr": "13:08",
    "vs": [
        {
            "pre": "73833",
            "a": true,
            "Position": null
        },
        {
            "pre": "73722",
            "a": true,
            "Position": null
        }    
    ]
}

What can I do to make this code work?

Upvotes: 0

Views: 3642

Answers (2)

Brian Rogers
Brian Rogers

Reputation: 129687

There are a couple of ways you can achieve the result you want.
The quickest way is to make a couple of changes to your original Vehicle class:

  1. Add a new Position property and mark it with [JsonIgnore]
  2. Make the X and Y properties private and change them so that they write to, and read from, the Position object.

The resulting class should look like this:

public class Vehicle
{
    [JsonProperty(PropertyName = "pre")]
    public string Prefix { get; set; }

    [JsonIgnore]
    public Position Position { get; set; }

    [JsonProperty(PropertyName = "posx")]
    private string Y
    {
        get { return Position != null ? Position.Y : null; }
        set
        {
            if (Position == null) { Position = new Position(); }
            Position.Y = value;
        }
    }

    [JsonProperty(PropertyName = "posy")]
    private string X
    {
        get { return Position != null ? Position.X : null; }
        set
        {
            if (Position == null) { Position = new Position(); }
            Position.X = value;
        }
    }
}

Demo fiddle: https://dotnetfiddle.net/5zT5Rf


If you don't like that idea, another option is to make a custom JsonConverter for your Vehicle class:

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

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JObject obj = JObject.Load(reader);
        Vehicle veh = new Vehicle();
        serializer.Populate(obj.CreateReader(), veh);
        Position pos = new Position();
        serializer.Populate(obj.CreateReader(), pos);
        veh.Position = pos;
        return veh;
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        Vehicle veh = (Vehicle)value;
        JObject obj = JObject.FromObject(veh.Position, serializer);
        obj.AddFirst(new JProperty("pre", veh.Prefix));
        obj.WriteTo(writer);
    }
}

Then, mark your Vehicle class with a [JsonConverter] attribute to tie it to the converter:

[JsonConverter(typeof(VehicleConverter))]
public class Vehicle
{
    [JsonProperty(PropertyName = "pre")]
    public string Prefix { get; set; }

    public Position Position { get; set; }
}

Demo fiddle: https://dotnetfiddle.net/HRSRa9

Upvotes: 1

torsan
torsan

Reputation: 489

If you use Newtonsoft you should be able to deserialize using Vehicle myVehicle = JsonConvert.DeserializeObject<Vechicle)(myString) given that:

  • You are using the class at the bottom of your post.
  • You are deserializing Json serialized from that class. If you have older Json from your previous Vehicle class that won't work, unless you handle that case specifically (if first deserialization fails try the old class, if that succeds convert it to the new Vehicle class.

Upvotes: 0

Related Questions