questions/42274847/how-to-return-null-from-jsonconvert-deserializeobject

CSharp · Console

/Program.cs

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Collections.ObjectModel;
using System.Reflection;
using System.Runtime.Serialization;
using System.Data;
using System.Xml;

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;


namespace Question42274847
{
    // https://stackoverflow.com/questions/42274847/how-to-return-null-from-jsonconvert-deserializeobject
    public class ReturnNullConverter<T> : JsonConverter
    {
        public override bool CanConvert(Type objectType)
        {
            return typeof(T).IsAssignableFrom(objectType);
        }

        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            if (reader.TokenType == JsonToken.Null)
                return null;

            // Get the contract.
            var contract = (JsonObjectContract)serializer.ContractResolver.ResolveContract(objectType);

            // Allocate the object (it must have a parameterless constructor)
            existingValue = existingValue ?? contract.DefaultCreator();

            // Populate the values.
            serializer.Populate(reader, existingValue);

            // This checks for all properties being null.  Value types are never null, however the question
            // doesn't specify a requirement in such a case.  An alternative would be to check equality
            // with p.DefaultValue
            // http://www.newtonsoft.com/json/help/html/P_Newtonsoft_Json_Serialization_JsonProperty_DefaultValue.htm
            if (contract.Properties
                .Where(p => p.Readable)
                .All(p => object.ReferenceEquals(p.ValueProvider.GetValue(existingValue), null)))
                return null;

            return existingValue;
        }

        public override bool CanWrite { get { return false; } }

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

    public class CustomResponse
    {
        [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
        public string Message { get; set; }
        [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
        public string Details { get; set; }
    }

    public class CustomResponseSubClass : CustomResponse
    {
        public int SomeInt { get; set; }
    }

    internal class TestClass
    {
        internal static void Test()
        {
            Test<CustomResponse>("{}", true);
            Test<CustomResponse>("{Message: null}", true);
            Test<CustomResponse>("{Details: null}", true);
            Test<CustomResponse>(@"{""DocumentId"":""123321"", ""DocumentNumber"":""ABC123""}", true);
            Test<CustomResponse>("{Message: \"a\"}", false);
            Test<CustomResponse>("{Details: \"a\", Message: null}", false);
            Test<CustomResponseSubClass>("{}", false);

            Console.WriteLine("All tests passed");
        }

        static void Test<T>(string jsonString, bool shouldBeNull) where T : CustomResponse
        {
            var settings = new JsonSerializerSettings
            {
                NullValueHandling = NullValueHandling.Ignore,
                MissingMemberHandling = MissingMemberHandling.Ignore,
                Converters = { new ReturnNullConverter<CustomResponse>() },
            };
            var customResponse = JsonConvert.DeserializeObject<T>(jsonString, settings);
            Assert.IsTrue((customResponse == null) == shouldBeNull);

            Console.WriteLine("Correctly deserialized \"{0}\" to {1}", jsonString, shouldBeNull ? "null" : "a non-null object of type " + typeof(T).Name);
        }
    }

    public class AssertionFailedException : System.Exception
    {
        public AssertionFailedException() : base() { }

        public AssertionFailedException(string s) : base(s) { }
    }

    public static class Assert
    {
        public static void IsTrue(bool value)
        {
            if (value == false)
                throw new AssertionFailedException("failed");
        }
    }
}

public class Program
{
	public static void Main()
	{
		Console.WriteLine("Json.NET version: " + typeof(JsonSerializer).Assembly.FullName);
		Console.WriteLine("");
		
		Question42274847.TestClass.Test();
	}
}
;