0

I have a JSON file containing lines like this:

{"id":"0258","name":"Canterbury","coordinates":[1.07992,51.27904]}

The coordinates item is the geographic coordinates of the city. However it is stored as an array which always contains the [longitude, latitude].

I want to deserialize these entries into C# POCO classes that are defined like this:

    public sealed class City
        {
        [JsonPropertyName("name")]
        public string Name { get; set; }

        [JsonPropertyName("coordinates")]
        public GeographicLocation Location { get; set; }
        }

    public sealed class GeographicLocation
        {
        public GeographicLocation(double latitude, double longitude)
            {
            Latitude = latitude;
            Longitude = longitude;
            }

        public double Latitude { get; private set; }
        public double Longitude { get; private set; }
        }

I think you can see where I'm going with that.

Is there a way of annotating these classes so that the source JSON will deserialize correctly into my desired object graph?

I'm currently using System.Text.Json but would switch to Newtonsoft.Json in a heartbeat if it has a better solution.

Clarification

I know how to deserialize JSON to a class, where there's a correspondence between JSON elements and class properties. The essential problem here is that the source JSON file contains a 2-element array which I'd like to end up in properties of my deserialized class, rather than in a single array property. I don't know how to accomplish that.

Tim Long
  • 13,508
  • 19
  • 79
  • 147
  • Does this help? https://stackoverflow.com/questions/25052293/deserialize-json-to-c-sharp-classes Or this? https://stackoverflow.com/questions/42110098/deserialize-json-to-class-in-c-sharp – Rufus L May 01 '20 at 18:29
  • @RufusL Not really, since neither of them addresses my question. I know how to deserialize to a class where all the JSON properties match the class properties, but I don't know how to deserialize a JSON array to properties of a class. – Tim Long May 01 '20 at 18:32
  • 1
    You can write custom [JsonConverter](https://www.newtonsoft.com/json/help/html/CustomJsonConverter.htm) – Guru Stron May 01 '20 at 18:36
  • If there isn't a simple way to do this, I'm tempted to just use an editor to do a search-and-replace of the input file, which is a static file that will never change. – Tim Long May 01 '20 at 18:38
  • Newtonsoft has the idea of a [Custom JsonConverterr](https://www.newtonsoft.com/json/help/html/CustomJsonConverterGeneric.htm) that would allow you to implement a class that would convert that array into a new `GeographicLocation` instance. – Heretic Monkey May 01 '20 at 18:39

1 Answers1

2

As was mentioned above, you can use custom JsonConverter<>. A simple solution would look like this:

public class GeographicLocationJsonConverter : JsonConverter<GeographicLocation>
    {
        public override GeographicLocation ReadJson(JsonReader reader, Type objectType, [AllowNull] GeographicLocation existingValue, bool hasExistingValue, Newtonsoft.Json.JsonSerializer serializer)
        {
            var token = JArray.Load(reader);
            var values = token.ToObject<List<double>>();
            return new GeographicLocation(values[0], values[1]);
        }

        public override void WriteJson(JsonWriter writer, [AllowNull] GeographicLocation value, Newtonsoft.Json.JsonSerializer serializer)
        {
            var jArray = new JArray(new double[] { value.Latitude, value.Longitude });
            jArray.WriteTo(writer);
        }
    }

Usage:

        var city = new City()
        {
            Location = new GeographicLocation(1, 2),
            Name = "Zhytomyr"
        };

        var converter = new GeographicLocationJsonConverter();

        var json = JsonConvert.SerializeObject(city, converter);

        var deserializedCity = JsonConvert.DeserializeObject<City>(json, converter);
  • 1
    Awesome, thank you. You deserve to get a much higher reputation for giving useful and complete answers like that. This should bump you up a bit :) [41 -> 66] – Tim Long May 01 '20 at 19:52