Search code examples
c#classserializationextendjson.net

how to get newtonsoft to deserialize yes and no to boolean


NOTE: I have provided the solution at the bottom of this feed.

I have a C# Win 8 app where I'm de-serializing some json that looks like this:

{
    'Unit': [
        {
            'name':'House 123',
            isAvailable:'no'
        },
        {
            'name':'House 456',
            isAvailable:'yes'
        }]
}

into a class that uses this interface:

public interface IUnit
{
    string Name { get; }
    bool isAvailable { get; }
}

But Newtonsoft throws an error:

Unexpected character encountered while parsing value: n. Path 'Unit[0].isAvailable, line 1, position 42.

Is there a way to extend Newtonsoft to parse yes/no or 1/0 based on the resulting object property type of bool? Right now it only works for true/false.

There are several posts on custom converters for classes, but not a primitive type like bool.

Any suggestions?


Solution

  • //This is what I came up with...

       using System;
     using System.Collections.Generic;
     using System.IO;
    using System.Linq;
    using Newtonsoft.Json;
    using Newtonsoft.Json.Linq;
    
    namespace NewtonTest
    {
    
    internal class NewtonTest
    {
        public class Data
        {
            public IEnumerable<IUnit> Unit { get; set; }
    
            public override string ToString()
            {
                return string.Format("Data{{Unit=[{0}]}}",
                    string.Join(", ", Unit.Select(c =>
                                    string.Format("{0} - Single Unit: {1}", 
                                        c.Name,
                                        c.isSingleUnit.ToString()))));
            }
        }
    
        public interface IUnit
        {
            string Name { get; }
    
            // [JsonConverter(typeof(Converter))]
            bool isSingleUnit { get; }
        }
    
        public class House : IUnit
        {
            public House(string name, bool isSingle)
            {
                this.Name = name;
                this.isSingleUnit = isSingle;
            }
    
            public string Name { get; private set; }
    
            public bool isSingleUnit { get; private set; }
        }
    
        public class Apartment : IUnit
        {
            public Apartment(string name, bool isSingle)
            {
                this.Name = name;
                this.isSingleUnit = isSingle;
            }
    
            public string Name { get; private set; }
    
            public bool isSingleUnit { get; private set; }
        }
    
        private static bool ConvertToBool(string value)
        {
            value =
                value.ToUpper().
                      Replace("YES", "TRUE").
                      Replace("Y", "TRUE").
                      Replace("1", "TRUE").
                      Replace("NO", "FALSE").
                      Replace("N", "FALSE").
                      Replace("0", "FALSE");
    
            bool result = false;
    
            bool.TryParse(value, out result);
    
            return result;
        }
    
    
        private class UnitConverter : Newtonsoft.Json.JsonConverter
        {
            public override bool CanConvert(Type objectType)
            {
                return typeof (NewtonTest.IUnit).IsAssignableFrom(objectType);
            }
    
            public override object ReadJson(Newtonsoft.Json.JsonReader reader, Type objectType, object existingValue,
                                            Newtonsoft.Json.JsonSerializer serializer)
            {
                JObject obj = serializer.Deserialize<JToken>(reader) as JObject;
    
                if (obj != null)
                {
                    string result = obj["isSingleUnit"].ToObject<string>();
    
                    bool isSingleUnit = ConvertToBool(result);
    
                    string name = obj["name"].ToObject<string>();
    
                    if (isSingleUnit)
                    {
                        return new NewtonTest.House(name, isSingleUnit);
                    }
                    else
                    {
                        return new NewtonTest.Apartment(name, isSingleUnit);
                    }
                }
                else
                {
                    return null;
                }
            }
    
            public override void WriteJson(Newtonsoft.Json.JsonWriter writer, object value,
                                           Newtonsoft.Json.JsonSerializer serializer)
            {
                throw new NotImplementedException();
            }
        }
    
    
        public static void Main()
        {
            Newtonsoft.Json.JsonSerializer serializer = new Newtonsoft.Json.JsonSerializer();
            serializer.Converters.Add(new UnitConverter());
            string json =
                "{'Unit':[{'name':'Apartment 123',isSingleUnit:'no'},{'name':'House 456',isSingleUnit:'yes'}]}".Replace(
                    '\'', '\"');
            var obj = serializer.Deserialize(new StringReader(json), typeof (Data));
            Console.WriteLine(obj);
            Console.ReadKey();
        }
    }
    }