Newtonsoft.Json
Newtonsoft.Json copied to clipboard
DeserializeObject<Object> with empty string returns unexpected null
Source/destination types
public class TestsEmptyString
{
public string str { get; set; }
}
Source/destination JSON
"\"\""
Expected behavior
var str = """"; var test = JsonConvert.DeserializeObject<TestsEmptyString>(str); Should throw an exception / go to a custom TypeConverter if there is any. In my case, I have a TypeConverter that takes the string and creates TestsEmptyString object with str set as the string. This works every time except in the case of """". For example ""foo"" gets to my TypeConverter ConvertFrom and CanConvertFrom methods But """" just returns null without getting to that converter.
Please note that any other string like ""foo"" will behave differently than """". Also, my project is configured with nullable annotation context enabled which makes TestsEmptyString not nullable, so I don't understand how it even works.
Actual behavior
returns null to a non-nullble object
Steps to reproduce
var str = "\"\"";
var test = JsonConvert.DeserializeObject<TestsEmptyString>(str); // returns null
var otherStr = "\"foo\"";
var test = JsonConvert.DeserializeObject<TestsEmptyString>(otherStr); // throws an exception
I would like to stress one point here - since C# we have nullable reference types in the language. If the assembly calling to Newtonsoft has opted in to nullable aware context, then 'null' is no longer a legitimate value for a string type from the developers' perspective.
Thus the empty string coersing behavior of Newtosoft.Json performed by CoerceEmptyStringToNull() method (as mentioned in #1687) is seriously wrong as the one that makes C# string not round-tripable, if the nullable annotation context is enabled.
I have a similar problem. I have a type with required fields. I'd want to rely on json serializer to throw serialization exception if it can't correctly deserialize required fields, but an empty string doesn't trigger serialization exception (be it just an empty string ""
or an emtpy json string "\"\""
);
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using Newtonsoft.Json.Converters;
public class ApiResponse<T>
{
[JsonProperty(Required = Required.Always)]
public bool Ok { get; set; }
[JsonProperty(Required = Required.Always)]
public T Result { get; set; }
}
var emptyJsonString = "\"\"";
JsonConvert.DeserializeObject<ApiResponse<int>>(emptyJsonString) // returns null
var emptyString = "";
JsonConvert.DeserializeObject<ApiResponse<int>>(emptyString) // returns null
System.Text.Json work like expected and when trying to de-serialize empty string will (always?) fail: System.Text.Json.JsonException: 'The input does not contain any JSON tokens. Expected the input to start with a valid JSON token, when isFinalBlock is true. Path: $ | LineNumber: 0 | BytePositionInLine: 0.'
Same is true for all:
Newtonsoft.Json.JsonConvert.DeserializeObject
Newtonsoft.Json.JsonConvert.DeserializeObject
Newtonsoft.Json.JsonConvert.DeserializeObject<MyClass>(""); // null System.Text.Json.JsonSerializer.Deserialize<MyClass>(""); // error
Hello! This is still actual. It is very ambiguous because missing required property is treated as an Exception, however, something like this " " return null. I understand, that just starting to throw exceptions, in this case, may break backward compatibility, but could you please consider adding an option to JsonSerializerSettings which would enable throwing Exceptions in such cases?