Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JSON deserialization - Map array indices to properties with JSON.NET

I want to deserialize a 2-dimensional array to a collection of .net objects. The reason is, array syntax will be easier for my user to work with in an input file. So I just want to map the indices of the arrays to specific properties of my target type.

E.G. With:

[
     ["John", "Smith", "23"],
     ["Paula", "Martin", "54]
]

I would get two instances of a Person:

public class Person {
    public string First {get;set;}
    public string Last {get;set;}
    public string Age {get;set;}
}

where index 0 of an inner array maps to First, index 1 maps to Last, and index 2 maps to Age;

Is there a way to extend Json.NET so that I can do the mapping during deserialization so the implementation details are hidden? I have been playing around with a custom JsonConverter but I haven't found much info on how to use it.

Edit: Specifically, I'm not sure if JsonConverter is the right thing to use, and I'm having trouble figuring out how to implement CanConvert and how to use the parameters passed to the ReadJson method.

like image 310
xr280xr Avatar asked Apr 21 '16 00:04

xr280xr


People also ask

How do I deserialize a JSON object?

Deserialization work is done in public override object ReadJson (JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) method. JSON is loaded to a NewtonSoft JObject and instance of result object is created.

How do I deserialize an object to an interface?

You can't deserialize something directly to an interface, You need a concrete class to instantiate. This can be done by following some easy steps. The Newtonsoft.json Nuget package allows you to serialize and deserialize objects into JSON. Install-Package Newtonsoft.Json

What are the default behaviors for jsonserializeroptions in ASP NET Core?

When you use System.Text.Json indirectly in an ASP.NET Core app, some default behaviors are different. For more information, see Web defaults for JsonSerializerOptions. By default, all public properties are serialized. You can specify properties to ignore. By default, JSON is minified. You can pretty-print the JSON.

Could not create an instance of type JSONserialization?

Could not create an instance of type JsonSerialization.IThing. Type is an interface or abstract class and cannot be instantated This means that the JSON deserializer has seen that there is a property of type IThing but doesn’t know what type of object it should create to populate it.


1 Answers

You can do this with a JsonConverter. A simple converter for this purpose would be:

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

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.Null)
            return null;
        var array = JArray.Load(reader);
        var person = (existingValue as Person ?? new Person());
        person.First = (string)array.ElementAtOrDefault(0);
        person.Last = (string)array.ElementAtOrDefault(1);
        person.Age = (string)array.ElementAtOrDefault(2);
        return person;
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var person = (Person)value;
        serializer.Serialize(writer, new[] { person.First, person.Last, person.Age });
    }
}

If the specific properties have non-primitive types, you can use JToken.ToObject<T>(JsonSerializer) to deserialize them to the required type:

person.First = array.ElementAtOrDefault(0)?.ToObject<string>(serializer);

Then you can apply it to your class:

[JsonConverter(typeof(PersonConverter))]
public class Person
{
    public string First { get; set; }
    public string Last { get; set; }
    public string Age { get; set; }
}

Or use it in settings:

var settings = new JsonSerializerSettings { Converters = new [] { new PersonConverter() } };
var list = JsonConvert.DeserializeObject<List<Person>>(json, settings);
like image 137
dbc Avatar answered Sep 20 '22 22:09

dbc