Recently I was working on an issue where a service would return null when called with some parameters and the consuming service would have an issue, because the response read from the HTTP response stream would be a string containing the 4 characters “null” and only had a check whether the string was null and if not was using a JSON converter to parse the JSON text which would result in an exception being thrown. The question we were discussing here is what should be the JSON representation of a null object.
What is JSON ?
JavaScript Object Notation (JSON) is a lightweight, language independent text format for the serialization and exchange of structured data. It is derived from the object literals defined in the ECMAScript Programming Language Standard and defines a small set of formatting rules for the portable representation of structured data.
JSON is described in a few standard documents:
- RFC 4627: The application/json Media Type for JavaScript Object Notation (JSON) –> Made obsolete after the publication of RFC 7159
- RFC 7159: The JavaScript Object Notation (JSON) Data Interchange Format
- ECMA-404: The JSON Data Interchange Syntax
JSON text vs. JSON value
A JSON text is a sequence of tokens representing structured data transmitted as a string. A JSON value is be an object, array, number, or string, or one of the three literal names: false, null or true.
In RFC 4627, a JSON text was defined as serialized object or array. An JSON object value having to start and end with curly brackets and a JSON array value having to start and end with square brackets. This effectively meant that “null” was not a valid JSON text.
But even in RFC 4627, null was a valid JSON value.
Changes in RFC 7159
RFC 7159 was published in March 2014 and updates RFC 4627. The goal of this update was to remove inconsistencies with other specifications of JSON and highlight practices that can lead to interoperability problems. One of the changes in RFC 7159 is that a JSON text is not defined as being an object or an array anymore but rather as being a serialized value.
This means that with RFC 7159, “null” (as well as “true” and “false”) becomes a valid JSON text. So the JSON text serialized value of a null object is indeed “null”. Unfortunately, not all JSON parsers / deserializers support parsing the string “null”.
Parsing null with JSON.NET
When using JSON.Net (Newtonsoft.Json), there are two ways to deserialize a JSON text:
- JObject.parse: this returns a JObject which allows you to work with JSON results which structure might not be completely known.
- JsonConvert.DeserializeObject: this is always to deserialize the JSON text to an instance of a defined class.
JObject.parse unfortunately throws an exception when trying to parse “null” (JObject.Parse(“null”)):
Newtonsoft.Json.JsonReaderException: ‘Error reading JObject from JsonReader. Current JsonReader item is not an object: Null. Path ”, line 1, position 4.’
But if you do not have a class corresponding to the JSON text you’re deserializing, you can either use “object” as type when calling JsonConvert.DeserializeObject or use the overload without generics:
JsonConvert.DeserializeObject<object>("null");
JsonConvert.DeserializeObject("null");
In both cases, you will get an instance of JObject back (just like the return value of JObject.parse).
Interesting. Why would you want to store a null object? My understanding is that null is used to indicate failure or to inform GC that the object is not used by assigning it null.
You do not always want to store the data. You could just request an object and service could return null when not found instead of returning an HTTP 404 response although it would be the right way to do it. Unfortunately, as the user of an API you cannot force the service you call to return an HTTP error code instead of null. So the best thing you can do is to at least on crash failing to parse something which is actually a valid JSON text value.