Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I deserialize an array of enum using Json.Net?

I have a JSON like this:

[{ 
    "agencyId": "myCity",
    "road": {
    "note": "",
        "lat": "45.321",
        "lon": "12.21",
        "streetCode": "290",
        "street": "street1",
        "fromNumber": "",
        "toNumber": "",
        "fromIntersection": "",
        "toIntersection": ""
    },
    "changeTypes": ["PARKING_BLOCK", "ROAD_BLOCK"],
},]

and a class like this:

public class AlertRoad : BaseAlert
{
    [JsonProperty("agencyId")]
    [JsonConverter(typeof(StringEnumConverter))]
    public AgencyType AgencyId { get; set; }

    [JsonProperty("changeTypes")]
    [JsonConverter(typeof(StringEnumConverter))]
    public ChangeType[] ChangeTypes { get; set; }

    [JsonProperty("road")]
    public Road RoadInfo { get; set; }
}

AgencyType is an enumeration, and deserializiation and serialization for AgencyId works.

ChangeType is another enumeration, but deserializiation and serialization for ChangeTypes doesn't work. I assume the reason is that ChangeTypes is an array of enumeration values.

The question is: how can I deserialize/serialize ChangeTypes field, or in general an array of enumeration values?

I tried by defining my own field converter, called ChangeTypeConverter, and changing StrinEnumConverter to ChangeTypeConverter for ChangeTypes field, but in the ReadJson function the value of reader is null.

public class ChangeTypeConverter : JsonConverter
{
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {

    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var val = reader.Value;
        //val is null?!?
        return val;
    }

    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(ChangeType);
    }
}
like image 588
panizza Avatar asked Apr 29 '14 13:04

panizza


People also ask

Can JSON serialize enums?

In C#, JSON serialization very often needs to deal with enum objects. By default, enums are serialized in their integer form. This often causes a lack of interoperability with consumer applications because they need prior knowledge of what those numbers actually mean.

How do I deserialize an object in JSON?

NET objects (deserialize) A common way to deserialize JSON is to first create a class with properties and fields that represent one or more of the JSON properties. Then, to deserialize from a string or a file, call the JsonSerializer. Deserialize method.

How does Newtonsoft JSON deserialize work?

Newtonsoft. Json uses reflection to get constructor parameters and then tries to find closest match by name of these constructor parameters to object's properties. It also checks type of property and parameters to match. If there is no match found, then default value will be passed to this parameterized constructor.


2 Answers

The StringEnumConverter expects only a single enumeration value. Because ChangeTypes is an array, you need to annotate the property a little differently to make it work.

Try this instead:

[JsonProperty("changeTypes", ItemConverterType=typeof(StringEnumConverter))]
public ChangeType[] ChangeTypes { get; set; }
like image 76
Brian Rogers Avatar answered Oct 16 '22 14:10

Brian Rogers


There is no need to write a custom JsonConverter for serializing/deserializing array of Enum. Instead of decorating individual property within parent model, just decorate the Enum with a StringEnumConverter JsonConverter attribute.

For eg:-

Following Environment model has Shelter enum property and array of enum Shelter[]

public class Environment
{

    public string Name { get; set; }
    public Shelter Shelter { get; set; }
    public Shelter[] Shelters { get; set; }
}

[JsonConverter(typeof(StringEnumConverter))]
public enum Shelter
{
    Indoor,
    Outdoor
}

Output json:-

 {
   "name": "",
   "shelter": "Indoor",
    "shelters": [
       "Indoor",
       "Outdoor"
  ]
 }
like image 26
Jimit.Gandhi Avatar answered Oct 16 '22 14:10

Jimit.Gandhi