Representing null in JSON
Asked Answered
S

8

646

What is the preferred method for returning null values in JSON? Is there a different preference for primitives?

For example, if my object on the server has an Integer called "myCount" with no value, the most correct JSON for that value would be:

{}

or

{
    "myCount": null
}

or

{
    "myCount": 0
}

Same question for Strings - if I have a null string "myString" on the server, is the best JSON:

{}

or

{
    "myString": null
}

or

{
    "myString": ""
}

or (lord help me)

{
    "myString": "null"
}

I like the convention for collections to be represented in the JSON as an empty collection http://jtechies.blogspot.nl/2012/07/item-43-return-empty-arrays-or.html

An empty Array would be represented:

{
    "myArray": []
}

EDIT Summary

The 'personal preference' argument seems realistic, but short sighted in that, as a community we will be consuming an ever greater number of disparate services/sources. Conventions for JSON structure would help normalize consumption and reuse of said services. As far as establishing a standard, I would suggest adopting most of the Jackson conventions with a few exceptions:

  • Objects are preferred over primitives.
  • Empty collections are preferred over null.
  • Objects with no value are represented as null.
  • Primitives return their value.

If you are returning a JSON object with mostly null values, you may have a candidate for refactoring into multiple services.

{
    "value1": null,
    "value2": null,
    "text1": null,
    "text2": "hello",
    "intValue": 0, //use primitive only if you are absolutely sure the answer is 0
    "myList": [],
    "myEmptyList": null, //NOT BEST PRACTICE - return [] instead
    "boolean1": null, //use primitive only if you are absolutely sure the answer is true/false
    "littleboolean": false
}

The above JSON was generated from the following Java class.

package jackson;    
import java.util.ArrayList;
import java.util.List;    
import com.fasterxml.jackson.databind.ObjectMapper;
    
public class JacksonApp {    
    public static class Data {    
        public Integer value1;    
        public Integer value2;
        public String text1;
        public String text2 = "hello";
        public int intValue;
        public List<Object> myList = new ArrayList<Object>();
        public List<Object> myEmptyList;
        public Boolean boolean1;
        public boolean littleboolean;   
   }
    
   public static void main(String[] args) throws Exception {
       ObjectMapper mapper = new ObjectMapper();
       System.out.println(mapper.writeValueAsString(new Data()));
   }
}

Maven dependency:

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>2.3.0</version>
</dependency>
Shroff answered 14/1, 2014 at 18:19 Comment(6)
There is no best way. Pick what's easiest to consume for the client in your concrete use case. In the spirit of returning empty collections instead of null, consider if your client is better of with the empty string or null -- a string containing the word "null" is indistinguishable from a valid value, don't do that.Curriery
0 or an empty string could very well have different meaning from null, which could have different meaning from the attribute not existing. If you want to represent null, use null. It's the most explicit.Yves
In Objective-C there is a defined NSNull class which has a singleton instance. A reference to that instance is equivalent to JSON's null. I would guess that another language could do the same thing. Of course, one would have to check the class of the received object before casting to the presumed class -- be "null aware", as it were.Montsaintmichel
Note that having a "null" list isn't best practice in Java either: if the list is expected to be empty, initialise it to an empty list. If it is required to remain empty (e.g. because it will be replaced wholesale by a new list rather than modified to add values), initialise it to the empty list (i.e. Collections.emptyList()). Doing so avoids null reference bugs that can be a pain otherwise.Rhombohedron
@HotLicks - that's only possible because Objective-C is dynamically typed. In Java, for instance, you couldn't have a (useful) Null class because you would only be able to assign its values to objects of its own type or of type Object.Rhombohedron
@PeriataBreatta You're confusing "null pointers" with "null values". The former is bad, the latter is fine.Scoutmaster
P
562

Let's evaluate the parsing of each:

http://jsfiddle.net/brandonscript/Y2dGv/

var json1 = '{}';
var json2 = '{"myCount": null}';
var json3 = '{"myCount": 0}';
var json4 = '{"myString": ""}';
var json5 = '{"myString": "null"}';
var json6 = '{"myArray": []}';

console.log(JSON.parse(json1)); // {}
console.log(JSON.parse(json2)); // {myCount: null}
console.log(JSON.parse(json3)); // {myCount: 0}
console.log(JSON.parse(json4)); // {myString: ""}
console.log(JSON.parse(json5)); // {myString: "null"}
console.log(JSON.parse(json6)); // {myArray: []}

The tl;dr here:

The fragment in the json2 variable is the way the JSON spec indicates null should be represented. But as always, it depends on what you're doing -- sometimes the "right" way to do it doesn't always work for your situation. Use your judgement and make an informed decision.


JSON1 {}

This returns an empty object. There is no data there, and it's only going to tell you that whatever key you're looking for (be it myCount or something else) is of type undefined.


JSON2 {"myCount": null}

In this case, myCount is actually defined, albeit its value is null. This is not the same as both "not undefined and not null", and if you were testing for one condition or the other, this might succeed whereas JSON1 would fail.

This is the definitive way to represent null per the JSON spec.


JSON3 {"myCount": 0}

In this case, myCount is 0. That's not the same as null, and it's not the same as false. If your conditional statement evaluates myCount > 0, then this might be worthwhile to have. Moreover, if you're running calculations based on the value here, 0 could be useful. If you're trying to test for null however, this is actually not going to work at all.


JSON4 {"myString": ""}

In this case, you're getting an empty string. Again, as with JSON2, it's defined, but it's empty. You could test for if (obj.myString == "") but you could not test for null or undefined.


JSON5 {"myString": "null"}

This is probably going to get you in trouble, because you're setting the string value to null; in this case, obj.myString == "null" however it is not == null.


JSON6 {"myArray": []}

This will tell you that your array myArray exists, but it's empty. This is useful if you're trying to perform a count or evaluation on myArray. For instance, say you wanted to evaluate the number of photos a user posted - you could do myArray.length and it would return 0: defined, but no photos posted.

Poeticize answered 14/1, 2014 at 18:34 Comment(3)
Thanks a lot, very helpful. Just a small side node; when Play Json (scala) serializes Option[String] = None result is JSON1 i.e. {}Dall
Is there no option for {"myObject": {}}? Is setting a value to an empty object possible?Pearcy
Sure, go ahead. It means something different than null.Poeticize
F
271

null is not zero. It is not a value, per se: it is a value outside the domain of the variable indicating missing or unknown data.

There is only one way to represent null in JSON. Per the specs (RFC 4627 and json.org):

2.1.  Values

A JSON value MUST be an object, array, number, or string, or one of
the following three literal names:

  false null true

enter image description here

Frore answered 14/1, 2014 at 19:16 Comment(8)
It is such a shame that null has to be present at all. 4 characters for nothing. It would have been nice to simply exclude the value entirely. json = '{"myValue":}';Ennis
@Richard A Quadling - I'm a follower of Hal Abelson's "Programs must be written for people to read, and only incidentally for machines to execute". I'd prefer the word 'null', confirming the programmer's intention, and not just a question of accidental omission.Ogden
@ScottSmith: Of course programs must be written for people to read. But JSON values are not programs, they are data. Programming languages have positional parameters where the person doesn't type null for every unspecified function parameter. And under the hood, it would be nice if the serialization of a function call didn't have to send 4 ASCII characters 'n', 'u', 'l', 'l' for every parameter that the person omits, quite readably, by typing nothing between two commas.Caston
@Caston May: "JSON values are not programs" -- My point is about signaling intent in an unambiguous way. Yes, it costs an extra four characters, and for some applications the difference may be significant. In many cases though, the benefits of making errors look wrong far outweighs the benefits of minor optimizations.Ogden
@Caston Also, according to json.org, JSON "is easy for humans to read and write."Galang
@RichardAQuadling Although on the one hand I agree (because I'm a sucker for shorthand), you can also let JSON values be empty strings, so that wouldn't work. The other option, completely omitting anything, like "first":true, "second":, "third":false could easily be confusing or mistaken for an error.Doyen
It says "Easy for humans to read and write", but then proceeds to define the Unicode escaping rules, wiping out that prior claim.Impersonate
Also note that if you have problems with 4 ASCII characters, JSON isn't the best approach, look at Binary JSON or better to a pure binary format.Hardigg
O
49

There is only one way to represent null; that is with null.

console.log(null === null);   // true
console.log(null === true);   // false
console.log(null === false);  // false
console.log(null === 'null'); // false
console.log(null === "null"); // false
console.log(null === "");     // false
console.log(null === []);     // false
console.log(null === 0);      // false

That is to say; if any of the clients that consume your JSON representation use the === operator; it could be a problem for them.

no value

If you want to convey that you have an object whose attribute myCount has no value:

{ "myCount": null }

no attribute / missing attribute

What if you to convey that you have an object with no attributes:

{}

Client code will try to access myCount and get undefined; it's not there.

empty collection

What if you to convey that you have an object with an attribute myCount that is an empty list:

{ "myCount": [] }
Outdare answered 18/12, 2015 at 17:27 Comment(1)
+1 good examples with comparisons, but it would be helpful to distinguish between javascript and json, meaning, representation of null in javascript didn't have to match the json's (although it does).Ostracoderm
R
18

I would use null to show that there is no value for that particular key. For example, use null to represent that "number of devices in your household connects to internet" is unknown.

On the other hand, use {} if that particular key is not applicable. For example, you should not show a count, even if null, to the question "number of cars that has active internet connection" is asked to someone who does not own any cars.

I would avoid defaulting any value unless that default makes sense. While you may decide to use null to represent no value, certainly never use "null" to do so.

Rackety answered 14/1, 2014 at 18:33 Comment(0)
J
9

I would pick "default" for data type of variable (null for strings/objects, 0 for numbers), but indeed check what code that will consume the object expects. Don't forget there there is sometimes distinction between null/default vs. "not present".

Check out null object pattern - sometimes it is better to pass some special object instead of null (i.e. [] array instead of null for arrays or "" for strings).

Joellenjoelly answered 14/1, 2014 at 18:28 Comment(0)
F
4

According to the JSON spec, the outermost container does not have to be a dictionary (or 'object') as implied in most of the comments above. It can also be a list or a bare value (i.e. string, number, boolean or null). If you want to represent a null value in JSON, the entire JSON string (excluding the quotes containing the JSON string) is simply null. No braces, no brackets, no quotes. You could specify a dictionary containing a key with a null value ({"key1":null}), or a list with a null value ([null]), but these are not null values themselves - they are proper dictionaries and lists. Similarly, an empty dictionary ({}) or an empty list ([]) are perfectly fine, but aren't null either.

In Python:

>>> print json.loads('{"key1":null}')
{u'key1': None}
>>> print json.loads('[null]')
[None]
>>> print json.loads('[]')
[]
>>> print json.loads('{}')
{}
>>> print json.loads('null')
None
Fennie answered 10/8, 2018 at 20:31 Comment(1)
Note it is the McKeeman Form grammar on the right sidebar of the linked JSON spec page that validates the assertion that bare null constitutes valid JSON. The main body text and illustrations there are ambiguous and if anything seem to suggest only objects and arrays are valid at the root.Accursed
A
2

This is a personal and situational choice. The important thing to remember is that the empty string and the number zero are conceptually distinct from null.

In the case of a count you probably always want some valid number (unless the count is unknown or undefined), but in the case of strings, who knows? The empty string could mean something in your application. Or maybe it doesn't. That's up to you to decide.

Airborne answered 14/1, 2014 at 18:29 Comment(0)
R
1

'null' is best for practical use

FWIW, using PHP as an example, PHP interprets empty sets as entries made by PHP...

// This loop will iterate one item with the value 'the car'
$empty_json = '["the car"]';
$some_json_array = json_decode($empty_json);

foreach ($some_json_array as $i) {
  echo "PHP sees one item";
}

output: PHP sees the car

// This loop will iterate one item, but with no values
$empty_json = '[""]';
$some_json_array = json_decode($empty_json);

foreach ($some_json_array as $i) {
  echo "PHP sees: $i";
}

output: PHP sees

// This loop will iterate nothing because PHP's `json_decode()` function knew it was `null`
$empty_json = 'null';
$some_json_array = json_decode($empty_json);

foreach ($some_json_array as $i) {
  echo "PHP sees one item";
}

output: (nothing, foreach will not loop)

Rao answered 15/5, 2022 at 4:38 Comment(1)
This Question is not restricted to java or phython, though it has a Java example in the Question and a Python example in another Answer. This Answer shows some from PHP to round out the area covered by the Answers.Rao

© 2022 - 2024 — McMap. All rights reserved.