Search code examples
c#.netjson.net

Use JsonConverter to deserialize JToken to bool


I have an odd JSON object I need to deserialize.

{
  "data": {
    "id": 123,
    "permissions": {
      "appName": {
        "data": {
          "1": {
            "2021-08-01": {
              "2020": {
                "isAllowed": {}
              }
            }
          }
        }
      }
    }
  }
}

I've gotten most of it to work with a wrapper and nested dictionaries but the final part isn't working as expected. It works fine if I create a class like this, but using it is clunky.

public class DataWrapper<T>
{
   public T Data { get; set;}
}

public class PermissionValues
{
   public JToken IsAllowed { get; set; }
}

DataWrapper<Dictionary<int, Dictionary<DateTime, Dictionary<int, PermissionValues>>>>

I'd like to change JToken to a bool. When I do that and add a JsonConverter

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
    return true; //{} is true but JSON.net parses as null, old was: reader.Value != null;
}

I get an error:

Newtonsoft.Json.JsonSerializationException: 'Could not convert string 'isAllowed' to dictionary key type 'System.Int32'. Create a TypeConverter to convert from the string to the key type object. Path 'data.permissions.appName.data.1.2021-08-01.2020.isAllowed'

Any idea what I am missing?


Solution

  • Use JToken.ToObject()

    string json = "{\"data\":{\"id\":123,\"permissions\":{\"appName\":{\"data\":{\"1\":{\"2021-08-01\":{\"2020\":{\"isAllowed\":{}}}}}}}}}";
    var jToken= JToken.Parse(json).SelectToken("$.data.permissions.appName");
    var result = jToken.ToObject<DataWrapper<Dictionary<int, Dictionary<DateTime, Dictionary<int, PermissionValues>>>>>();
    

    Use the JsonConvertor Attribute on IsAllowed Property.

    public class DataWrapper<T>
    {
        public T Data { get; set; }
    }
    
    public class PermissionValues
    {
        [JsonConverter(typeof(BoolConverter))]
        public bool IsAllowed { get; set; }
    }
    
    
    public class BoolConverter : JsonConverter
    {
        //Implement other abstract functions
    
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            return reader.Value != null;
        }
    
        public override bool CanConvert(Type objectType)
        {
            return objectType == typeof(bool);
        }
    }