Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Apply a converter to all elements in Json Array

Tags:

c#

json.net

One can use custom converters by defining a class like this:

public class MyCustomConverter : JsonConverter
{

    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(MyCustomType);
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var ret = new MyCustomType();
        return ret;
    }
}

And then using it like this:

MyCustomType item = JsonConvert.DeserializeObject<MyCustomType>(jsonString, new MyCustomTypeConverter());

My question is, how can I apply this deserializer when dealing with a list of MyCustomType? Basically I have a Json array ([{ ... }, { ... }]) and I would like to use the converter above on each item of the array to get a List<MyCustomType>.

I know I can do it by hand using the JArray object and its methods but I was wondering if there was an easier and cleaner way to do it.


Here's a simplified context.

C# (I want to deserialize a List of those):

class MyCustomType
{
    public Dictionary<string, string> Data
    {
        get;
        set;
    }
    public int Id
    {
        get;
        set;
    }
}

JSON (one item in the array sample):

{
    "Id": 50,
    "Data": [
        "Hello",
        "World"
    ]
}

C# Deserialization I want to apply:

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
    var ret = new MyCustomType();
    ret.Data = new Dictionary<string, string>();
    while (reader.Read())
    {
        if (reader.TokenType == JsonToken.EndObject)
        {
            continue;
        }

        var value = reader.Value.ToString();
        switch(value)
        {
            case "Id":
                ret.Id = reader.ReadAsInt32().Value;
                break;
            case "Data":
                ret.Data.Add(MySingleton.Instance.CurrentLanguage, reader.ReadAsString());
                break;
        }
    }
    return ret;
}
like image 510
Max Avatar asked Jan 11 '23 05:01

Max


2 Answers

While L.B's answer works, there are cases where a converter is indeed necessary - for instance, when you don't ever get to touch the raw JSON and only get to attribute ASP.NET methods that will be accessible to HTTP requests.

In that case, you can use the JsonPropertyAttribute class and assign a value to its ItemConverterType property:

[JsonProperty(ItemConverterType = typeof(MyCustomConverter))]
public List<MyCustomType> Items { get; set; }
like image 93
O. R. Mapper Avatar answered Jan 24 '23 06:01

O. R. Mapper


var obj = JsonConvert.DeserializeObject<MyCustomType>(json);

if your json is an array then use

var obj = JsonConvert.DeserializeObject<List<MyCustomType>>(json);

And if you can change the type of Data to List<string>, you don't even need jsonConverter


public class MyCustomType
{
    public int Id { get; set; }
    [JsonConverter(typeof(MyCustomConverter))]
    public Dictionary<string, string> Data { get; set; }
}

public class MyCustomConverter : JsonConverter
{

    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(MyCustomType);
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        // read the string array and convert it to dictionary 
        // as declared in your MyCustomType
        var arr = serializer.Deserialize<List<string>>(reader);
        return arr.ToDictionary(x => x, x => x);
    }
}

EDIT

Just deserialize as

var yourObj = JsonConvert.DeserializeObject<MyCustomType.Rootobject>(yourjson);

public class MyCustomType
{

    public class Rootobject
    {
        public Datum[] data { get; set; }
    }

    public class Datum
    {
        public string id { get; set; }
        public string al { get; set; }
        public string[] datapsi { get; set; }
        public string[] tags { get; set; }
        public string partype { get; set; }
        public Info info { get; set; }
        public Factors factors { get; set; }
        public Espace[] espace { get; set; }
        public Annex Annex { get; set; }
    }

    public class Info
    {
        public string nopub { get; set; }
        public int nodem { get; set; }
    }

    public class Factors
    {
        public int a { get; set; }
        public float b { get; set; }
        public int c { get; set; }
        public float d { get; set; }
        public int e { get; set; }
        public float f { get; set; }
        public float g { get; set; }
        public int h { get; set; }
        public int i { get; set; }
        public int j { get; set; }
        public int k { get; set; }
        public int l { get; set; }
        public float m { get; set; }
        public int n { get; set; }
        public int o { get; set; }
        public int p { get; set; }
        public float q { get; set; }
        public float r { get; set; }
        public int s { get; set; }
        public float t { get; set; }
    }

    public class Annex
    {
        public string name { get; set; }
        public Image image { get; set; }
    }

    public class Espace
    {
        public string id { get; set; }
        public string description { get; set; }
        public Datatip datatip { get; set; }
        public Image image { get; set; }
        public string resource { get; set; }
        public int delta { get; set; }
        public int[] target { get; set; }
        public string targetType { get; set; }
        public string targetOneLined { get; set; }
        public int[] alx { get; set; }
        public string alxOneLined { get; set; }
        public int[][] damps { get; set; }
        public string[] dampsOneLined { get; set; }
        public Var[] vars { get; set; }
        public object misc { get; set; }
        public string miscOneLined { get; set; }
    }

    public class Datatip
    {
        public string[] label { get; set; }
        public string[] damps { get; set; }
    }

    public class Image
    {
        public string full { get; set; }
        public string sprite { get; set; }
        public string group { get; set; }
        public int x { get; set; }
        public int y { get; set; }
        public int w { get; set; }
        public int h { get; set; }
    }

    public class Var
    {
        public string key { get; set; }
        public string link { get; set; }
        public float coeff { get; set; }
    }
}
like image 26
L.B Avatar answered Jan 24 '23 05:01

L.B