Représentant null dans JSON

423

Quelle est la méthode préférée pour renvoyer des valeurs nulles en JSON? Existe-t-il une préférence différente pour les primitives?

Par exemple, si mon objet sur le serveur a un entier appelé "myCount" sans valeur, le JSON le plus correct pour cette valeur serait:

{}

ou

{
    "myCount": null
}

ou

{
    "myCount": 0
}

Même question pour Strings - si j'ai une chaîne nulle "myString" sur le serveur, c'est le meilleur JSON:

{}

ou

{
    "myString": null
}

ou

{
    "myString": ""
}

ou (seigneur m'aide)

{
    "myString": "null"
}

J'aime la convention pour que les collections soient représentées dans le JSON comme une collection vide http://jtechies.blogspot.nl/2012/07/item-43-return-empty-arrays-or.html

Un tableau vide serait représenté:

{
    "myArray": []
}

Modifier le résumé

L'argument de la «préférence personnelle» semble réaliste, mais à courte vue dans la mesure où, en tant que communauté, nous consommerons un nombre toujours plus grand de services / sources disparates. Des conventions pour la structure JSON aideraient à normaliser la consommation et la réutilisation desdits services. En ce qui concerne l'établissement d'une norme, je suggérerais d'adopter la plupart des conventions de Jackson à quelques exceptions près:

  • Les objets sont préférés aux primitives.
  • Les collections vides sont préférées à null.
  • Les objets sans valeur sont représentés comme nuls.
  • Les primitifs renvoient leur valeur.

Si vous renvoyez un objet JSON avec des valeurs généralement nulles, vous pouvez avoir un candidat pour la refactorisation dans plusieurs 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

}

Le JSON ci-dessus a été généré à partir de la classe Java suivante.

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

Dépendance Maven:

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>2.3.0</version>
</dependency>
pherris
la source
5
Il n'y a pas de meilleur moyen. Choisissez ce qui est le plus facile à consommer pour le client dans votre cas d'utilisation concret. Dans l'esprit de retourner des collections vides au lieu de null, considérez si votre client préfère la chaîne vide ou null- une chaîne contenant le mot "null" ne peut pas être distinguée d'une valeur valide, ne faites pas cela.
Philipp Reichart
3
0 ou une chaîne vide pourrait très bien avoir une signification différente de null, qui pourrait avoir une signification différente de l'attribut qui n'existe pas. Si vous souhaitez représenter null, utilisez null. C'est le plus explicite.
John Sheehan
Dans Objective-C, il existe une NSNullclasse définie qui a une instance singleton. Une référence à cette instance est équivalente à JSON null. Je suppose qu'une autre langue pourrait faire la même chose. Bien sûr, il faudrait vérifier la classe de l'objet reçu avant de lancer dans la classe présumée - être "nul au courant", pour ainsi dire.
Hot Licks
2
Notez que le fait d'avoir une liste "nulle" n'est pas non plus la meilleure pratique en Java: si la liste est censée être vide, initialisez-la sur une liste vide. S'il doit rester vide (par exemple parce qu'il sera remplacé en gros par une nouvelle liste plutôt que modifié pour ajouter des valeurs), initialisez-le à la liste vide (ie Collections.emptyList()). Cela évite les bogues de référence nuls qui peuvent être gênants autrement.
Periata Breatta du
@HotLicks - c'est uniquement possible car Objective-C est typé dynamiquement. En Java, par exemple, vous ne pouviez pas avoir de Nullclasse (utile) car vous ne pouviez affecter ses valeurs qu'à des objets de son propre type ou de type Object.
Periata Breatta du

Réponses:

379

Évaluons l'analyse de chacun:

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: []}

Le tl; dr ici:

Le fragment de la variable json2 est la façon dont la spécification JSON indique nulldoit être représentée. Mais comme toujours, cela dépend de ce que vous faites - parfois la "bonne" façon de le faire ne fonctionne pas toujours pour votre situation. Utilisez votre jugement et prenez une décision éclairée.


JSON1 {}

Cela renvoie un objet vide. Il n'y a pas de données là-bas, et cela va seulement vous dire que quelle que soit la clé que vous recherchez (que ce myCountsoit ou autre) est de type undefined.


JSON2 {"myCount": null}

Dans ce cas, myCountest en fait défini, bien que sa valeur soit null. Ce n'est pas la même chose que «non undefinedet non null», et si vous testiez une condition ou l'autre, cela pourrait réussir alors que JSON1 échouerait.

C'est la façon définitive de représenter nullselon la spécification JSON .


JSON3 {"myCount": 0}

Dans ce cas, myCount est 0. Ce n'est pas la même chose que null, et ce n'est pas la même chose que false. Si votre déclaration conditionnelle est évaluée myCount > 0, cela peut valoir la peine. De plus, si vous exécutez des calculs basés sur la valeur ici, 0 pourrait être utile. nullCependant, si vous essayez de tester , cela ne fonctionnera pas du tout.


JSON4 {"myString": ""}

Dans ce cas, vous obtenez une chaîne vide. Encore une fois, comme avec JSON2, il est défini, mais il est vide. Vous pouvez tester if (obj.myString == "")mais vous ne pouvez pas tester nullou undefined.


JSON5 {"myString": "null"}

Cela va probablement vous poser des problèmes, car vous définissez la valeur de chaîne sur null; dans ce cas, obj.myString == "null"ce n'est pas le cas == null .


JSON6 {"myArray": []}

Cela vous dira que votre tableau myArrayexiste, mais il est vide. Ceci est utile si vous essayez d'effectuer un comptage ou une évaluation sur myArray. Par exemple, supposons que vous vouliez évaluer le nombre de photos postées par un utilisateur - vous pourriez le faire myArray.lengthet cela reviendrait 0: défini, mais aucune photo publiée.

brandonscript
la source
1
Merci beaucoup, très utile. Juste un petit nœud latéral; lorsque Play Json (scala) sérialise Option [String] = Aucun résultat est JSON1ie{}
Neil
207

nulln'est pas nul. Ce n'est pas une valeur en soi : c'est une valeur en dehors du domaine de la variable indiquant des données manquantes ou inconnues.

Il n'y a qu'une seule façon de représenter nullen JSON. Selon les spécifications ( RFC 4627 et json.org ):

2.1. Valeurs

Une valeur JSON DOIT être un objet, un tableau, un nombre ou une chaîne, ou l'un des
les trois noms littéraux suivants:

  faux nul vrai

entrez la description de l'image ici

Nicholas Carey
la source
8
C'est tellement dommage que nul doit être présent du tout. 4 personnages pour rien. Il aurait été bien d'exclure complètement la valeur. json = '{"myValue":}';
Richard A Quadling
119
@Richard A Quadling - Je suis un adepte des programmes de Hal Abelson "doivent être écrits pour que les gens lisent, et accessoirement pour que les machines s'exécutent". Je préférerais le mot «null», confirmant l'intention du programmeur, et pas seulement une question d'omission accidentelle.
Scott Smith
13
@Dave May: "Les valeurs JSON ne sont pas des programmes" - Mon point concerne la signalisation d'intention sans ambiguïté. Oui, cela coûte quatre caractères supplémentaires, et pour certaines applications, la différence peut être importante. Dans de nombreux cas, cependant, les avantages de faire des erreurs semblent fausses l' emportent largement sur les avantages des optimisations mineures.
Scott Smith
11
@Dave En outre, selon json.org, JSON "est facile à lire et à écrire pour les humains".
Sophivorus
14
Notez également que si vous avez des problèmes avec 4 caractères ASCII, JSON n'est pas la meilleure approche, regardez JSON binaire ou mieux vers un format binaire pur.
PhoneixS
26

Il n'y a qu'une seule façon de représenter null; c'est avec 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

C'est-à-dire; si l'un des clients qui consomment votre représentation JSON utilise l' ===opérateur; cela pourrait être un problème pour eux.

aucune valeur

Si vous souhaitez transmettre que vous avez un objet dont l'attribut myCountn'a pas de valeur:

{ "myCount": null }

aucun attribut / attribut manquant

Que faire si vous indiquez que vous avez un objet sans attribut:

{}

Le code client essaiera d'accéder myCountet d'obtenir undefined; Ce n'est pas là.

collection vide

Que faire si vous indiquez que vous avez un objet avec un attribut myCountqui est une liste vide:

{ "myCount": [] }
dnozay
la source
+1 de bons exemples avec des comparaisons, mais il serait utile de faire la distinction entre javascript et json, ce qui signifie que la représentation de null en javascript n'a pas à correspondre à celle de json (bien que ce soit le cas).
Mladen B.
15

Je voudrais utiliser nullpour montrer qu'il n'y a aucune valeur pour cette clé particulière. Par exemple, utilisez nullpour représenter que «le nombre d'appareils de votre foyer se connecte à Internet» est inconnu.

D'un autre côté, utilisez {}si cette clé particulière n'est pas applicable. Par exemple, vous ne devez pas afficher de décompte, même si null, à la question «le nombre de voitures disposant d'une connexion Internet active» est demandé à une personne qui ne possède pas de voiture.

J'éviterais de mettre par défaut une valeur à moins que cette valeur par défaut ait du sens. Bien que vous puissiez décider de l'utiliser nullpour ne représenter aucune valeur, ne l'utilisez certainement jamais "null".

marcoseu
la source
7

Je choisirais "par défaut" pour le type de données de la variable ( nullpour les chaînes / objets, 0pour les nombres), mais vérifie en effet quel code qui consommera l'objet attend. N'oubliez pas qu'il y a parfois une distinction entre null/ default et "not present".

Consultez le modèle d'objet nul - il est parfois préférable de passer un objet spécial au lieu de null(c'est-à-dire un []tableau plutôt que nullpour des tableaux ou ""des chaînes).

Alexei Levenkov
la source
2

Il s'agit d'un choix personnel et situationnel. La chose importante à retenir est que la chaîne vide et le nombre zéro sont conceptuellement distincts de null.

Dans le cas d'un, countvous voulez probablement toujours un certain nombre valide (sauf si le countest inconnu ou indéfini), mais dans le cas des chaînes, qui sait? La chaîne vide peut signifier quelque chose dans votre application. Ou peut-être que non. C'est à vous de décider.

Wayne
la source
1

Selon la spécification JSON , le conteneur le plus à l'extérieur ne doit pas nécessairement être un dictionnaire (ou un «objet») comme le laisse entendre la plupart des commentaires ci-dessus. Il peut également s'agir d'une liste ou d'une valeur nue (c'est-à-dire chaîne, nombre, booléen ou null). Si vous souhaitez représenter une valeur nulle en JSON, la chaîne JSON entière (à l'exclusion des guillemets contenant la chaîne JSON) est simplement null. Pas d'accolades, pas de crochets, pas de guillemets. Vous pouvez spécifier un dictionnaire contenant une clé avec une valeur nulle ( {"key1":null}) ou une liste avec une valeur nulle ( [null]), mais ce ne sont pas des valeurs nulles elles-mêmes - ce sont des dictionnaires et des listes appropriés. De même, un dictionnaire vide ( {}) ou une liste vide ( []) sont parfaitement bien, mais ne sont pas non plus nuls.

En 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
iggie
la source
Notez que c'est la grammaire du formulaire McKeeman dans la barre latérale droite de la page de spécification JSON liée qui valide l'assertion selon laquelle bare nullconstitue un JSON valide. Le corps du texte et les illustrations sont ambigus et, si quelque chose semble suggérer, seuls les objets et les tableaux sont valides à la racine.
yoyoyoyosef