skip to Main Content

I have two JSON files: One for Locations, another for Objects at a location.

locations.json =>

[
  {
    "Name": "Location#1",
    "X": 0,
    "Y": 20
  },
  {
    "Name": "Location#2",
    "X": 0,
    "Y": 19
  },
  ...
]

objects.json ==>

[
  {
    "Name": "Piano",
    "CurrentLocation": "Location#1"
  },
  {
    "Name": "Violin",
    "CurrentLocation": "Location#2"
  },
  ...
]

The objects.json references the locations instances using the location names.

I have two classes that this deserializes to (or serializes from):

public class ObjectOfInterest
{
    [JsonPropertyName("Name")]  
    public string Name { get; set; } = string.Empty;

    [JsonPropertyName("CurrentLocation")]
    public LocationNode CurrentLocation { get; set; } = new()
}

public class Location
{
    [JsonPropertyName("Name")]  
    public string Name { get; set; } = string.Empty;

    [JsonPropertyName("X")]
    public float X { get; set; }

    [JsonPropertyName("Y")]
    public float Y { get; set; }
}

How do I create a custom JSONSerializer or Converter that takes the string Location name JSON attribute, and assigns the correct location instance to the Objects class?

2

Answers


  1. Chosen as BEST ANSWER

    It turns out that the JSON Converter was overkill. I ended up indexing the locations by their Name. And then making an additional public string type that mapped to the indexed private Location type (renamed to _currentLocation since we can't have two properties with the same name) I needed.

    private Location _currentLocation = new();
    
    [JsonPropertyName("CurrentLocation")]
    public string CurrentLocation {
        get => _currentLocation.Name; 
        set {
            _currentLocation = LocationIndexer.Locations[value];
        }
    }
    

  2. Add a JsonConverterAttribute to the CurrentLocation property

    public class ObjectOfInterest
    {
        [JsonPropertyName("Name")]
        public string Name { get; set; } = string.Empty;
    
        [JsonPropertyName("CurrentLocation")]
        [JsonConverter(typeof(LocationConverter))]
        public Location CurrentLocation { get; set; } = new();
    }
    

    The converter should store the locations indexed by their name:

    public class LocationConverter : JsonConverter<Location>
    {
        private readonly Dictionary<string, Location> _locationDictionary = new();
    
        public LocationConverter(IEnumerable<Location> locations)
        {
            foreach (var location in locations)
            {
                _locationDictionary[location.Name] = location;
            }
        }
    
        public override Location Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
            string locationName = reader.GetString();
            if (_locationDictionary.TryGetValue(locationName, out Location location))
            {
                return location;
            }
    
            throw new KeyNotFoundException($"Location '{locationName}' not found.");
        }
    
        public override void Write(Utf8JsonWriter writer, Location value, JsonSerializerOptions options)
        {
            writer.WriteStringValue(value.Name);
        }
    }
    

    Finaly, you can use the LocationConverter like that:

    var locations = JsonSerializer.Deserialize<Location[]>(locationsJson);
    var options = new JsonSerializerOptions();
    options.Converters.Add(new LocationConverter(locations));
    var objects = JsonSerializer.Deserialize<ObjectOfInterest[]>(objectsJson, options);
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search