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

2

30

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);
    }
}
Immoral answered 29/4, 2014 at 13:40 Comment(0)
C
69

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; }
Cletus answered 29/4, 2014 at 14:49 Comment(2)
Instead of JsonProperty on the property, a cleaner approach is to use StringEnumConverter attribute over enum itself. I prefer it since my case I didn't want to have an alias to my property name and if we need to use ItemConverterType, then the only way is to use JsonProperty and unnecessary provide alias name.Hogback
What if it's a DataMember attribute?Tarry
H
18

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"
  ]
 }
Hogback answered 27/6, 2019 at 9:54 Comment(2)
Note it may not always be possible to decorate the enum directly with an attribute, e.g. if it is defined in a third-party library. A good example is System.Windows.Media.ColorsCletus
Not sure why but, JsonConverter attribute did not work for an array of enums when declared in the class but it worked when declared right in the enum definition.Nahtanha

© 2022 - 2024 — McMap. All rights reserved.