3

This using json.net (C#). Not sure why JToken is not null.

var obj = new JObject();
obj["field1"] = null;
var token = obj["field1"];

Console.WriteLine(token == null); // false 
Console.WriteLine(token.ToString() == ""); // true

Console.WriteLine(token.Type == JTokenType.Null); // true
dbc
  • 104,963
  • 20
  • 228
  • 340
user2529654
  • 71
  • 1
  • 5
  • 1
    Json.NET never actually allows a `null` value in the `JToken` hierarchy. Instead it replaces nulls with a *non-null `JValue`* with [`JValue.Type`](http://www.newtonsoft.com/json/help/html/P_Newtonsoft_Json_Linq_JValue_Type.htm) equal to [`JTokenType.Null`](http://www.newtonsoft.com/json/help/html/T_Newtonsoft_Json_Linq_JTokenType.htm). – dbc Aug 09 '18 at 23:15
  • 1
    See [Newtonsoft Json.Net serialize JObject doesn't ignore nulls, even with the right settings](https://stackoverflow.com/a/29259032/3744182) or [Issue with JSON null handling in Newtonsoft](https://stackoverflow.com/a/31141975/3744182) or [Null-coalescing operator returning null for properties of dynamic objects](https://stackoverflow.com/a/29053805/3744182) for details. – dbc Aug 09 '18 at 23:15

1 Answers1

9

This is by design.

Json.NET never allows an actual null JToken value to appear in a JToken hierarchy, either as an JArray member or a JProperty value. Instead, if applications code attempts to set or add a null token, it gets replaced with a non-null JValue with JValue.Type equal to JTokenType.Null. This replacement occurs in, e.g., JContainer.EnsureParentToken(JToken item, bool skipParentCheck):

    internal JToken EnsureParentToken(JToken item, bool skipParentCheck)
    {
        if (item == null)
        {
            return JValue.CreateNull();
        }

As well as JProperty.Value:

    public JToken Value
    {
        set
        {
            CheckReentrancy();

            JToken newValue = value ?? JValue.CreateNull();

I believe Newtonsoft does this to capture the difference between the following two JSON objects:

{
   "field1": null
}

And the empty object:

{ }

In the first case, the property "field1" is present with a null JSON value. In the second case, the property "field1" is not present. Linq-to-JSON represents the first case with a null-type JValue rather than having JProperty.Value actually be null. It likely does this because if it did not, object["field1"] would return null in both cases, making them harder to distinguish. (Unlike Dictionary<TKey, TValue>, JObject does not throw a KeyNotFoundException when attempting to access the value of a non-existent property. Instead, JObject.Item[String] returns a null JValue for the value of a missing key.)

Your code, obj["field1"] = null;, creates a JSON object of the first form, which you can see if you examine the value of obj.ToString(). Thus obj["field1"] returns non-null

If you do not need to distinguish between missing and null-valued properties, you could introduce an extension method to check for a null value such as the one of the ones from Checking for empty/null JToken in a JObject or Issue with JSON null handling in Newtonsoft.

dbc
  • 104,963
  • 20
  • 228
  • 340