CSharp · Console
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();
}
}